Merge pull request #391 from vkbo/code_cleanup

Code Cleanup
This commit is contained in:
Veronica K. Berglyd Olsen
2020-08-08 22:01:34 +02:00
committed by GitHub
24 changed files with 286 additions and 164 deletions
+9 -3
View File
@@ -35,6 +35,8 @@ from nw.constants import nwConst
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def checkString(checkValue, defaultValue, allowNone=False): def checkString(checkValue, defaultValue, allowNone=False):
"""Check if a variable is a string or a none.
"""
if allowNone: if allowNone:
if checkValue == None: if checkValue == None:
return None return None
@@ -45,6 +47,8 @@ def checkString(checkValue, defaultValue, allowNone=False):
return defaultValue return defaultValue
def checkInt(checkValue, defaultValue, allowNone=False): def checkInt(checkValue, defaultValue, allowNone=False):
"""Check if a variable is an integer or a none.
"""
if allowNone: if allowNone:
if checkValue == None: if checkValue == None:
return None return None
@@ -56,6 +60,8 @@ def checkInt(checkValue, defaultValue, allowNone=False):
return defaultValue return defaultValue
def checkBool(checkValue, defaultValue, allowNone=False): def checkBool(checkValue, defaultValue, allowNone=False):
"""Check if a variable is a boolean or a none.
"""
if allowNone: if allowNone:
if checkValue == None: if checkValue == None:
return None return None
@@ -92,7 +98,8 @@ def isHandle(theString):
return not invalidChar return not invalidChar
def colRange(rgbStart, rgbEnd, nStep): def colRange(rgbStart, rgbEnd, nStep):
"""Generate a range of colours from one RGB value to another.
"""
if len(rgbStart) != 3 and len(rgbEnd) != 3 and nStep < 1: if len(rgbStart) != 3 and len(rgbEnd) != 3 and nStep < 1:
logger.error("Cannot create colour range from given parameters") logger.error("Cannot create colour range from given parameters")
return None return None
@@ -124,7 +131,7 @@ def colRange(rgbStart, rgbEnd, nStep):
def formatInt(theInt): def formatInt(theInt):
"""Formats an integer with k, M, G etc. """Formats an integer with k, M, G etc.
""" """
postFix = ["k","M","G","T","P","E"] postFix = ["k", "M", "G", "T", "P", "E"]
theVal = float(theInt) theVal = float(theInt)
if theVal > 1000.0: if theVal > 1000.0:
@@ -153,7 +160,6 @@ def splitVersionNumber(vString):
""" Splits a version string on the form aa.bb.cc into major, minor """ Splits a version string on the form aa.bb.cc into major, minor
and patch, and computes an integer value aabbcc. and patch, and computes an integer value aabbcc.
""" """
vMajor = 0 vMajor = 0
vMinor = 0 vMinor = 0
vPatch = 0 vPatch = 0
+11 -3
View File
@@ -88,7 +88,7 @@ class Config:
self.guiSyntax = "default_light" self.guiSyntax = "default_light"
self.guiIcons = "typicons_colour_light" self.guiIcons = "typicons_colour_light"
self.guiDark = False self.guiDark = False
self.guiLang = "en" # Hardcoded for now self.guiLang = "en" # Hardcoded for now since the GUI is only in English
self.guiFont = "" self.guiFont = ""
self.guiFontSize = 11 self.guiFontSize = 11
self.guiScale = 1.0 # Set automatically by Theme class self.guiScale = 1.0 # Set automatically by Theme class
@@ -286,7 +286,7 @@ class Config:
# Check if config file exists # Check if config file exists
if self.confPath is not None: if self.confPath is not None:
if path.isfile(path.join(self.confPath,self.confFile)): if path.isfile(path.join(self.confPath, self.confFile)):
# If it exists, load it # If it exists, load it
self.loadConfig() self.loadConfig()
else: else:
@@ -855,7 +855,9 @@ class Config:
## ##
def _unpackList(self, inStr, listLen, listDefault, castTo=int): def _unpackList(self, inStr, listLen, listDefault, castTo=int):
inData = inStr.split(",") """Unpack a comma separated string of items into a list.
"""
inData = inStr.split(",")
outData = [] outData = []
for i in range(listLen): for i in range(listLen):
try: try:
@@ -865,9 +867,13 @@ class Config:
return outData return outData
def _packList(self, inData): def _packList(self, inData):
"""Pack a list of items into a comma separated string.
"""
return ", ".join(str(inVal) for inVal in inData) return ", ".join(str(inVal) for inVal in inData)
def _parseLine(self, cnfParse, cnfSec, cnfName, cnfType, cnfDefault): def _parseLine(self, cnfParse, cnfSec, cnfName, cnfType, cnfDefault):
"""Parse a line and return the correct datatype.
"""
if cnfParse.has_section(cnfSec): if cnfParse.has_section(cnfSec):
if cnfParse.has_option(cnfSec, cnfName): if cnfParse.has_option(cnfSec, cnfName):
if cnfType == self.CNF_STR: if cnfType == self.CNF_STR:
@@ -883,6 +889,8 @@ class Config:
return cnfDefault return cnfDefault
def _checkNone(self, checkVal): def _checkNone(self, checkVal):
"""Convert a string to a none type.
"""
if checkVal is None: if checkVal is None:
return None return None
if isinstance(checkVal, str): if isinstance(checkVal, str):
+1 -1
View File
@@ -25,7 +25,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from nw.constants.enum import nwItemClass, nwItemLayout, nwOutline, nwDocInsert from nw.constants.enum import nwItemClass, nwItemLayout, nwOutline
class nwConst(): class nwConst():
+6 -5
View File
@@ -28,7 +28,7 @@
import logging import logging
import nw import nw
from os import path, mkdir, rename, unlink from os import path, rename, unlink
from nw.core.item import NWItem from nw.core.item import NWItem
from nw.constants import nwAlert from nw.constants import nwAlert
@@ -44,10 +44,11 @@ class NWDoc():
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
self.theProject = theProject self.theProject = theProject
self.theParent = theParent self.theParent = theParent
self.theItem = None
self.docHandle = None self.theItem = None
self.fileLoc = None self.docHandle = None
self.docMeta = "" self.fileLoc = None
self.docMeta = ""
# Internal Mapping # Internal Mapping
self.makeAlert = self.theParent.makeAlert self.makeAlert = self.theParent.makeAlert
-1
View File
@@ -195,7 +195,6 @@ class NWSpellEnchant(NWSpellCheck):
class NWSpellEnchantDummy: class NWSpellEnchantDummy:
"""Fallback for when Enchant is selected, but not installed. """Fallback for when Enchant is selected, but not installed.
""" """
def __init__(self): def __init__(self):
return return
-3
View File
@@ -227,7 +227,6 @@ class Tokenizer():
"""Set the text for the tokenizer from a handle. If theText is """Set the text for the tokenizer from a handle. If theText is
not set, load it from the file. not set, load it from the file.
""" """
self.theHandle = theHandle self.theHandle = theHandle
self.theItem = self.theProject.projTree[theHandle] self.theItem = self.theProject.projTree[theHandle]
if self.theItem is None: if self.theItem is None:
@@ -308,7 +307,6 @@ class Tokenizer():
4: The internal formatting map of the text, self.FMT_* 4: The internal formatting map of the text, self.FMT_*
5: The style of the block, self.A_* 5: The style of the block, self.A_*
""" """
# RegExes for adding formatting tags within text lines # RegExes for adding formatting tags within text lines
rxFormats = [ rxFormats = [
(QRegularExpression(nwRegEx.FMT_I), [None, self.FMT_I_B, None, self.FMT_I_E]), (QRegularExpression(nwRegEx.FMT_I), [None, self.FMT_I_B, None, self.FMT_I_E]),
@@ -457,7 +455,6 @@ class Tokenizer():
"""Apply formatting to the text headers according to document """Apply formatting to the text headers according to document
layout and user settings. layout and user settings.
""" """
# No special header formatting for notes and no-layout files # No special header formatting for notes and no-layout files
if self.isNone or self.isNote: if self.isNone or self.isNote:
return return
-2
View File
@@ -30,8 +30,6 @@
import logging import logging
import nw import nw
from os import path, unlink, rmdir
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# =============================================================================================== # # =============================================================================================== #
+3 -3
View File
@@ -46,7 +46,7 @@ def formatHtmlErrMsg(exType, exValue, exTrace):
"<p>Please report this error by submitting an issue report on " "<p>Please report this error by submitting an issue report on "
"GitHub, providing a description and this error message. " "GitHub, providing a description and this error message. "
"URL: &lt;{issueUrl}&gt;.</p>" "URL: &lt;{issueUrl}&gt;.</p>"
"<p><b>Environment</b><br>Version: {nwVersion}, OS: {osType} ({osKernel})," "<p><b>Environment</b><br>Version: {nwVersion}, OS: {osType} ({osKernel}), "
"Python: {pyVersion} ({pyHexVer:#x}), Qt: {qtVers}, PyQt: {pyqtVers}</p>" "Python: {pyVersion} ({pyHexVer:#x}), Qt: {qtVers}, PyQt: {pyqtVers}</p>"
"<p><b>Error Type</b><br>{exType}: {exMessage}</p>" "<p><b>Error Type</b><br>{exType}: {exMessage}</p>"
"<p><b>Traceback</b><br>{exTrace}</p>" "<p><b>Traceback</b><br>{exTrace}</p>"
@@ -76,9 +76,9 @@ def exceptionHandler(exType, exValue, exTrace):
"""Function to catch unhandled global exceptions. """Function to catch unhandled global exceptions.
""" """
import logging import logging
from traceback import print_tb, format_tb from traceback import print_tb
from nw import CONFIG from nw import CONFIG
from PyQt5.QtWidgets import qApp, QApplication, QErrorMessage, QMessageBox from PyQt5.QtWidgets import qApp, QErrorMessage
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.error("%s: %s" % (exType.__name__, str(exValue))) logger.error("%s: %s" % (exType.__name__, str(exValue)))
+1 -1
View File
@@ -39,7 +39,7 @@ from PyQt5.QtCore import (
Qt, QSize, QThread, QTimer, pyqtSlot, QRegExp, QRegularExpression Qt, QSize, QThread, QTimer, pyqtSlot, QRegExp, QRegularExpression
) )
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QTextCursor, QTextOption, QKeySequence, QFont, QColor, QPalette, QIcon, QTextCursor, QTextOption, QKeySequence, QFont, QColor, QPalette,
QTextDocument, QCursor, QPixmap QTextDocument, QCursor, QPixmap
) )
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
-2
View File
@@ -95,7 +95,6 @@ class GuiDocMerge(QDialog):
create a new file in the same parent folder. The old files are create a new file in the same parent folder. The old files are
not removed in the merge process, and must be deleted manually. not removed in the merge process, and must be deleted manually.
""" """
logger.verbose("GuiDocMerge merge button clicked") logger.verbose("GuiDocMerge merge button clicked")
finalOrder = [] finalOrder = []
@@ -142,7 +141,6 @@ class GuiDocMerge(QDialog):
are then added to the list view in order. The list itself can be are then added to the list view in order. The list itself can be
reordered by the user. reordered by the user.
""" """
tHandle = self.theParent.treeView.getSelectedHandle() tHandle = self.theParent.treeView.getSelectedHandle()
self.sourceItem = tHandle self.sourceItem = tHandle
if tHandle is None: if tHandle is None:
+2 -3
View File
@@ -33,6 +33,7 @@ from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QComboBox, QListWidget, QAbstractItemView, QDialog, QVBoxLayout, QComboBox, QListWidget, QAbstractItemView,
QListWidgetItem, QDialogButtonBox, QLabel QListWidgetItem, QDialogButtonBox, QLabel
) )
from nw.constants import nwAlert, nwItemType, nwItemClass, nwItemLayout from nw.constants import nwAlert, nwItemType, nwItemClass, nwItemLayout
from nw.gui.custom import QHelpLabel from nw.gui.custom import QHelpLabel
from nw.core import NWDoc from nw.core import NWDoc
@@ -109,7 +110,6 @@ class GuiDocSplit(QDialog):
settings. The old file is not removed in the merge process, and settings. The old file is not removed in the merge process, and
must be deleted manually. must be deleted manually.
""" """
logger.verbose("GuiDocSplit split button clicked") logger.verbose("GuiDocSplit split button clicked")
if self.sourceItem is None: if self.sourceItem is None:
@@ -131,7 +131,7 @@ class GuiDocSplit(QDialog):
nLines = len(theLines) nLines = len(theLines)
theLines.insert(0, "%Split Doc") theLines.insert(0, "%Split Doc")
logger.debug( logger.debug(
"Splitting document %s with %d lines" % (self.sourceItem,nLines) "Splitting document %s with %d lines" % (self.sourceItem, nLines)
) )
finalOrder = [] finalOrder = []
@@ -209,7 +209,6 @@ class GuiDocSplit(QDialog):
are then added to the list view in order. The list itself can be are then added to the list view in order. The list itself can be
reordered by the user. reordered by the user.
""" """
if self.sourceItem is None: if self.sourceItem is None:
self.sourceItem = self.theParent.treeView.getSelectedHandle() self.sourceItem = self.theParent.treeView.getSelectedHandle()
+2 -2
View File
@@ -29,11 +29,11 @@ import logging
import nw import nw
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QIcon, QPixmap from PyQt5.QtGui import QFont, QPixmap
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
from nw.constants import ( from nw.constants import (
nwLabels, nwItemClass, nwItemType, nwItemLayout, nwUnicode nwLabels, nwItemClass, nwItemType, nwItemLayout
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
+2 -2
View File
@@ -28,7 +28,6 @@
import logging import logging
import nw import nw
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QGridLayout, QLineEdit, QComboBox, QLabel, QDialog, QVBoxLayout, QGridLayout, QLineEdit, QComboBox, QLabel,
QDialogButtonBox QDialogButtonBox
@@ -151,7 +150,6 @@ class GuiItemEditor(QDialog):
def _doSave(self): def _doSave(self):
"""Save the setting to the item. """Save the setting to the item.
""" """
logger.verbose("ItemEditor save button clicked") logger.verbose("ItemEditor save button clicked")
itemName = self.editName.text() itemName = self.editName.text()
@@ -172,6 +170,8 @@ class GuiItemEditor(QDialog):
return return
def _doClose(self): def _doClose(self):
"""Close the dialog without saving the settings.
"""
logger.verbose("ItemEditor close button clicked") logger.verbose("ItemEditor close button clicked")
self.close() self.close()
return return
+18 -9
View File
@@ -192,7 +192,8 @@ class GuiMainMenu(QMenuBar):
## ##
def _buildProjectMenu(self): def _buildProjectMenu(self):
"""Assemble the Project menu.
"""
# Project # Project
self.projMenu = self.addMenu("&Project") self.projMenu = self.addMenu("&Project")
@@ -295,7 +296,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildDocumentMenu(self): def _buildDocumentMenu(self):
"""Assemble the Document menu.
"""
# Document # Document
self.docuMenu = self.addMenu("&Document") self.docuMenu = self.addMenu("&Document")
@@ -377,7 +379,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildEditMenu(self): def _buildEditMenu(self):
"""Assemble the Edit menu.
"""
# Edit # Edit
self.editMenu = self.addMenu("&Edit") self.editMenu = self.addMenu("&Edit")
@@ -439,7 +442,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildViewMenu(self): def _buildViewMenu(self):
"""Assemble the View menu.
"""
# View # View
self.viewMenu = self.addMenu("&View") self.viewMenu = self.addMenu("&View")
@@ -486,7 +490,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildInsertMenu(self): def _buildInsertMenu(self):
"""Assemble the Insert menu.
"""
# Insert # Insert
self.insertMenu = self.addMenu("&Insert") self.insertMenu = self.addMenu("&Insert")
@@ -576,7 +581,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildSearchMenu(self): def _buildSearchMenu(self):
"""Assemble the Search menu.
"""
# Search # Search
self.srcMenu = self.addMenu("&Search") self.srcMenu = self.addMenu("&Search")
@@ -627,7 +633,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildFormatMenu(self): def _buildFormatMenu(self):
"""Assemble the Format menu.
"""
# Format # Format
self.fmtMenu = self.addMenu("&Format") self.fmtMenu = self.addMenu("&Format")
@@ -732,7 +739,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildToolsMenu(self): def _buildToolsMenu(self):
"""Assemble the Tools menu.
"""
# Tools # Tools
self.toolsMenu = self.addMenu("&Tools") self.toolsMenu = self.addMenu("&Tools")
@@ -828,7 +836,8 @@ class GuiMainMenu(QMenuBar):
return return
def _buildHelpMenu(self): def _buildHelpMenu(self):
"""Assemble the Help menu.
"""
# Help # Help
self.helpMenu = self.addMenu("&Help") self.helpMenu = self.addMenu("&Help")
+4
View File
@@ -195,8 +195,10 @@ class GuiOutline(QTreeWidget):
tLine = int(tItem.text(self.colIndex[nwOutline.LINE])) tLine = int(tItem.text(self.colIndex[nwOutline.LINE]))
except: except:
tLine = 1 tLine = 1
logger.verbose("User selected entry with handle %s on line %s" % (tHandle, tLine)) logger.verbose("User selected entry with handle %s on line %s" % (tHandle, tLine))
self.theParent.openDocument(tHandle, tLine=tLine-1, doScroll=True) self.theParent.openDocument(tHandle, tLine=tLine-1, doScroll=True)
return return
def _itemSelected(self): def _itemSelected(self):
@@ -208,6 +210,7 @@ class GuiOutline(QTreeWidget):
tHandle = selItems[0].data(self.colIndex[nwOutline.TITLE], Qt.UserRole) tHandle = selItems[0].data(self.colIndex[nwOutline.TITLE], Qt.UserRole)
sTitle = selItems[0].data(self.colIndex[nwOutline.LINE], Qt.UserRole) sTitle = selItems[0].data(self.colIndex[nwOutline.LINE], Qt.UserRole)
self.theParent.projMeta.showItem(tHandle, sTitle) self.theParent.projMeta.showItem(tHandle, sTitle)
return return
def _headerRightClick(self, clickPos): def _headerRightClick(self, clickPos):
@@ -232,6 +235,7 @@ class GuiOutline(QTreeWidget):
if theItem in self.colIndex: if theItem in self.colIndex:
self.setColumnHidden(self.colIndex[theItem], not isChecked) self.setColumnHidden(self.colIndex[theItem], not isChecked)
self._saveHeaderState() self._saveHeaderState()
return return
## ##
+2 -1
View File
@@ -30,7 +30,8 @@ import nw
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QScrollArea, QWidget, QGridLayout, QHBoxLayout, QGroupBox, QLabel, QSizePolicy QScrollArea, QWidget, QGridLayout, QHBoxLayout, QGroupBox, QLabel,
QSizePolicy
) )
from nw.constants import nwLabels, nwKeyWords from nw.constants import nwLabels, nwKeyWords
+17 -6
View File
@@ -80,7 +80,9 @@ class GuiPreferences(PagedDialog):
## ##
def _doSave(self): def _doSave(self):
"""Trigger all the save functions in the tabs, and collect the
status of the saves.
"""
logger.verbose("ConfigEditor save button clicked") logger.verbose("ConfigEditor save button clicked")
validEntries = True validEntries = True
@@ -115,6 +117,8 @@ class GuiPreferences(PagedDialog):
return return
def _doClose(self): def _doClose(self):
"""Close the preferences without saving the changes.
"""
logger.verbose("ConfigEditor close button clicked") logger.verbose("ConfigEditor close button clicked")
self.close() self.close()
return return
@@ -284,7 +288,8 @@ class GuiConfigEditGeneralTab(QWidget):
return return
def saveValues(self): def saveValues(self):
"""Save the values set for this tab.
"""
validEntries = True validEntries = True
needsRestart = False needsRestart = False
@@ -329,7 +334,6 @@ class GuiConfigEditGeneralTab(QWidget):
def _backupFolder(self): def _backupFolder(self):
"""Open a dialog to select the backup folder. """Open a dialog to select the backup folder.
""" """
currDir = self.backupPath currDir = self.backupPath
if not path.isdir(currDir): if not path.isdir(currDir):
currDir = "" currDir = ""
@@ -515,7 +519,8 @@ class GuiConfigEditLayoutTab(QWidget):
return return
def saveValues(self): def saveValues(self):
"""Save the values set for this tab.
"""
validEntries = True validEntries = True
needsRestart = False needsRestart = False
@@ -681,7 +686,8 @@ class GuiConfigEditEditingTab(QWidget):
return return
def saveValues(self): def saveValues(self):
"""Save the values set for this tab.
"""
validEntries = True validEntries = True
needsRestart = False needsRestart = False
@@ -712,6 +718,8 @@ class GuiConfigEditEditingTab(QWidget):
## ##
def _disableComboItem(self, theList, theValue): def _disableComboItem(self, theList, theValue):
"""Disable a list item in the combo box.
"""
theIdx = theList.findData(theValue) theIdx = theList.findData(theValue)
theModel = theList.model() theModel = theList.model()
anItem = theModel.item(1) anItem = theModel.item(1)
@@ -719,6 +727,8 @@ class GuiConfigEditEditingTab(QWidget):
return theModel return theModel
def _doUpdateSpellTool(self, currIdx): def _doUpdateSpellTool(self, currIdx):
"""Update the list of dictionaries based on spell tool selected.
"""
spellTool = self.spellToolList.currentData() spellTool = self.spellToolList.currentData()
self._updateLanguageList(spellTool) self._updateLanguageList(spellTool)
return return
@@ -903,7 +913,8 @@ class GuiConfigEditAutoReplaceTab(QWidget):
return return
def saveValues(self): def saveValues(self):
"""Save the values set for this tab.
"""
validEntries = True validEntries = True
needsRestart = False needsRestart = False
+3
View File
@@ -152,6 +152,7 @@ class GuiProjectLoad(QDialog):
""" """
logger.verbose("GuiProjectLoad open button clicked") logger.verbose("GuiProjectLoad open button clicked")
self._saveDialogState() self._saveDialogState()
selItems = self.listBox.selectedItems() selItems = self.listBox.selectedItems()
if selItems: if selItems:
self.openPath = selItems[0].data(self.C_NAME, Qt.UserRole) self.openPath = selItems[0].data(self.C_NAME, Qt.UserRole)
@@ -160,6 +161,7 @@ class GuiProjectLoad(QDialog):
else: else:
self.openPath = None self.openPath = None
self.openState = self.NONE_STATE self.openState = self.NONE_STATE
return return
def _doSelectRecent(self): def _doSelectRecent(self):
@@ -189,6 +191,7 @@ class GuiProjectLoad(QDialog):
self.openPath = thePath self.openPath = thePath
self.openState = self.OPEN_STATE self.openState = self.OPEN_STATE
self.accept() self.accept()
return return
def _doClose(self): def _doClose(self):
+44 -9
View File
@@ -97,6 +97,7 @@ class GuiProjectSettings(PagedDialog):
bookTitle = self.tabMain.editTitle.text() bookTitle = self.tabMain.editTitle.text()
bookAuthors = self.tabMain.editAuthors.toPlainText() bookAuthors = self.tabMain.editAuthors.toPlainText()
doBackup = not self.tabMain.doBackup.isChecked() doBackup = not self.tabMain.doBackup.isChecked()
self.theProject.setProjectName(projName) self.theProject.setProjectName(projName)
self.theProject.setBookTitle(bookTitle) self.theProject.setBookTitle(bookTitle)
self.theProject.setBookAuthors(bookAuthors) self.theProject.setBookAuthors(bookAuthors)
@@ -105,11 +106,14 @@ class GuiProjectSettings(PagedDialog):
if self.tabStatus.colChanged: if self.tabStatus.colChanged:
statusCol = self.tabStatus.getNewList() statusCol = self.tabStatus.getNewList()
self.theProject.setStatusColours(statusCol) self.theProject.setStatusColours(statusCol)
if self.tabImport.colChanged: if self.tabImport.colChanged:
importCol = self.tabImport.getNewList() importCol = self.tabImport.getNewList()
self.theProject.setImportColours(importCol) self.theProject.setImportColours(importCol)
if self.tabStatus.colChanged or self.tabImport.colChanged: if self.tabStatus.colChanged or self.tabImport.colChanged:
self.theParent.rebuildTree() self.theParent.rebuildTree()
if self.tabReplace.arChanged: if self.tabReplace.arChanged:
newList = self.tabReplace.getNewList() newList = self.tabReplace.getNewList()
self.theProject.setAutoReplace(newList) self.theProject.setAutoReplace(newList)
@@ -119,7 +123,7 @@ class GuiProjectSettings(PagedDialog):
return return
def _doClose(self): def _doClose(self):
"""Close the dialog. """Save settings and close the dialog.
""" """
winWidth = self.mainConf.rpxInt(self.width()) winWidth = self.mainConf.rpxInt(self.width())
winHeight = self.mainConf.rpxInt(self.height()) winHeight = self.mainConf.rpxInt(self.height())
@@ -372,6 +376,8 @@ class GuiProjectEditStatus(QWidget):
## ##
def _selectColour(self): def _selectColour(self):
"""Open a dialog to select the status icon colour.
"""
logger.verbose("Item colour button clicked") logger.verbose("Item colour button clicked")
if self.selColour is not None: if self.selColour is not None:
newCol = QColorDialog.getColor( newCol = QColorDialog.getColor(
@@ -386,6 +392,8 @@ class GuiProjectEditStatus(QWidget):
return return
def _newItem(self): def _newItem(self):
"""Create a new status item.
"""
logger.verbose("New item button clicked") logger.verbose("New item button clicked")
newItem = self._addItem("New Item", (0, 0, 0), None, 0) newItem = self._addItem("New Item", (0, 0, 0), None, 0)
newItem.setBackground(QBrush(QColor(0, 255, 0, 80))) newItem.setBackground(QBrush(QColor(0, 255, 0, 80)))
@@ -393,6 +401,8 @@ class GuiProjectEditStatus(QWidget):
return return
def _delItem(self): def _delItem(self):
"""Delete a status item.
"""
logger.verbose("Delete item button clicked") logger.verbose("Delete item button clicked")
selItem = self._getSelectedItem() selItem = self._getSelectedItem()
if selItem is not None: if selItem is not None:
@@ -408,6 +418,8 @@ class GuiProjectEditStatus(QWidget):
return return
def _saveItem(self): def _saveItem(self):
"""Save changes made to a status item.
"""
logger.verbose("Save item button clicked") logger.verbose("Save item button clicked")
selItem = self._getSelectedItem() selItem = self._getSelectedItem()
iRow = self.listBox.row(selItem) iRow = self.listBox.row(selItem)
@@ -427,6 +439,8 @@ class GuiProjectEditStatus(QWidget):
return return
def _addItem(self, iName, iCol, oName, nUse): def _addItem(self, iName, iCol, oName, nUse):
"""Add a status item to the list.
"""
newIcon = QPixmap(self.iPx, self.iPx) newIcon = QPixmap(self.iPx, self.iPx)
newIcon.fill(QColor(*iCol)) newIcon.fill(QColor(*iCol))
newItem = QListWidgetItem() newItem = QListWidgetItem()
@@ -439,11 +453,14 @@ class GuiProjectEditStatus(QWidget):
return newItem return newItem
def _selectedItem(self): def _selectedItem(self):
"""Extract the info of a selected item and populate the settings
boxes and button.
"""
logger.verbose("Item selected") logger.verbose("Item selected")
selItem = self._getSelectedItem() selItem = self._getSelectedItem()
if selItem is not None: if selItem is not None:
selIdx = selItem.data(Qt.UserRole) selIdx = selItem.data(Qt.UserRole)
selVal = self.colData[selIdx] selVal = self.colData[selIdx]
self.selColour = QColor(selVal[1], selVal[2], selVal[3]) self.selColour = QColor(selVal[1], selVal[2], selVal[3])
newIcon = QPixmap(self.iPx, self.iPx) newIcon = QPixmap(self.iPx, self.iPx)
newIcon.fill(self.selColour) newIcon.fill(self.selColour)
@@ -459,6 +476,8 @@ class GuiProjectEditStatus(QWidget):
## ##
def _getSelectedItem(self): def _getSelectedItem(self):
"""Get the currently selected item.
"""
selItem = self.listBox.selectedItems() selItem = self.listBox.selectedItems()
if len(selItem) == 0: if len(selItem) == 0:
return None return None
@@ -467,6 +486,8 @@ class GuiProjectEditStatus(QWidget):
return None return None
def _rowsMoved(self): def _rowsMoved(self):
"""A row has been moved, so sett the changed flag.
"""
logger.verbose("A drag move event occurred") logger.verbose("A drag move event occurred")
self.colChanged = True self.colChanged = True
return return
@@ -506,9 +527,9 @@ class GuiProjectEditReplace(QWidget):
self.editKey = QLineEdit() self.editKey = QLineEdit()
self.editValue = QLineEdit() self.editValue = QLineEdit()
self.saveButton = QPushButton(self.theTheme.getIcon("done"),"") self.saveButton = QPushButton(self.theTheme.getIcon("done"), "")
self.addButton = QPushButton(self.theTheme.getIcon("add"),"") self.addButton = QPushButton(self.theTheme.getIcon("add"), "")
self.delButton = QPushButton(self.theTheme.getIcon("remove"),"") self.delButton = QPushButton(self.theTheme.getIcon("remove"), "")
self.saveButton.setToolTip("Save entry") self.saveButton.setToolTip("Save entry")
self.addButton.setToolTip("Add new entry") self.addButton.setToolTip("Add new entry")
self.delButton.setToolTip("Delete selected entry") self.delButton.setToolTip("Delete selected entry")
@@ -536,11 +557,13 @@ class GuiProjectEditReplace(QWidget):
return return
def getNewList(self): def getNewList(self):
"""Extract the list from the widget.
"""
newList = {} newList = {}
for n in range(self.listBox.topLevelItemCount()): for n in range(self.listBox.topLevelItemCount()):
tItem = self.listBox.topLevelItem(n) tItem = self.listBox.topLevelItem(n)
aKey = self._stripNotAllowed(tItem.text(0)) aKey = self._stripNotAllowed(tItem.text(0))
aVal = tItem.text(1) aVal = tItem.text(1)
if len(aKey) > 0: if len(aKey) > 0:
newList[aKey] = aVal newList[aKey] = aVal
return newList return newList
@@ -550,6 +573,9 @@ class GuiProjectEditReplace(QWidget):
## ##
def _selectedItem(self): def _selectedItem(self):
"""Extract the details from the selected item and populate the
edit form.
"""
selItem = self._getSelectedItem() selItem = self._getSelectedItem()
if selItem is None: if selItem is None:
return False return False
@@ -564,7 +590,8 @@ class GuiProjectEditReplace(QWidget):
return True return True
def _saveEntry(self): def _saveEntry(self):
"""Save the form data into the list widget.
"""
selItem = self._getSelectedItem() selItem = self._getSelectedItem()
if selItem is None: if selItem is None:
return False return False
@@ -586,6 +613,8 @@ class GuiProjectEditReplace(QWidget):
return return
def _addEntry(self): def _addEntry(self):
"""Add a new list entry.
"""
saveKey = "<keyword%d>" % (self.listBox.topLevelItemCount() + 1) saveKey = "<keyword%d>" % (self.listBox.topLevelItemCount() + 1)
newVal = "" newVal = ""
newItem = QTreeWidgetItem([saveKey, newVal]) newItem = QTreeWidgetItem([saveKey, newVal])
@@ -593,6 +622,8 @@ class GuiProjectEditReplace(QWidget):
return True return True
def _delEntry(self): def _delEntry(self):
"""Delete the selected entry.
"""
selItem = self._getSelectedItem() selItem = self._getSelectedItem()
if selItem is None: if selItem is None:
return False return False
@@ -601,12 +632,16 @@ class GuiProjectEditReplace(QWidget):
return True return True
def _getSelectedItem(self): def _getSelectedItem(self):
"""Extract the currently selected item.
"""
selItem = self.listBox.selectedItems() selItem = self.listBox.selectedItems()
if len(selItem) == 0: if len(selItem) == 0:
return None return None
return selItem[0] return selItem[0]
def _stripNotAllowed(self, theKey): def _stripNotAllowed(self, theKey):
"""Clean up the replace key string.
"""
retKey = "" retKey = ""
for c in theKey: for c in theKey:
if c.isalnum(): if c.isalnum():
+30 -4
View File
@@ -30,15 +30,15 @@ import logging
import nw import nw
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont, QColor, QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMessageBox, qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMessageBox,
QHeaderView, QMenu, QAction QMenu, QAction
) )
from nw.core import NWDoc from nw.core import NWDoc
from nw.constants import ( from nw.constants import (
nwLabels, nwItemType, nwItemClass, nwItemLayout, nwAlert, nwUnicode nwLabels, nwItemType, nwItemClass, nwItemLayout, nwAlert
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -90,7 +90,7 @@ class GuiProjectTree(QTreeWidget):
# for some fonts like the Ubuntu font. # for some fonts like the Ubuntu font.
treeHeader = self.header() treeHeader = self.header()
treeHeader.setStretchLastSection(True) treeHeader.setStretchLastSection(True)
treeHeader.setMinimumSectionSize(iPx+6) treeHeader.setMinimumSectionSize(iPx + 6)
# Allow Move by Drag & Drop # Allow Move by Drag & Drop
self.setDragEnabled(True) self.setDragEnabled(True)
@@ -237,6 +237,7 @@ class GuiProjectTree(QTreeWidget):
has focus. This also applies when the menu is used. has focus. This also applies when the menu is used.
""" """
if qApp.focusWidget() == self and self.theParent.hasProject: if qApp.focusWidget() == self and self.theParent.hasProject:
tHandle = self.getSelectedHandle() tHandle = self.getSelectedHandle()
tItem = self._getTreeItem(tHandle) tItem = self._getTreeItem(tHandle)
pItem = tItem.parent() pItem = tItem.parent()
@@ -248,6 +249,7 @@ class GuiProjectTree(QTreeWidget):
return False return False
cItem = self.takeTopLevelItem(tIndex) cItem = self.takeTopLevelItem(tIndex)
self.insertTopLevelItem(nIndex, cItem) self.insertTopLevelItem(nIndex, cItem)
else: else:
tIndex = pItem.indexOfChild(tItem) tIndex = pItem.indexOfChild(tItem)
nChild = pItem.childCount() nChild = pItem.childCount()
@@ -256,11 +258,14 @@ class GuiProjectTree(QTreeWidget):
return False return False
cItem = pItem.takeChild(tIndex) cItem = pItem.takeChild(tIndex)
pItem.insertChild(nIndex, cItem) pItem.insertChild(nIndex, cItem)
self.clearSelection() self.clearSelection()
cItem.setSelected(True) cItem.setSelected(True)
self._setTreeChanged(True) self._setTreeChanged(True)
else: else:
return False return False
return True return True
def saveTreeOrder(self): def saveTreeOrder(self):
@@ -516,8 +521,10 @@ class GuiProjectTree(QTreeWidget):
for i in range(pItem.childCount()): for i in range(pItem.childCount()):
pCount += int(pItem.child(i).text(self.C_COUNT)) pCount += int(pItem.child(i).text(self.C_COUNT))
pHandle = pItem.data(self.C_NAME, Qt.UserRole) pHandle = pItem.data(self.C_NAME, Qt.UserRole)
if not nDepth > 200 and pHandle != "": if not nDepth > 200 and pHandle != "":
self.propagateCount(pHandle, pCount, nDepth+1) self.propagateCount(pHandle, pCount, nDepth+1)
return return
def projectWordCount(self): def projectWordCount(self):
@@ -533,9 +540,11 @@ class GuiProjectTree(QTreeWidget):
if tItem == self.orphRoot: if tItem == self.orphRoot:
continue continue
nWords += int(tItem.text(self.C_COUNT)) nWords += int(tItem.text(self.C_COUNT))
self.theProject.setProjectWordCount(nWords) self.theProject.setProjectWordCount(nWords)
sWords = self.theProject.getSessionWordCount() sWords = self.theProject.getSessionWordCount()
self.theParent.statusBar.setStats(nWords,sWords) self.theParent.statusBar.setStats(nWords,sWords)
return return
def buildTree(self): def buildTree(self):
@@ -547,9 +556,11 @@ class GuiProjectTree(QTreeWidget):
logger.debug("Building project tree ...") logger.debug("Building project tree ...")
self.clear() self.clear()
iCount = 0 iCount = 0
for nwItem in self.theProject.getProjectItems(): for nwItem in self.theProject.getProjectItems():
iCount += 1 iCount += 1
self._addTreeItem(nwItem) self._addTreeItem(nwItem)
logger.debug("%d items added to project tree" % iCount) logger.debug("%d items added to project tree" % iCount)
return True return True
@@ -558,10 +569,13 @@ class GuiProjectTree(QTreeWidget):
selected, return the first. selected, return the first.
""" """
selItem = self.selectedItems() selItem = self.selectedItems()
if len(selItem) == 0: if len(selItem) == 0:
return None return None
if isinstance(selItem[0], QTreeWidgetItem): if isinstance(selItem[0], QTreeWidgetItem):
return selItem[0].data(self.C_NAME, Qt.UserRole) return selItem[0].data(self.C_NAME, Qt.UserRole)
return None return None
def getSelectedHandles(self): def getSelectedHandles(self):
@@ -572,6 +586,7 @@ class GuiProjectTree(QTreeWidget):
for n in range(len(selItems)): for n in range(len(selItems)):
if isinstance(selItems[n], QTreeWidgetItem): if isinstance(selItems[n], QTreeWidgetItem):
selHandles.append(selItems[n].data(self.C_NAME, Qt.UserRole)) selHandles.append(selItems[n].data(self.C_NAME, Qt.UserRole))
return selHandles return selHandles
def setSelectedHandle(self, tHandle, doScroll=False): def setSelectedHandle(self, tHandle, doScroll=False):
@@ -580,12 +595,14 @@ class GuiProjectTree(QTreeWidget):
if tHandle in self.theMap: if tHandle in self.theMap:
self.clearSelection() self.clearSelection()
self.theMap[tHandle].setSelected(True) self.theMap[tHandle].setSelected(True)
selItems = self.selectedIndexes() selItems = self.selectedIndexes()
if selItems and doScroll: if selItems and doScroll:
self.scrollTo( self.scrollTo(
selItems[0], QAbstractItemView.PositionAtCenter selItems[0], QAbstractItemView.PositionAtCenter
) )
return True return True
return False return False
## ##
@@ -601,9 +618,11 @@ class GuiProjectTree(QTreeWidget):
tHandle = selItem.data(self.C_NAME, Qt.UserRole) tHandle = selItem.data(self.C_NAME, Qt.UserRole)
tItem = self.theProject.projTree[tHandle] tItem = self.theProject.projTree[tHandle]
self.setSelectedHandle(tHandle) # Just to be safe self.setSelectedHandle(tHandle) # Just to be safe
if self.ctxMenu.filterActions(tItem): if self.ctxMenu.filterActions(tItem):
# Only open menu if any actions remain after filter # Only open menu if any actions remain after filter
self.ctxMenu.exec_(self.viewport().mapToGlobal(clickPos)) self.ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
return return
## ##
@@ -615,9 +634,11 @@ class GuiProjectTree(QTreeWidget):
mouse in a blank area of the tree view. mouse in a blank area of the tree view.
""" """
QTreeWidget.mousePressEvent(self, theEvent) QTreeWidget.mousePressEvent(self, theEvent)
selItem = self.indexAt(theEvent.pos()) selItem = self.indexAt(theEvent.pos())
if not selItem.isValid(): if not selItem.isValid():
self.clearSelection() self.clearSelection()
return return
def dropEvent(self, theEvent): def dropEvent(self, theEvent):
@@ -766,6 +787,7 @@ class GuiProjectTree(QTreeWidget):
trashHandle = self.theProject.trashFolder() trashHandle = self.theProject.trashFolder()
if trashHandle is None: if trashHandle is None:
return None return None
trItem = self._getTreeItem(trashHandle) trItem = self._getTreeItem(trashHandle)
if trItem is None: if trItem is None:
trItem = self._addTreeItem( trItem = self._addTreeItem(
@@ -773,6 +795,7 @@ class GuiProjectTree(QTreeWidget):
) )
trItem.setExpanded(True) trItem.setExpanded(True)
self._setTreeChanged(True) self._setTreeChanged(True)
return trItem return trItem
def _addOrphanedRoot(self): def _addOrphanedRoot(self):
@@ -790,6 +813,7 @@ class GuiProjectTree(QTreeWidget):
newItem.setExpanded(True) newItem.setExpanded(True)
newItem.setData(self.C_NAME, Qt.UserRole, "") newItem.setData(self.C_NAME, Qt.UserRole, "")
newItem.setIcon(self.C_NAME, self.theTheme.getIcon("proj_orphan")) newItem.setIcon(self.C_NAME, self.theTheme.getIcon("proj_orphan"))
return return
def _cleanOrphanedRoot(self): def _cleanOrphanedRoot(self):
@@ -834,10 +858,12 @@ class GuiProjectTree(QTreeWidget):
if trItemP is None: if trItemP is None:
logger.error("Failed to find new parent item of %s" % tHandle) logger.error("Failed to find new parent item of %s" % tHandle)
return return
pHandle = trItemP.data(self.C_NAME, Qt.UserRole) pHandle = trItemP.data(self.C_NAME, Qt.UserRole)
nwItemS.setParent(pHandle) nwItemS.setParent(pHandle)
self.setTreeItemValues(tHandle) self.setTreeItemValues(tHandle)
self._setTreeChanged(True) self._setTreeChanged(True)
return return
def _setTreeChanged(self, theState): def _setTreeChanged(self, theState):
+3 -3
View File
@@ -30,8 +30,8 @@ import nw
from time import time from time import time
from PyQt5.QtCore import Qt, QTimer from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QColor, QPixmap, QFont, QPainter from PyQt5.QtGui import QColor, QPainter
from PyQt5.QtWidgets import qApp, QStatusBar, QLabel, QAbstractButton from PyQt5.QtWidgets import qApp, QStatusBar, QLabel, QAbstractButton
from nw.core import NWSpellCheck from nw.core import NWSpellCheck
@@ -264,7 +264,7 @@ class StatusLED(QAbstractButton):
qPaint.setPen(qPalette.dark().color()) qPaint.setPen(qPalette.dark().color())
qPaint.setBrush(self._theCol) qPaint.setBrush(self._theCol)
qPaint.setOpacity(1.0) qPaint.setOpacity(1.0)
qPaint.drawEllipse(1, 1, self.width()-2, self.height()-2) qPaint.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
return return
# END Class StatusLED # END Class StatusLED
+56 -53
View File
@@ -77,11 +77,11 @@ class GuiTheme:
self.themeLicenseUrl = "" self.themeLicenseUrl = ""
## GUI ## GUI
self.treeWCount = [ 0, 0, 0] self.treeWCount = [ 0, 0, 0]
self.statNone = [120,120,120] self.statNone = [120, 120, 120]
self.statUnsaved = [120,120, 40] self.statUnsaved = [120, 120, 40]
self.statSaved = [ 40,120, 0] self.statSaved = [ 40, 120, 0]
self.helpText = [ 0, 0, 0] self.helpText = [ 0, 0, 0]
# Loaded Syntax Settings # Loaded Syntax Settings
@@ -95,22 +95,22 @@ class GuiTheme:
self.syntaxLicenseUrl = "" self.syntaxLicenseUrl = ""
## Colours ## Colours
self.colBack = [255,255,255] self.colBack = [255, 255, 255]
self.colText = [ 0, 0, 0] self.colText = [ 0, 0, 0]
self.colLink = [ 0, 0, 0] self.colLink = [ 0, 0, 0]
self.colHead = [ 0, 0, 0] self.colHead = [ 0, 0, 0]
self.colHeadH = [ 0, 0, 0] self.colHeadH = [ 0, 0, 0]
self.colEmph = [ 0, 0, 0] self.colEmph = [ 0, 0, 0]
self.colDialN = [ 0, 0, 0] self.colDialN = [ 0, 0, 0]
self.colDialD = [ 0, 0, 0] self.colDialD = [ 0, 0, 0]
self.colDialS = [ 0, 0, 0] self.colDialS = [ 0, 0, 0]
self.colComm = [ 0, 0, 0] self.colComm = [ 0, 0, 0]
self.colKey = [ 0, 0, 0] self.colKey = [ 0, 0, 0]
self.colVal = [ 0, 0, 0] self.colVal = [ 0, 0, 0]
self.colSpell = [ 0, 0, 0] self.colSpell = [ 0, 0, 0]
self.colTagErr = [ 0, 0, 0] self.colTagErr = [ 0, 0, 0]
self.colRepTag = [ 0, 0, 0] self.colRepTag = [ 0, 0, 0]
self.colMod = [ 0, 0, 0] self.colMod = [ 0, 0, 0]
# Changeable Settings # Changeable Settings
self.guiTheme = None self.guiTheme = None
@@ -144,9 +144,9 @@ class GuiTheme:
qMetric = QFontMetrics(self.guiFont) qMetric = QFontMetrics(self.guiFont)
self.fontPointSize = self.guiFont.pointSizeF() self.fontPointSize = self.guiFont.pointSizeF()
self.fontPixelSize = int(round(qMetric.height())) self.fontPixelSize = int(round(qMetric.height()))
self.baseIconSize = int(round(qMetric.ascent())) self.baseIconSize = int(round(qMetric.ascent()))
self.textNHeight = qMetric.boundingRect("N").height() self.textNHeight = qMetric.boundingRect("N").height()
self.textNWidth = qMetric.boundingRect("N").width() self.textNWidth= qMetric.boundingRect("N").width()
logger.verbose("GUI Font Family: %s" % self.guiFont.family()) logger.verbose("GUI Font Family: %s" % self.guiFont.family())
logger.verbose("GUI Font Point Size: %.2f" % self.fontPointSize) logger.verbose("GUI Font Point Size: %.2f" % self.fontPointSize)
@@ -223,10 +223,10 @@ class GuiTheme:
self.guiTheme = self.mainConf.guiTheme self.guiTheme = self.mainConf.guiTheme
self.guiSyntax = self.mainConf.guiSyntax self.guiSyntax = self.mainConf.guiSyntax
self.themeRoot = self.mainConf.themeRoot self.themeRoot = self.mainConf.themeRoot
self.themePath = path.join(self.mainConf.themeRoot,self.guiPath,self.guiTheme) self.themePath = path.join(self.mainConf.themeRoot, self.guiPath, self.guiTheme)
self.syntaxFile = path.join(self.themeRoot,self.syntaxPath,self.guiSyntax+".conf") self.syntaxFile = path.join(self.themeRoot, self.syntaxPath, self.guiSyntax+".conf")
self.confFile = path.join(self.themePath,self.confName) self.confFile = path.join(self.themePath, self.confName)
self.cssFile = path.join(self.themePath,self.cssName) self.cssFile = path.join(self.themePath, self.cssName)
self.loadTheme() self.loadTheme()
self.loadSyntax() self.loadSyntax()
@@ -256,7 +256,7 @@ class GuiTheme:
cssData = "" cssData = ""
try: try:
if path.isfile(self.cssFile): if path.isfile(self.cssFile):
with open(self.cssFile,mode="r",encoding="utf8") as inFile: with open(self.cssFile, mode="r", encoding="utf8") as inFile:
cssData = inFile.read() cssData = inFile.read()
except Exception as e: except Exception as e:
logger.error("Could not load theme css file") logger.error("Could not load theme css file")
@@ -329,13 +329,13 @@ class GuiTheme:
## Main ## Main
cnfSec = "Main" cnfSec = "Main"
if confParser.has_section(cnfSec): if confParser.has_section(cnfSec):
self.syntaxName = self._parseLine( confParser, cnfSec, "name", "") self.syntaxName = self._parseLine(confParser, cnfSec, "name", "")
self.syntaxDescription = self._parseLine( confParser, cnfSec, "description", "") self.syntaxDescription = self._parseLine(confParser, cnfSec, "description", "")
self.syntaxAuthor = self._parseLine( confParser, cnfSec, "author", "") self.syntaxAuthor = self._parseLine(confParser, cnfSec, "author", "")
self.syntaxCredit = self._parseLine( confParser, cnfSec, "credit", "") self.syntaxCredit = self._parseLine(confParser, cnfSec, "credit", "")
self.syntaxUrl = self._parseLine( confParser, cnfSec, "url", "") self.syntaxUrl = self._parseLine(confParser, cnfSec, "url", "")
self.syntaxLicense = self._parseLine( confParser, cnfSec, "license", "") self.syntaxLicense = self._parseLine(confParser, cnfSec, "license", "")
self.syntaxLicenseUrl = self._parseLine( confParser, cnfSec, "licenseurl", "") self.syntaxLicenseUrl = self._parseLine(confParser, cnfSec, "licenseurl", "")
## Syntax ## Syntax
cnfSec = "Syntax" cnfSec = "Syntax"
@@ -376,7 +376,7 @@ class GuiTheme:
confParser.read_file(inFile) confParser.read_file(inFile)
except Exception as e: except Exception as e:
self.theParent.makeAlert( self.theParent.makeAlert(
["Could not load theme config file.",str(e)], nwAlert.ERROR ["Could not load theme config file.", str(e)], nwAlert.ERROR
) )
continue continue
themeName = "" themeName = ""
@@ -409,7 +409,7 @@ class GuiTheme:
confParser.read_file(inFile) confParser.read_file(inFile)
except Exception as e: except Exception as e:
self.theParent.makeAlert( self.theParent.makeAlert(
["Could not load syntax file.",str(e)], nwAlert.ERROR ["Could not load syntax file.", str(e)], nwAlert.ERROR
) )
return [] return []
syntaxName = "" syntaxName = ""
@@ -429,8 +429,10 @@ class GuiTheme:
## ##
def _loadColour(self, confParser, cnfSec, cnfName): def _loadColour(self, confParser, cnfSec, cnfName):
"""Load a colour value from a config string.
"""
if confParser.has_option(cnfSec,cnfName): if confParser.has_option(cnfSec,cnfName):
inData = confParser.get(cnfSec,cnfName).split(",") inData = confParser.get(cnfSec,cnfName).split(",")
outData = [] outData = []
try: try:
outData.append(int(inData[0])) outData.append(int(inData[0]))
@@ -438,16 +440,18 @@ class GuiTheme:
outData.append(int(inData[2])) outData.append(int(inData[2]))
except: except:
logger.error("Could not load theme colours for '%s' from config file" % cnfName) logger.error("Could not load theme colours for '%s' from config file" % cnfName)
outData = [0,0,0] outData = [0, 0, 0]
else: else:
logger.warning("Could not find theme colours for '%s' in config file" % cnfName) logger.warning("Could not find theme colours for '%s' in config file" % cnfName)
outData = [0,0,0] outData = [0, 0, 0]
return outData return outData
def _setPalette(self, confParser, cnfSec, cnfName, paletteVal): def _setPalette(self, confParser, cnfSec, cnfName, paletteVal):
"""Set a palette colour value from a config string.
"""
readCol = [] readCol = []
if confParser.has_option(cnfSec,cnfName): if confParser.has_option(cnfSec,cnfName):
inData = confParser.get(cnfSec,cnfName).split(",") inData = confParser.get(cnfSec,cnfName).split(",")
try: try:
readCol.append(int(inData[0])) readCol.append(int(inData[0]))
readCol.append(int(inData[1])) readCol.append(int(inData[1]))
@@ -547,8 +551,8 @@ class GuiIcons:
"reference" : (None, None), "reference" : (None, None),
## Switches ## Switches
"sticky-on" : (None, None), "sticky-on" : (None, None),
"sticky-off" : (None, None), "sticky-off" : (None, None),
} }
DECO_MAP = { DECO_MAP = {
@@ -615,13 +619,13 @@ class GuiIcons:
## Main ## Main
cnfSec = "Main" cnfSec = "Main"
if confParser.has_section(cnfSec): if confParser.has_section(cnfSec):
self.themeName = self._parseLine( confParser, cnfSec, "name", "") self.themeName = self._parseLine(confParser, cnfSec, "name", "")
self.themeDescription = self._parseLine( confParser, cnfSec, "description", "") self.themeDescription = self._parseLine(confParser, cnfSec, "description", "")
self.themeAuthor = self._parseLine( confParser, cnfSec, "author", "") self.themeAuthor = self._parseLine(confParser, cnfSec, "author", "")
self.themeCredit = self._parseLine( confParser, cnfSec, "credit", "") self.themeCredit = self._parseLine(confParser, cnfSec, "credit", "")
self.themeUrl = self._parseLine( confParser, cnfSec, "url", "") self.themeUrl = self._parseLine(confParser, cnfSec, "url", "")
self.themeLicense = self._parseLine( confParser, cnfSec, "license", "") self.themeLicense = self._parseLine(confParser, cnfSec, "license", "")
self.themeLicenseUrl = self._parseLine( confParser, cnfSec, "licenseurl", "") self.themeLicenseUrl = self._parseLine(confParser, cnfSec, "licenseurl", "")
## Palette ## Palette
cnfSec = "Map" cnfSec = "Map"
@@ -705,7 +709,7 @@ class GuiIcons:
confParser.read_file(inFile) confParser.read_file(inFile)
except Exception as e: except Exception as e:
self.theParent.makeAlert( self.theParent.makeAlert(
["Could not load theme config file.",str(e)], nwAlert.ERROR ["Could not load theme config file.", str(e)], nwAlert.ERROR
) )
continue continue
themeName = "" themeName = ""
@@ -730,7 +734,6 @@ class GuiIcons:
an icon exists. Prefer svg files over png files. Always returns an icon exists. Prefer svg files over png files. Always returns
a QIcon. a QIcon.
""" """
if iconKey not in self.ICON_MAP: if iconKey not in self.ICON_MAP:
logger.error("Requested unknown icon name '%s'" % iconKey) logger.error("Requested unknown icon name '%s'" % iconKey)
return QIcon() return QIcon()
+1 -1
View File
@@ -90,7 +90,7 @@ class GuiWritingStats(QDialog):
) )
self.listBox = QTreeWidget() self.listBox = QTreeWidget()
self.listBox.setHeaderLabels(["Session Start","Length","Words","Histogram"]) self.listBox.setHeaderLabels(["Session Start", "Length", "Words", "Histogram"])
self.listBox.setIndentation(0) self.listBox.setIndentation(0)
self.listBox.setColumnWidth(self.C_TIME, wCol0) self.listBox.setColumnWidth(self.C_TIME, wCol0)
self.listBox.setColumnWidth(self.C_LENGTH, wCol1) self.listBox.setColumnWidth(self.C_LENGTH, wCol1)
+71 -47
View File
@@ -46,7 +46,7 @@ from nw.gui import (
GuiProjectSettings, GuiProjectTree, GuiWritingStats, GuiAbout GuiProjectSettings, GuiProjectTree, GuiWritingStats, GuiAbout
) )
from nw.core import NWProject, NWDoc, NWIndex from nw.core import NWProject, NWDoc, NWIndex
from nw.constants import nwFiles, nwItemType, nwAlert from nw.constants import nwItemType, nwAlert
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -128,7 +128,7 @@ class GuiMain(QMainWindow):
self.tabWidget = QTabWidget() self.tabWidget = QTabWidget()
self.tabWidget.setTabPosition(QTabWidget.East) self.tabWidget.setTabPosition(QTabWidget.East)
self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;}") self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;}")
self.tabWidget.addTab(self.splitDocs, "Editor") self.tabWidget.addTab(self.splitDocs, "Editor")
self.tabWidget.addTab(self.splitOutline, "Outline") self.tabWidget.addTab(self.splitOutline, "Outline")
self.tabWidget.currentChanged.connect(self._mainTabChanged) self.tabWidget.currentChanged.connect(self._mainTabChanged)
@@ -139,8 +139,6 @@ class GuiMain(QMainWindow):
self.splitMain.addWidget(self.tabWidget) self.splitMain.addWidget(self.tabWidget)
self.splitMain.setSizes(self.mainConf.getMainPanePos()) self.splitMain.setSizes(self.mainConf.getMainPanePos())
self.setCentralWidget(self.splitMain)
self.idxTree = self.splitMain.indexOf(self.treePane) self.idxTree = self.splitMain.indexOf(self.treePane)
self.idxMain = self.splitMain.indexOf(self.tabWidget) self.idxMain = self.splitMain.indexOf(self.tabWidget)
self.idxEditor = self.splitDocs.indexOf(self.docEditor) self.idxEditor = self.splitDocs.indexOf(self.docEditor)
@@ -167,8 +165,8 @@ class GuiMain(QMainWindow):
# Set Main Window Elements # Set Main Window Elements
self.setMenuBar(self.mainMenu) self.setMenuBar(self.mainMenu)
self.setCentralWidget(self.splitMain)
self.setStatusBar(self.statusBar) self.setStatusBar(self.statusBar)
self.statusBar.setStatus("Ready")
# Finalise Initialisation # Finalise Initialisation
########################## ##########################
@@ -222,6 +220,7 @@ class GuiMain(QMainWindow):
self.manageProjects() self.manageProjects()
logger.debug("novelWriter is ready ...") logger.debug("novelWriter is ready ...")
self.statusBar.setStatus("novelWriter is ready ...")
return return
@@ -348,9 +347,7 @@ class GuiMain(QMainWindow):
return saveOK return saveOK
def openProject(self, projFile): def openProject(self, projFile):
"""Open a project. The parameter projFile is passed from the """Open a project from a projFile path.
open recent projects menu, and must be set to be forwarded to
the project class. Otherwise, we just return.
""" """
if projFile is None: if projFile is None:
return False return False
@@ -365,43 +362,47 @@ class GuiMain(QMainWindow):
# Try to open the project # Try to open the project
if not self.theProject.openProject(projFile): if not self.theProject.openProject(projFile):
if self.theProject.lockedBy is not None: # The project open failed.
if self.mainConf.showGUI:
try:
lockDetails = (
"<br><br>The project was locked by the computer "
"'%s' (%s %s), last active on %s"
) % (
self.theProject.lockedBy[0],
self.theProject.lockedBy[1],
self.theProject.lockedBy[2],
datetime.fromtimestamp(
int(self.theProject.lockedBy[3])
).strftime("%x %X")
)
except:
lockDetails = ""
msgBox = QMessageBox() if self.theProject.lockedBy is None:
msgRes = msgBox.warning( # The project is not locked, so failed for some other
self, "Project Locked", ( # reason handled by the project class.
"The project is already open by another instance of novelWriter, and "
"is therefore locked. Override lock and continue anyway?<br><br>"
"Note: If the program or the computer previously crashed, the lock "
"can safely be overridden. If, however, another instance of "
"novelWriter has the project open, overriding the lock may corrupt "
"the project, and is not recommended.%s"
) % lockDetails,
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
)
if msgRes == QMessageBox.Yes:
if not self.theProject.openProject(projFile, overrideLock=True):
return False
else:
return False
else:
return False return False
if self.mainConf.showGUI:
try:
lockDetails = (
"<br><br>The project was locked by the computer "
"'%s' (%s %s), last active on %s"
) % (
self.theProject.lockedBy[0],
self.theProject.lockedBy[1],
self.theProject.lockedBy[2],
datetime.fromtimestamp(
int(self.theProject.lockedBy[3])
).strftime("%x %X")
)
except:
lockDetails = ""
msgBox = QMessageBox()
msgRes = msgBox.warning(
self, "Project Locked", (
"The project is already open by another instance of novelWriter, and "
"is therefore locked. Override lock and continue anyway?<br><br>"
"Note: If the program or the computer previously crashed, the lock "
"can safely be overridden. If, however, another instance of "
"novelWriter has the project open, overriding the lock may corrupt "
"the project, and is not recommended.%s"
) % lockDetails,
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
)
if msgRes == QMessageBox.Yes:
if not self.theProject.openProject(projFile, overrideLock=True):
return False
else:
return False
# Project is loaded # Project is loaded
self.hasProject = True self.hasProject = True
@@ -570,7 +571,7 @@ class GuiMain(QMainWindow):
dlgOpt = QFileDialog.Options() dlgOpt = QFileDialog.Options()
dlgOpt |= QFileDialog.DontUseNativeDialog dlgOpt |= QFileDialog.DontUseNativeDialog
inPath = QFileDialog.getOpenFileName( inPath = QFileDialog.getOpenFileName(
self,"Import File",lastPath,options=dlgOpt,filter=";;".join(extFilter) self, "Import File", lastPath, options=dlgOpt, filter=";;".join(extFilter)
) )
if inPath: if inPath:
loadFile = inPath[0] loadFile = inPath[0]
@@ -582,7 +583,7 @@ class GuiMain(QMainWindow):
theText = None theText = None
try: try:
with open(loadFile,mode="rt",encoding="utf8") as inFile: with open(loadFile, mode="rt", encoding="utf8") as inFile:
theText = inFile.read() theText = inFile.read()
self.mainConf.setLastPath(loadFile) self.mainConf.setLastPath(loadFile)
except Exception as e: except Exception as e:
@@ -602,7 +603,7 @@ class GuiMain(QMainWindow):
if not self.docEditor.isEmpty(): if not self.docEditor.isEmpty():
if self.mainConf.showGUI: if self.mainConf.showGUI:
msgBox = QMessageBox() msgBox = QMessageBox()
msgRes = msgBox.question(self, "Import Document",( msgRes = msgBox.question(self, "Import Document", (
"Importing the file will overwrite the current content of the document. " "Importing the file will overwrite the current content of the document. "
"Do you want to proceed?" "Do you want to proceed?"
)) ))
@@ -917,6 +918,8 @@ class GuiMain(QMainWindow):
return True return True
def setFocus(self, paneNo): def setFocus(self, paneNo):
"""Switch focus to one of the three main gUi panes.
"""
if paneNo == 1: if paneNo == 1:
self.treeView.setFocus() self.treeView.setFocus()
elif paneNo == 2: elif paneNo == 2:
@@ -926,6 +929,8 @@ class GuiMain(QMainWindow):
return return
def closeDocEditor(self): def closeDocEditor(self):
"""Close the document edit panel. This does not hide the editor.
"""
self.closeDocument() self.closeDocument()
self.theProject.setLastEdited(None) self.theProject.setLastEdited(None)
return return
@@ -1059,6 +1064,8 @@ class GuiMain(QMainWindow):
return True return True
def _setWindowTitle(self, projName=None): def _setWindowTitle(self, projName=None):
"""Set the window title and add the project's working title.
"""
winTitle = self.mainConf.appName winTitle = self.mainConf.appName
if projName is not None: if projName is not None:
winTitle += " - %s" % projName winTitle += " - %s" % projName
@@ -1066,19 +1073,30 @@ class GuiMain(QMainWindow):
return True return True
def _autoSaveProject(self): def _autoSaveProject(self):
if (self.hasProject and self.theProject.projChanged and """Triggered by the auto-save project timer to save the project.
self.theProject.projPath is not None): """
doSave = self.hasProject
doSave &= self.theProject.projChanged
doSave &= self.theProject.projPath is not None
if doSave:
logger.debug("Autosaving project") logger.debug("Autosaving project")
self.saveProject(autoSave=True) self.saveProject(autoSave=True)
return return
def _autoSaveDocument(self): def _autoSaveDocument(self):
"""Triggered by the auto-save document timer to save the
document.
"""
if self.hasProject and self.docEditor.docChanged: if self.hasProject and self.docEditor.docChanged:
logger.debug("Autosaving document") logger.debug("Autosaving document")
self.saveDocument() self.saveDocument()
return return
def _makeStatusIcons(self): def _makeStatusIcons(self):
"""Generate all the item status icons based on project settings.
"""
self.statusIcons = {} self.statusIcons = {}
iPx = self.mainConf.pxInt(32) iPx = self.mainConf.pxInt(32)
for sLabel, sCol, _ in self.theProject.statusItems: for sLabel, sCol, _ in self.theProject.statusItems:
@@ -1088,6 +1106,9 @@ class GuiMain(QMainWindow):
return return
def _makeImportIcons(self): def _makeImportIcons(self):
"""Generate all the item importance icons based on project
settings.
"""
self.importIcons = {} self.importIcons = {}
iPx = self.mainConf.pxInt(32) iPx = self.mainConf.pxInt(32)
for sLabel, sCol, _ in self.theProject.importItems: for sLabel, sCol, _ in self.theProject.importItems:
@@ -1101,6 +1122,9 @@ class GuiMain(QMainWindow):
## ##
def closeEvent(self, theEvent): def closeEvent(self, theEvent):
"""Capture the closing event of the GUI and call the close
function to handle all the close process steps.
"""
if self.closeMain(): if self.closeMain():
theEvent.accept() theEvent.accept()
else: else: