@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
* The back-references list now shows references to any tag in the open document, not just the first tag. Issue #227, PR #234.
|
* The back-references list now shows references to any tag in the open document, not just the first tag. Issue #227, PR #234.
|
||||||
* Clicking a tag now tries to scroll to the header where the tag is set. The index needed a couple of minor changes for this feature, so this will invalidate the old index for a project, and require a new to be built. This is done automatically. PR #234.
|
* Clicking a tag now tries to scroll to the header where the tag is set. The index needed a couple of minor changes for this feature, so this will invalidate the old index for a project, and require a new to be built. This is done automatically. PR #234.
|
||||||
|
* Moved the Close button on the "Build Novel project" dialog to the area with the other buttons since we anyway increased the size of that area. PR #256.
|
||||||
|
|
||||||
**Project Structure**
|
**Project Structure**
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -533,7 +533,9 @@ class Config:
|
|||||||
|
|
||||||
# Write config file
|
# Write config file
|
||||||
try:
|
try:
|
||||||
cnfParse.write(open(path.join(self.confPath,self.confFile),mode="w",encoding="utf8"))
|
cnfParse.write(
|
||||||
|
open(path.join(self.confPath, self.confFile), mode="w", encoding="utf8")
|
||||||
|
)
|
||||||
self.confChanged = False
|
self.confChanged = False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Could not save config file")
|
logger.error("Could not save config file")
|
||||||
|
|||||||
+8
-8
@@ -113,7 +113,7 @@ class NWProject():
|
|||||||
CUSTOM, and always have parent handle set to None.
|
CUSTOM, and always have parent handle set to None.
|
||||||
"""
|
"""
|
||||||
if not self.projTree.checkRootUnique(rootClass):
|
if not self.projTree.checkRootUnique(rootClass):
|
||||||
self.makeAlert("Duplicate root item detected!", nwAlert.ERROR)
|
self.makeAlert("Duplicate root item detected.", nwAlert.ERROR)
|
||||||
return None
|
return None
|
||||||
newItem = NWItem(self)
|
newItem = NWItem(self)
|
||||||
newItem.setName(rootName)
|
newItem.setName(rootName)
|
||||||
@@ -995,7 +995,7 @@ class NWProject():
|
|||||||
# Report status
|
# Report status
|
||||||
if len(orphanFiles) > 0:
|
if len(orphanFiles) > 0:
|
||||||
self.makeAlert(
|
self.makeAlert(
|
||||||
"Found %d orphaned file(s) in project folder!" % len(orphanFiles),
|
"Found %d orphaned file(s) in project folder." % len(orphanFiles),
|
||||||
nwAlert.WARN
|
nwAlert.WARN
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -1097,10 +1097,10 @@ class NWProject():
|
|||||||
|
|
||||||
# END Class NWProject
|
# END Class NWProject
|
||||||
|
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
# NWTree
|
# NWTree
|
||||||
# Class holding the project tree for the NWProject
|
# Class holding the project tree for the NWProject
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
|
|
||||||
class NWTree():
|
class NWTree():
|
||||||
|
|
||||||
@@ -1435,10 +1435,10 @@ class NWTree():
|
|||||||
|
|
||||||
# END Class NWTree
|
# END Class NWTree
|
||||||
|
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
# NWItem
|
# NWItem
|
||||||
# Class holding the project items making up the NWProject
|
# Class holding the project items making up the NWProject
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
|
|
||||||
class NWItem():
|
class NWItem():
|
||||||
|
|
||||||
@@ -1680,10 +1680,10 @@ class NWItem():
|
|||||||
|
|
||||||
# END Class NWItem
|
# END Class NWItem
|
||||||
|
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
# NWStatus
|
# NWStatus
|
||||||
# Class holding the item status values stored in the NWProject
|
# Class holding the item status values stored in the NWProject
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
|
|
||||||
class NWStatus():
|
class NWStatus():
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ from nw.constants import isoLanguage
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
# SpellChecking SuperClass
|
# SpellChecking SuperClass
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
|
|
||||||
class NWSpellCheck():
|
class NWSpellCheck():
|
||||||
|
|
||||||
@@ -129,9 +129,9 @@ class NWSpellCheck():
|
|||||||
|
|
||||||
# END Class NWSpellCheck
|
# END Class NWSpellCheck
|
||||||
|
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
# Enchant Based SpellChecking
|
# Enchant Based SpellChecking
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
|
|
||||||
class NWSpellEnchant(NWSpellCheck):
|
class NWSpellEnchant(NWSpellCheck):
|
||||||
|
|
||||||
@@ -211,9 +211,9 @@ class NWSpellEnchantDummy:
|
|||||||
|
|
||||||
# END Class NWSpellEnchantDummy
|
# END Class NWSpellEnchantDummy
|
||||||
|
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
# Fallback SpellChecking Using difflib
|
# Fallback SpellChecking Using difflib
|
||||||
# ================================================================================================ #
|
# =============================================================================================== #
|
||||||
|
|
||||||
class NWSpellSimple(NWSpellCheck):
|
class NWSpellSimple(NWSpellCheck):
|
||||||
"""Internal spell check tool that uses standard Python packages with
|
"""Internal spell check tool that uses standard Python packages with
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@ from nw.gui.theme import GuiTheme
|
|||||||
|
|
||||||
# Dialogs
|
# Dialogs
|
||||||
from nw.gui.dialogs.about import GuiAbout
|
from nw.gui.dialogs.about import GuiAbout
|
||||||
from nw.gui.dialogs.configeditor import GuiConfigEditor
|
from nw.gui.dialogs.preferences import GuiPreferences
|
||||||
from nw.gui.dialogs.docmerge import GuiDocMerge
|
from nw.gui.dialogs.docmerge import GuiDocMerge
|
||||||
from nw.gui.dialogs.docsplit import GuiDocSplit
|
from nw.gui.dialogs.docsplit import GuiDocSplit
|
||||||
from nw.gui.dialogs.itemeditor import GuiItemEditor
|
from nw.gui.dialogs.itemeditor import GuiItemEditor
|
||||||
@@ -40,7 +40,7 @@ __all__ = [
|
|||||||
"GuiMainStatus",
|
"GuiMainStatus",
|
||||||
"GuiTheme",
|
"GuiTheme",
|
||||||
"GuiAbout",
|
"GuiAbout",
|
||||||
"GuiConfigEditor",
|
"GuiPreferences",
|
||||||
"GuiDocMerge",
|
"GuiDocMerge",
|
||||||
"GuiDocSplit",
|
"GuiDocSplit",
|
||||||
"GuiItemEditor",
|
"GuiItemEditor",
|
||||||
|
|||||||
+33
-24
@@ -34,12 +34,12 @@ from time import time
|
|||||||
from PyQt5.QtCore import Qt, QByteArray
|
from PyQt5.QtCore import Qt, QByteArray
|
||||||
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
|
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QTextOption, QPalette, QColor, QTextDocumentWriter, QFont
|
QPalette, QColor, QTextDocumentWriter, QFont
|
||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel,
|
QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel,
|
||||||
QLineEdit, QGroupBox, QGridLayout, QProgressBar, QMenu, QAction,
|
QLineEdit, QGroupBox, QGridLayout, QProgressBar, QMenu, QAction,
|
||||||
QFileDialog, QFontComboBox, QSpinBox, QDialogButtonBox
|
QFileDialog, QFontComboBox, QSpinBox
|
||||||
)
|
)
|
||||||
|
|
||||||
from nw.gui.additions import QSwitch
|
from nw.gui.additions import QSwitch
|
||||||
@@ -83,8 +83,7 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.optState.getInt("GuiBuildNovel", "winHeight", 800)
|
self.optState.getInt("GuiBuildNovel", "winHeight", 800)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.outerBox = QVBoxLayout()
|
self.outerBox = QHBoxLayout()
|
||||||
self.innerBox = QHBoxLayout()
|
|
||||||
self.toolsBox = QVBoxLayout()
|
self.toolsBox = QVBoxLayout()
|
||||||
|
|
||||||
self.docView = GuiBuildNovelDocView(self, self.theProject)
|
self.docView = GuiBuildNovelDocView(self, self.theProject)
|
||||||
@@ -173,7 +172,9 @@ class GuiBuildNovel(QDialog):
|
|||||||
|
|
||||||
self.textFont = QFontComboBox()
|
self.textFont = QFontComboBox()
|
||||||
self.textFont.setFixedWidth(220)
|
self.textFont.setFixedWidth(220)
|
||||||
self.textFont.setToolTip("The font is used for PDF and printing. Other formats have no font set.")
|
self.textFont.setToolTip(
|
||||||
|
"The font is used for PDF and printing. Other formats have no font set."
|
||||||
|
)
|
||||||
self.textFont.setCurrentFont(
|
self.textFont.setCurrentFont(
|
||||||
QFont(self.optState.getString("GuiBuildNovel", "textFont", self.mainConf.textFont))
|
QFont(self.optState.getString("GuiBuildNovel", "textFont", self.mainConf.textFont))
|
||||||
)
|
)
|
||||||
@@ -183,13 +184,17 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.textSize.setMinimum(5)
|
self.textSize.setMinimum(5)
|
||||||
self.textSize.setMaximum(48)
|
self.textSize.setMaximum(48)
|
||||||
self.textSize.setSingleStep(1)
|
self.textSize.setSingleStep(1)
|
||||||
self.textSize.setToolTip("The size is used for PDF and printing. Other formats have no size set.")
|
self.textSize.setToolTip(
|
||||||
|
"The size is used for PDF and printing. Other formats have no size set."
|
||||||
|
)
|
||||||
self.textSize.setValue(
|
self.textSize.setValue(
|
||||||
self.optState.getInt("GuiBuildNovel", "textSize", self.mainConf.textSize)
|
self.optState.getInt("GuiBuildNovel", "textSize", self.mainConf.textSize)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.justifyText = QSwitch()
|
self.justifyText = QSwitch()
|
||||||
self.justifyText.setToolTip("Applies to PDF, printing, HTML, and Open Document exports.")
|
self.justifyText.setToolTip(
|
||||||
|
"Applies to PDF, printing, HTML, and Open Document exports."
|
||||||
|
)
|
||||||
self.justifyText.setChecked(
|
self.justifyText.setChecked(
|
||||||
self.optState.getBool("GuiBuildNovel", "justifyText", False)
|
self.optState.getBool("GuiBuildNovel", "justifyText", False)
|
||||||
)
|
)
|
||||||
@@ -211,15 +216,21 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.includeGroup.setLayout(self.includeForm)
|
self.includeGroup.setLayout(self.includeForm)
|
||||||
|
|
||||||
self.includeSynopsis = QSwitch()
|
self.includeSynopsis = QSwitch()
|
||||||
self.includeSynopsis.setToolTip("Include synopsis type comments in the output.")
|
self.includeSynopsis.setToolTip(
|
||||||
|
"Include synopsis type comments in the output."
|
||||||
|
)
|
||||||
self.includeSynopsis.setChecked(self.theProject.titleFormat["withSynopsis"])
|
self.includeSynopsis.setChecked(self.theProject.titleFormat["withSynopsis"])
|
||||||
|
|
||||||
self.includeComments = QSwitch()
|
self.includeComments = QSwitch()
|
||||||
self.includeComments.setToolTip("Include plain comments in the output.")
|
self.includeComments.setToolTip(
|
||||||
|
"Include plain comments in the output."
|
||||||
|
)
|
||||||
self.includeComments.setChecked(self.theProject.titleFormat["withComments"])
|
self.includeComments.setChecked(self.theProject.titleFormat["withComments"])
|
||||||
|
|
||||||
self.includeKeywords = QSwitch()
|
self.includeKeywords = QSwitch()
|
||||||
self.includeKeywords.setToolTip("Include meta keywords (tags, references) in the output.")
|
self.includeKeywords.setToolTip(
|
||||||
|
"Include meta keywords (tags, references) in the output."
|
||||||
|
)
|
||||||
self.includeKeywords.setChecked(self.theProject.titleFormat["withKeywords"])
|
self.includeKeywords.setChecked(self.theProject.titleFormat["withKeywords"])
|
||||||
|
|
||||||
self.includeForm.addWidget(QLabel("Include synopsis"), 0, 0, 1, 1, Qt.AlignLeft)
|
self.includeForm.addWidget(QLabel("Include synopsis"), 0, 0, 1, 1, Qt.AlignLeft)
|
||||||
@@ -292,7 +303,7 @@ class GuiBuildNovel(QDialog):
|
|||||||
|
|
||||||
# Action Buttons
|
# Action Buttons
|
||||||
# ==============
|
# ==============
|
||||||
self.buttonForm = QGridLayout()
|
self.buttonBox = QHBoxLayout()
|
||||||
|
|
||||||
self.btnPrint = QPushButton("Print")
|
self.btnPrint = QPushButton("Print")
|
||||||
self.btnPrint.clicked.connect(self._printDocument)
|
self.btnPrint.clicked.connect(self._printDocument)
|
||||||
@@ -326,12 +337,13 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.saveTXT.triggered.connect(lambda: self._saveDocument(self.FMT_TXT))
|
self.saveTXT.triggered.connect(lambda: self._saveDocument(self.FMT_TXT))
|
||||||
self.saveMenu.addAction(self.saveTXT)
|
self.saveMenu.addAction(self.saveTXT)
|
||||||
|
|
||||||
self.buttonForm.addWidget(self.btnSave, 0, 0)
|
self.btnClose = QPushButton("Close")
|
||||||
self.buttonForm.addWidget(self.btnPrint, 0, 1)
|
self.btnClose.clicked.connect(self._doClose)
|
||||||
|
|
||||||
# Buttons
|
self.buttonBox.addWidget(self.btnSave)
|
||||||
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
|
self.buttonBox.addWidget(self.btnPrint)
|
||||||
self.buttonBox.rejected.connect(self._doClose)
|
self.buttonBox.addWidget(self.btnClose)
|
||||||
|
self.buttonBox.setSpacing(4)
|
||||||
|
|
||||||
# Assemble GUI
|
# Assemble GUI
|
||||||
# ============
|
# ============
|
||||||
@@ -343,18 +355,15 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.toolsBox.addWidget(self.buildProgress)
|
self.toolsBox.addWidget(self.buildProgress)
|
||||||
self.toolsBox.addWidget(self.buildNovel)
|
self.toolsBox.addWidget(self.buildNovel)
|
||||||
self.toolsBox.addSpacing(8)
|
self.toolsBox.addSpacing(8)
|
||||||
self.toolsBox.addLayout(self.buttonForm)
|
self.toolsBox.addLayout(self.buttonBox)
|
||||||
|
|
||||||
self.innerBox.addLayout(self.toolsBox)
|
self.outerBox.addLayout(self.toolsBox)
|
||||||
self.innerBox.addWidget(self.docView)
|
self.outerBox.addWidget(self.docView)
|
||||||
|
self.outerBox.setStretch(0, 0)
|
||||||
|
self.outerBox.setStretch(1, 1)
|
||||||
|
|
||||||
self.outerBox.addLayout(self.innerBox)
|
|
||||||
self.outerBox.addWidget(self.buttonBox)
|
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
|
|
||||||
self.innerBox.setStretch(0, 0)
|
|
||||||
self.innerBox.setStretch(1, 1)
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
logger.debug("GuiBuildNovel initialisation complete")
|
logger.debug("GuiBuildNovel initialisation complete")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from nw.gui.dialogs.about import GuiAbout
|
from nw.gui.dialogs.about import GuiAbout
|
||||||
from nw.gui.dialogs.configeditor import GuiConfigEditor
|
from nw.gui.dialogs.preferences import GuiPreferences
|
||||||
from nw.gui.dialogs.docmerge import GuiDocMerge
|
from nw.gui.dialogs.docmerge import GuiDocMerge
|
||||||
from nw.gui.dialogs.docsplit import GuiDocSplit
|
from nw.gui.dialogs.docsplit import GuiDocSplit
|
||||||
from nw.gui.dialogs.itemeditor import GuiItemEditor
|
from nw.gui.dialogs.itemeditor import GuiItemEditor
|
||||||
@@ -11,7 +11,7 @@ from nw.gui.dialogs.sessionlog import GuiSessionLogView
|
|||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"GuiAbout",
|
"GuiAbout",
|
||||||
"GuiConfigEditor",
|
"GuiPreferences",
|
||||||
"GuiDocMerge",
|
"GuiDocMerge",
|
||||||
"GuiDocSplit",
|
"GuiDocSplit",
|
||||||
"GuiItemEditor",
|
"GuiItemEditor",
|
||||||
|
|||||||
+13
-10
@@ -119,16 +119,19 @@ class GuiAbout(QDialog):
|
|||||||
"<h2>About {name:s}</h2>"
|
"<h2>About {name:s}</h2>"
|
||||||
"<p>{copyright:s}.</p>"
|
"<p>{copyright:s}.</p>"
|
||||||
"<p>Website: <a href='{website:s}'>{domain:s}</a></p>"
|
"<p>Website: <a href='{website:s}'>{domain:s}</a></p>"
|
||||||
"<p>{name:s} is a markdown-like text editor designed for organising and writing "
|
"<p>{name:s} is a markdown-like text editor designed for "
|
||||||
"novels. It is written in Python 3 with a Qt5 GUI, using PyQt5.</p>"
|
"organising and writing novels. It is written in Python 3 with a "
|
||||||
"<p>{name:s} is free software: you can redistribute it and/or modify it under the "
|
"Qt5 GUI, using PyQt5.</p>"
|
||||||
"terms of the GNU General Public License as published by the Free Software Foundation, "
|
"<p>{name:s} is free software: you can redistribute it and/or "
|
||||||
"either version 3 of the License, or (at your option) any later version.</p>"
|
"modify it under the terms of the GNU General Public License as "
|
||||||
"<p>{name:s} is distributed in the hope that it will be useful, but WITHOUT ANY "
|
"published by the Free Software Foundation, either version 3 of "
|
||||||
"WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A "
|
"the License, or (at your option) any later version.</p>"
|
||||||
"PARTICULAR PURPOSE.</p>"
|
"<p>{name:s} is distributed in the hope that it will be useful, "
|
||||||
"<p>See the License tab for the full text, or visit the GNU website at "
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of "
|
||||||
"<a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPL v3.0</a> for more details.</p>"
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</p>"
|
||||||
|
"<p>See the License tab for the full text, or visit the GNU website "
|
||||||
|
"at <a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPL v3.0</a> "
|
||||||
|
"for more details.</p>"
|
||||||
"<h3>Credits</h3>"
|
"<h3>Credits</h3>"
|
||||||
"<p>{credits:s}</p>"
|
"<p>{credits:s}</p>"
|
||||||
).format(
|
).format(
|
||||||
|
|||||||
@@ -150,7 +150,9 @@ class GuiDocSplit(QDialog):
|
|||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return
|
return
|
||||||
|
|
||||||
fHandle = self.theProject.newFolder(srcItem.itemName, srcItem.itemClass, srcItem.parHandle)
|
fHandle = self.theProject.newFolder(
|
||||||
|
srcItem.itemName, srcItem.itemClass, srcItem.parHandle
|
||||||
|
)
|
||||||
self.theParent.treeView.revealTreeItem(fHandle)
|
self.theParent.treeView.revealTreeItem(fHandle)
|
||||||
logger.verbose("Creating folder %s" % fHandle)
|
logger.verbose("Creating folder %s" % fHandle)
|
||||||
|
|
||||||
@@ -174,7 +176,9 @@ class GuiDocSplit(QDialog):
|
|||||||
newItem = self.theProject.projTree[nHandle]
|
newItem = self.theProject.projTree[nHandle]
|
||||||
newItem.setLayout(itemLayout)
|
newItem.setLayout(itemLayout)
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
"Creating new document %s with text from line %d to %d" % (nHandle, iStart, iEnd-1)
|
"Creating new document %s with text from line %d to %d" % (
|
||||||
|
nHandle, iStart, iEnd-1
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
theText = "\n".join(theLines[iStart:iEnd])
|
theText = "\n".join(theLines[iStart:iEnd])
|
||||||
@@ -227,7 +231,9 @@ class GuiDocSplit(QDialog):
|
|||||||
|
|
||||||
spLevel = self.splitLevel.currentData()
|
spLevel = self.splitLevel.currentData()
|
||||||
self.optState.setValue("GuiDocSplit", "spLevel", spLevel)
|
self.optState.setValue("GuiDocSplit", "spLevel", spLevel)
|
||||||
logger.debug("Scanning document %s for headings level <= %d" % (self.sourceItem, spLevel))
|
logger.debug(
|
||||||
|
"Scanning document %s for headings level <= %d" % (self.sourceItem, spLevel)
|
||||||
|
)
|
||||||
|
|
||||||
lineNo = 0
|
lineNo = 0
|
||||||
for aLine in theText.splitlines():
|
for aLine in theText.splitlines():
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ from nw.constants import nwAlert, nwQuotes
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class GuiConfigEditor(PagedDialog):
|
class GuiPreferences(PagedDialog):
|
||||||
|
|
||||||
def __init__(self, theParent, theProject):
|
def __init__(self, theParent, theProject):
|
||||||
PagedDialog.__init__(self, theParent)
|
PagedDialog.__init__(self, theParent)
|
||||||
|
|
||||||
logger.debug("Initialising ConfigEditor ...")
|
logger.debug("Initialising GuiPreferences ...")
|
||||||
|
|
||||||
self.mainConf = nw.CONFIG
|
self.mainConf = nw.CONFIG
|
||||||
self.theParent = theParent
|
self.theParent = theParent
|
||||||
@@ -74,7 +74,7 @@ class GuiConfigEditor(PagedDialog):
|
|||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
logger.debug("ConfigEditor initialisation complete")
|
logger.debug("GuiPreferences initialisation complete")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ class GuiConfigEditor(PagedDialog):
|
|||||||
self.close()
|
self.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
# END Class GuiConfigEditor
|
# END Class GuiPreferences
|
||||||
|
|
||||||
class GuiConfigEditGeneralTab(QWidget):
|
class GuiConfigEditGeneralTab(QWidget):
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ class GuiConfigEditGeneralTab(QWidget):
|
|||||||
|
|
||||||
## Backup Path
|
## Backup Path
|
||||||
self.backupPath = self.mainConf.backupPath
|
self.backupPath = self.mainConf.backupPath
|
||||||
self.backupGetPath = QPushButton(self.theTheme.getIcon("folder-open"),"Select Folder")
|
self.backupGetPath = QPushButton("Browse")
|
||||||
self.backupGetPath.clicked.connect(self._backupFolder)
|
self.backupGetPath.clicked.connect(self._backupFolder)
|
||||||
self.backupPathRow = self.mainForm.addRow(
|
self.backupPathRow = self.mainForm.addRow(
|
||||||
"Backup storage location",
|
"Backup storage location",
|
||||||
@@ -362,7 +362,9 @@ class GuiProjectEditStatus(QWidget):
|
|||||||
self.listBox.takeItem(iRow)
|
self.listBox.takeItem(iRow)
|
||||||
self.colChanged = True
|
self.colChanged = True
|
||||||
else:
|
else:
|
||||||
self.theParent.makeAlert("Cannot delete status item that is in use.",nwAlert.ERROR)
|
self.theParent.makeAlert(
|
||||||
|
"Cannot delete status item that is in use.", nwAlert.ERROR
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
def _saveItem(self):
|
def _saveItem(self):
|
||||||
|
|||||||
@@ -180,11 +180,15 @@ class GuiSessionLogView(QDialog):
|
|||||||
inData = inLine.split()
|
inData = inLine.split()
|
||||||
if len(inData) != 8:
|
if len(inData) != 8:
|
||||||
continue
|
continue
|
||||||
dStart = datetime.strptime("%s %s" % (inData[1],inData[2]), nwConst.tStampFmt)
|
dStart = datetime.strptime(
|
||||||
dEnd = datetime.strptime("%s %s" % (inData[4],inData[5]), nwConst.tStampFmt)
|
"%s %s" % (inData[1],inData[2]), nwConst.tStampFmt
|
||||||
|
)
|
||||||
|
dEnd = datetime.strptime(
|
||||||
|
"%s %s" % (inData[4],inData[5]), nwConst.tStampFmt
|
||||||
|
)
|
||||||
nWords = int(inData[7])
|
nWords = int(inData[7])
|
||||||
tDiff = dEnd - dStart
|
tDiff = dEnd - dStart
|
||||||
sDiff = tDiff.total_seconds()
|
sDiff = tDiff.total_seconds()
|
||||||
|
|
||||||
self.timeTotal += sDiff
|
self.timeTotal += sDiff
|
||||||
if abs(nWords) > 0:
|
if abs(nWords) > 0:
|
||||||
@@ -196,7 +200,9 @@ class GuiSessionLogView(QDialog):
|
|||||||
if hideNegative and nWords < 0:
|
if hideNegative and nWords < 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
newItem = QTreeWidgetItem([str(dStart),self._formatTime(sDiff),str(nWords),""])
|
newItem = QTreeWidgetItem(
|
||||||
|
[str(dStart), self._formatTime(sDiff), str(nWords), ""]
|
||||||
|
)
|
||||||
|
|
||||||
newItem.setTextAlignment(1,Qt.AlignRight)
|
newItem.setTextAlignment(1,Qt.AlignRight)
|
||||||
newItem.setTextAlignment(2,Qt.AlignRight)
|
newItem.setTextAlignment(2,Qt.AlignRight)
|
||||||
@@ -208,7 +214,9 @@ class GuiSessionLogView(QDialog):
|
|||||||
self.listBox.addTopLevelItem(newItem)
|
self.listBox.addTopLevelItem(newItem)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.theParent.makeAlert(["Failed to read session log file.",str(e)], nwAlert.ERROR)
|
self.theParent.makeAlert(
|
||||||
|
["Failed to read session log file.",str(e)], nwAlert.ERROR
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.labelFilter.setText(self._formatTime(self.timeFilter))
|
self.labelFilter.setText(self._formatTime(self.timeFilter))
|
||||||
|
|||||||
@@ -479,7 +479,9 @@ class GuiDocEditor(QTextEdit):
|
|||||||
self.hLight.rehighlight()
|
self.hLight.rehighlight()
|
||||||
qApp.restoreOverrideCursor()
|
qApp.restoreOverrideCursor()
|
||||||
afTime = time()
|
afTime = time()
|
||||||
logger.debug("Document re-highlighted in %.3f milliseconds" % (1000*(afTime-bfTime)))
|
logger.debug(
|
||||||
|
"Document re-highlighted in %.3f milliseconds" % (1000*(afTime-bfTime))
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -716,7 +718,9 @@ class GuiDocEditor(QTextEdit):
|
|||||||
"""
|
"""
|
||||||
sinceActive = time()-self.lastEdit
|
sinceActive = time()-self.lastEdit
|
||||||
if sinceActive > 5*self.wcInterval:
|
if sinceActive > 5*self.wcInterval:
|
||||||
logger.debug("Stopping word count timer: no activity last %.1f seconds" % sinceActive)
|
logger.debug(
|
||||||
|
"Stopping word count timer: no activity last %.1f seconds" % sinceActive
|
||||||
|
)
|
||||||
self.wcTimer.stop()
|
self.wcTimer.stop()
|
||||||
elif self.wCounter.isRunning():
|
elif self.wCounter.isRunning():
|
||||||
logger.verbose("Word counter thread is busy")
|
logger.verbose("Word counter thread is busy")
|
||||||
@@ -952,7 +956,9 @@ class GuiDocEditor(QTextEdit):
|
|||||||
theText = newText
|
theText = newText
|
||||||
cOffset -= 0
|
cOffset -= 0
|
||||||
else:
|
else:
|
||||||
logger.error("Unknown or unsupported block format requested: %s" % str(docAction))
|
logger.error(
|
||||||
|
"Unknown or unsupported block format requested: %s" % str(docAction)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Replace the block text
|
# Replace the block text
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ class GuiDocTree(QTreeWidget):
|
|||||||
trItemP.takeChild(tIndex)
|
trItemP.takeChild(tIndex)
|
||||||
del self.theProject.projTree[tHandle]
|
del self.theProject.projTree[tHandle]
|
||||||
else:
|
else:
|
||||||
self.makeAlert(["Cannot delete folder.","It is not empty."], nwAlert.ERROR)
|
self.makeAlert("Cannot delete folder. It is not empty.", nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
elif nwItemS.itemType == nwItemType.ROOT:
|
elif nwItemS.itemType == nwItemType.ROOT:
|
||||||
@@ -407,7 +407,7 @@ class GuiDocTree(QTreeWidget):
|
|||||||
self.theParent.mainMenu.setAvailableRoot()
|
self.theParent.mainMenu.setAvailableRoot()
|
||||||
self.theProject.setProjectChanged(True)
|
self.theProject.setProjectChanged(True)
|
||||||
else:
|
else:
|
||||||
self.makeAlert(["Cannot delete root folder.","It is not empty."], nwAlert.ERROR)
|
self.makeAlert("Cannot delete root folder. It is not empty.", nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
+6
-2
@@ -249,7 +249,9 @@ class GuiIcons:
|
|||||||
try:
|
try:
|
||||||
confParser.read_file(open(themeConf, mode="r", encoding="utf8"))
|
confParser.read_file(open(themeConf, mode="r", encoding="utf8"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.theParent.makeAlert(["Could not load theme config file.",str(e)],nwAlert.ERROR)
|
self.theParent.makeAlert(
|
||||||
|
["Could not load theme config file.",str(e)], nwAlert.ERROR
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
themeName = ""
|
themeName = ""
|
||||||
if confParser.has_section("Main"):
|
if confParser.has_section("Main"):
|
||||||
@@ -295,7 +297,9 @@ class GuiIcons:
|
|||||||
|
|
||||||
# Finally. we check if we have a fallback icon
|
# Finally. we check if we have a fallback icon
|
||||||
if self.mainConf.guiDark:
|
if self.mainConf.guiDark:
|
||||||
fbackIcon = path.join(self.mainConf.iconPath, self.fbackName, "%s-dark.svg" % iconKey)
|
fbackIcon = path.join(
|
||||||
|
self.mainConf.iconPath, self.fbackName, "%s-dark.svg" % iconKey
|
||||||
|
)
|
||||||
if path.isfile(fbackIcon):
|
if path.isfile(fbackIcon):
|
||||||
logger.verbose("Loading icon '%s' from fallback theme" % iconKey)
|
logger.verbose("Loading icon '%s' from fallback theme" % iconKey)
|
||||||
return QIcon(fbackIcon)
|
return QIcon(fbackIcon)
|
||||||
|
|||||||
+5
-1
@@ -137,13 +137,17 @@ class GuiMainStatus(QStatusBar):
|
|||||||
self._updateTime()
|
self._updateTime()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
##
|
||||||
|
# Setters
|
||||||
|
##
|
||||||
|
|
||||||
def setRefTime(self, theTime):
|
def setRefTime(self, theTime):
|
||||||
"""Set the reference time for the status bar clock.
|
"""Set the reference time for the status bar clock.
|
||||||
"""
|
"""
|
||||||
self.refTime = theTime
|
self.refTime = theTime
|
||||||
return
|
return
|
||||||
|
|
||||||
def setStatus(self, theMessage, timeOut=10.0):
|
def setStatus(self, theMessage, timeOut=20.0):
|
||||||
"""Set the status bar message to display for 'timeOut' seconds.
|
"""Set the status bar message to display for 'timeOut' seconds.
|
||||||
"""
|
"""
|
||||||
self.showMessage(theMessage, int(timeOut*1000))
|
self.showMessage(theMessage, int(timeOut*1000))
|
||||||
|
|||||||
+6
-2
@@ -284,7 +284,9 @@ class GuiTheme:
|
|||||||
try:
|
try:
|
||||||
confParser.read_file(open(themeConf, mode="r", encoding="utf8"))
|
confParser.read_file(open(themeConf, mode="r", encoding="utf8"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.theParent.makeAlert(["Could not load theme config file.",str(e)],nwAlert.ERROR)
|
self.theParent.makeAlert(
|
||||||
|
["Could not load theme config file.",str(e)], nwAlert.ERROR
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
themeName = ""
|
themeName = ""
|
||||||
if confParser.has_section("Main"):
|
if confParser.has_section("Main"):
|
||||||
@@ -314,7 +316,9 @@ class GuiTheme:
|
|||||||
try:
|
try:
|
||||||
confParser.read_file(open(syntaxPath, mode="r", encoding="utf8"))
|
confParser.read_file(open(syntaxPath, mode="r", encoding="utf8"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.theParent.makeAlert(["Could not load syntax file.",str(e)],nwAlert.ERROR)
|
self.theParent.makeAlert(
|
||||||
|
["Could not load syntax file.",str(e)], nwAlert.ERROR
|
||||||
|
)
|
||||||
return []
|
return []
|
||||||
syntaxName = ""
|
syntaxName = ""
|
||||||
if confParser.has_section("Main"):
|
if confParser.has_section("Main"):
|
||||||
|
|||||||
+15
-11
@@ -42,7 +42,7 @@ from PyQt5.QtWidgets import (
|
|||||||
from nw.gui import (
|
from nw.gui import (
|
||||||
GuiMainMenu, GuiMainStatus, GuiTheme, GuiDocTree, GuiDocEditor,
|
GuiMainMenu, GuiMainStatus, GuiTheme, GuiDocTree, GuiDocEditor,
|
||||||
GuiDocViewer, GuiDocDetails, GuiSearchBar, GuiNoticeBar, GuiDocViewDetails,
|
GuiDocViewer, GuiDocDetails, GuiSearchBar, GuiNoticeBar, GuiDocViewDetails,
|
||||||
GuiConfigEditor, GuiProjectSettings, GuiItemEditor, GuiProjectOutline,
|
GuiPreferences, GuiProjectSettings, GuiItemEditor, GuiProjectOutline,
|
||||||
GuiSessionLogView, GuiDocMerge, GuiDocSplit, GuiProjectLoad, GuiBuildNovel
|
GuiSessionLogView, GuiDocMerge, GuiDocSplit, GuiProjectLoad, GuiBuildNovel
|
||||||
)
|
)
|
||||||
from nw.core import NWProject, NWDoc, NWIndex
|
from nw.core import NWProject, NWDoc, NWIndex
|
||||||
@@ -553,7 +553,7 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
if self.docEditor.theHandle is None:
|
if self.docEditor.theHandle is None:
|
||||||
self.makeAlert(
|
self.makeAlert(
|
||||||
["Please open a document to import the text file into."],
|
"Please open a document to import the text file into.",
|
||||||
nwAlert.ERROR
|
nwAlert.ERROR
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
@@ -668,6 +668,12 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
theDoc = NWDoc(self.theProject, self)
|
theDoc = NWDoc(self.theProject, self)
|
||||||
for nDone, tItem in enumerate(self.theProject.projTree):
|
for nDone, tItem in enumerate(self.theProject.projTree):
|
||||||
|
|
||||||
|
if tItem is not None:
|
||||||
|
self.statusBar.setStatus("Indexing: '%s'" % tItem.itemName)
|
||||||
|
else:
|
||||||
|
self.statusBar.setStatus("Indexing: Unknown item")
|
||||||
|
|
||||||
if tItem is not None and tItem.itemType == nwItemType.FILE:
|
if tItem is not None and tItem.itemType == nwItemType.FILE:
|
||||||
logger.verbose("Scanning: %s" % tItem.itemName)
|
logger.verbose("Scanning: %s" % tItem.itemName)
|
||||||
theText = theDoc.openDocument(tItem.itemHandle, showStatus=False)
|
theText = theDoc.openDocument(tItem.itemHandle, showStatus=False)
|
||||||
@@ -683,16 +689,14 @@ class GuiMain(QMainWindow):
|
|||||||
self.treeView.propagateCount(tItem.itemHandle, wC)
|
self.treeView.propagateCount(tItem.itemHandle, wC)
|
||||||
self.treeView.projectWordCount()
|
self.treeView.projectWordCount()
|
||||||
|
|
||||||
self.statusBar.setStatus("Building index: %.2f%%" % (100.0*(nDone + 1)/nItems))
|
|
||||||
|
|
||||||
self.docEditor.reloadText()
|
|
||||||
qApp.restoreOverrideCursor()
|
|
||||||
tEnd = time()
|
tEnd = time()
|
||||||
|
self.statusBar.setStatus("Indexing completed in %.1f ms" % ((tEnd - tStart)*1000.0))
|
||||||
|
self.docEditor.reloadText()
|
||||||
|
|
||||||
|
qApp.restoreOverrideCursor()
|
||||||
|
|
||||||
if self.mainConf.showGUI:
|
if self.mainConf.showGUI:
|
||||||
self.makeAlert(
|
self.makeAlert("The project index has been successfully rebuilt.", nwAlert.INFO)
|
||||||
"Project index rebuilt in %.3f seconds." % (tEnd - tStart), nwAlert.INFO
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -737,7 +741,7 @@ class GuiMain(QMainWindow):
|
|||||||
def editConfigDialog(self):
|
def editConfigDialog(self):
|
||||||
"""Open the preferences dialog.
|
"""Open the preferences dialog.
|
||||||
"""
|
"""
|
||||||
dlgConf = GuiConfigEditor(self, self.theProject)
|
dlgConf = GuiPreferences(self, self.theProject)
|
||||||
if dlgConf.exec_() == QDialog.Accepted:
|
if dlgConf.exec_() == QDialog.Accepted:
|
||||||
logger.debug("Applying new preferences")
|
logger.debug("Applying new preferences")
|
||||||
self.initMain()
|
self.initMain()
|
||||||
@@ -778,7 +782,7 @@ class GuiMain(QMainWindow):
|
|||||||
0 = info, 1 = warning, and 2 = error.
|
0 = info, 1 = warning, and 2 = error.
|
||||||
"""
|
"""
|
||||||
if isinstance(theMessage, list):
|
if isinstance(theMessage, list):
|
||||||
popMsg = " ".join(theMessage)
|
popMsg = "<br>".join(theMessage)
|
||||||
logMsg = theMessage
|
logMsg = theMessage
|
||||||
else:
|
else:
|
||||||
popMsg = theMessage
|
popMsg = theMessage
|
||||||
|
|||||||
Reference in New Issue
Block a user