From 540aa7fcbc0c7700c9e785354d638256345dee5d Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 19 May 2019 19:03:59 +0200 Subject: [PATCH] Moved item status recrod keeping into a separate iterable class --- nw/enum.py | 9 ++++ nw/gui/docdetails.py | 13 +----- nw/gui/doctree.py | 13 ++---- nw/gui/itemeditor.py | 8 ++-- nw/gui/projecteditor.py | 59 ++++++++++++++++-------- nw/gui/winmain.py | 26 ++++------- nw/project/item.py | 12 +++-- nw/project/project.py | 61 +++++++++++++------------ nw/project/status.py | 78 ++++++++++++++++++++++++++++++++ sample/sampleNovel/nwProject.nwx | 30 ++++++------ 10 files changed, 200 insertions(+), 109 deletions(-) create mode 100644 nw/project/status.py diff --git a/nw/enum.py b/nw/enum.py index 61540882..5bbdb311 100644 --- a/nw/enum.py +++ b/nw/enum.py @@ -76,3 +76,12 @@ class nwAlert(Enum): BUG = 3 # END Enum nwAlert + +class nwChanged(Enum): + + NONE = 0 + DELETE = 1 + NEW = 2 + IGNORE = 3 + +# END Enum nwAlert diff --git a/nw/gui/docdetails.py b/nw/gui/docdetails.py index 1552640a..b1f91345 100644 --- a/nw/gui/docdetails.py +++ b/nw/gui/docdetails.py @@ -70,20 +70,9 @@ class GuiDocDetails(QFrame): if nwItem is None: colTwo = [""]*4 else: - itemStatus = nwItem.itemStatus - if nwItem.itemClass == nwItemClass.NOVEL: - if itemStatus < 0 or itemStatus >= len(self.theParent.statusLabels): - statusLabel = self.theParent.statusLabels[0] - else: - statusLabel = self.theParent.statusLabels[itemStatus] - else: - if itemStatus < 0 or itemStatus >= len(self.theParent.importLabels): - statusLabel = self.theParent.importLabels[0] - else: - statusLabel = self.theParent.importLabels[itemStatus] colTwo = [ nwItem.itemName, - statusLabel, + nwItem.itemStatus, nwLabels.CLASS_NAME[nwItem.itemClass], nwLabels.LAYOUT_NAME[nwItem.itemLayout], ] diff --git a/nw/gui/doctree.py b/nw/gui/doctree.py index 8844866c..e764709a 100644 --- a/nw/gui/doctree.py +++ b/nw/gui/doctree.py @@ -259,19 +259,12 @@ class GuiDocTree(QTreeWidget): tStatus = nwLabels.CLASS_FLAG[nwItem.itemClass] if nwItem.itemType == nwItemType.FILE: tStatus += "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout] - nStatus = nwItem.itemStatus if tClass == nwItemClass.NOVEL: - if nStatus < 0 or nStatus >= len(self.theParent.statusIcons): - flagIcon = self.theParent.statusIcons[0] - else: - flagIcon = self.theParent.statusIcons[nStatus] + flagIcon = self.theParent.statusIcons[nwItem.itemStatus] else: - if nStatus < 0 or nStatus >= len(self.theParent.importIcons): - flagIcon = self.theParent.importIcons[0] - else: - flagIcon = self.theParent.importIcons[nStatus] + flagIcon = self.theParent.importIcons[nwItem.itemStatus] - trItem.setText(self.C_NAME,tName) + trItem.setText(self.C_NAME, tName) trItem.setText(self.C_FLAGS,tStatus) trItem.setIcon(self.C_FLAGS,flagIcon) diff --git a/nw/gui/itemeditor.py b/nw/gui/itemeditor.py index 3cc48140..7939b8a5 100644 --- a/nw/gui/itemeditor.py +++ b/nw/gui/itemeditor.py @@ -55,14 +55,14 @@ class GuiItemEditor(QDialog): self.editLayout = QComboBox() if self.theItem.itemClass == nwItemClass.NOVEL: - for n in range(len(self.theParent.statusLabels)): + for sLabel, sCol in self.theProject.statusItems: self.editStatus.addItem( - self.theParent.statusIcons[n], self.theParent.statusLabels[n], n + self.theParent.statusIcons[sLabel], sLabel, sLabel ) else: - for n in range(len(self.theParent.statusLabels)): + for sLabel, sCol in self.theProject.importItems: self.editStatus.addItem( - self.theParent.importIcons[n], self.theParent.importLabels[n], n + self.theParent.importIcons[sLabel], sLabel, sLabel ) self.validLayouts = [] diff --git a/nw/gui/projecteditor.py b/nw/gui/projecteditor.py index d4d26b6e..640cb1a6 100644 --- a/nw/gui/projecteditor.py +++ b/nw/gui/projecteditor.py @@ -13,9 +13,9 @@ import logging import nw -from os import path +from os import path -from PyQt5.QtGui import QIcon, QPixmap, QColor +from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush from PyQt5.QtSvg import QSvgWidget from PyQt5.QtWidgets import ( QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel, @@ -23,6 +23,8 @@ from PyQt5.QtWidgets import ( QColorDialog ) +from nw.enum import nwChanged + logger = logging.getLogger(__name__) class GuiProjectEditor(QDialog): @@ -45,8 +47,8 @@ class GuiProjectEditor(QDialog): self.svgGradient.setFixedWidth(80) self.tabMain = GuiProjectEditMain(self.theParent, self.theProject) - self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusCols) - self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importCols) + self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems) + self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems) self.tabWidget = QTabWidget() self.tabWidget.addTab(self.tabMain, "Settings") @@ -80,10 +82,10 @@ class GuiProjectEditor(QDialog): self.theProject.setBookTitle(bookTitle) self.theProject.setBookAuthors(bookAuthors) - statusCol = self.tabStatus.getNewList() - importCol = self.tabImport.getNewList() - self.theProject.setStatusColours(statusCol) - self.theProject.setImportColours(importCol) + statusCol, statusChange = self.tabStatus.getNewList() + importCol, importChange = self.tabImport.getNewList() + self.theProject.setStatusColours(statusCol, statusChange) + self.theProject.setImportColours(importCol, importChange) self.close() @@ -127,11 +129,12 @@ class GuiProjectEditMain(QWidget): class GuiProjectEditStatus(QWidget): - def __init__(self, theParent, colList): + def __init__(self, theParent, theStatus): QWidget.__init__(self, theParent) self.theParent = theParent - self.colList = colList.copy() + self.theStatus = theStatus + self.colNames = [] self.colChanged = False self.mainBox = QHBoxLayout() @@ -140,8 +143,9 @@ class GuiProjectEditStatus(QWidget): self.listBox = QListWidget() self.listBox.itemSelectionChanged.connect(self._selectedItem) - for iName, iR, iG, iB in self.colList: - self._addItem(iName, iR, iG, iB) + for iName, iCol in self.theStatus: + self._addItem(iName, iCol) + self.colNames.append(iName) self.editName = QLineEdit() self.newButton = QPushButton("New") @@ -153,6 +157,7 @@ class GuiProjectEditStatus(QWidget): self.colButton.setIconSize(self.colPixmap.rect().size()) self.newButton.clicked.connect(self._newItem) + self.delButton.clicked.connect(self._delItem) self.saveButton.clicked.connect(self._saveItem) self.colButton.clicked.connect(self._selectColour) @@ -181,8 +186,8 @@ class GuiProjectEditStatus(QWidget): nImg = nItem.icon().pixmap(16,16).toImage() nCol = QColor(nImg.pixel(7,7)) newList.append((nName,nCol.red(),nCol.green(),nCol.blue())) - return newList - return self.colList + return newList, self.colNames + return None, None ## # User Actions @@ -201,7 +206,25 @@ class GuiProjectEditStatus(QWidget): return def _newItem(self): - self._addItem("New Item", 0, 0, 0) + newItem = self._addItem("New Item", (0, 0, 0)) + newItem.setBackground(QBrush(QColor(0,255,0,80))) + self.colNames.append(None) + self.colChanged = True + return + + def _delItem(self): + selItem = self._getSelectedItem() + colDel = QBrush(QColor(255,0,0,80)) + colNone = QBrush(QColor(0,0,0,0)) + if selItem is not None: + sText = selItem.text() + iRow = self.listBox.row(selItem) + if sText == "** Delete **": + selItem.setBackground(colNone) + selItem.setText(self.colNames[iRow]) + else: + selItem.setBackground(colDel) + selItem.setText("** Delete **") return def _saveItem(self): @@ -213,15 +236,15 @@ class GuiProjectEditStatus(QWidget): self.colChanged = True return - def _addItem(self, iName, iR, iG, iB): + def _addItem(self, iName, iCol): logger.verbose("New item button clicked") newIcon = QPixmap(16,16) - newIcon.fill(QColor(iR,iG,iB)) + newIcon.fill(QColor(*iCol)) newItem = QListWidgetItem() newItem.setText(iName) newItem.setIcon(QIcon(newIcon)) self.listBox.addItem(newItem) - return + return newItem def _selectedItem(self): logger.verbose("Item selected") diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index 6bcea030..58324e1c 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -61,10 +61,8 @@ class GuiMain(QMainWindow): self.statusBar = GuiMainStatus(self) # Minor Gui Elements - self.statusIcons = [] - self.statusLabels = [] - self.importIcons = [] - self.importLabels = [] + self.statusIcons = [] + self.importIcons = [] # Assemble Main Window self.treePane = QFrame() @@ -397,23 +395,19 @@ class GuiMain(QMainWindow): return True def _makeStatusIcons(self): - self.statusIcons = [] - self.statusLabels = [] - for sLabel, sR, sG, sB in self.theProject.statusCols: + self.statusIcons = {} + for sLabel, sCol in self.theProject.statusItems: theIcon = QPixmap(32,32) - theIcon.fill(QColor(sR,sG,sB)) - self.statusIcons.append(QIcon(theIcon)) - self.statusLabels.append(sLabel) + theIcon.fill(QColor(*sCol)) + self.statusIcons[sLabel] = QIcon(theIcon) return def _makeImportIcons(self): - self.importIcons = [] - self.importLabels = [] - for sLabel, sR, sG, sB in self.theProject.importCols: + self.importIcons = {} + for sLabel, sCol in self.theProject.importItems: theIcon = QPixmap(32,32) - theIcon.fill(QColor(sR,sG,sB)) - self.importIcons.append(QIcon(theIcon)) - self.importLabels.append(sLabel) + theIcon.fill(QColor(*sCol)) + self.importIcons[sLabel] = QIcon(theIcon) return ## diff --git a/nw/project/item.py b/nw/project/item.py index 7ea631ac..367167c8 100644 --- a/nw/project/item.py +++ b/nw/project/item.py @@ -26,7 +26,9 @@ class NWItem(): MAX_DEPTH = 8 - def __init__(self): + def __init__(self, theProject): + + self.theProject = theProject self.itemName = "" self.itemHandle = None @@ -35,7 +37,7 @@ class NWItem(): self.itemType = nwItemType.NO_TYPE self.itemClass = nwItemClass.NO_CLASS self.itemLayout = nwItemLayout.NO_LAYOUT - self.itemStatus = 0 + self.itemStatus = None self.isExpanded = False # Document Meta Data @@ -158,8 +160,10 @@ class NWItem(): return def setStatus(self, theStatus): - theStatus = checkInt(theStatus,0) - self.itemStatus = theStatus + if self.itemClass == nwItemClass.NOVEL: + self.itemStatus = self.theProject.statusItems.checkEntry(theStatus) + else: + self.itemStatus = self.theProject.importItems.checkEntry(theStatus) return def setExpanded(self, expState): diff --git a/nw/project/project.py b/nw/project/project.py index 2236592d..360ca69b 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -13,15 +13,16 @@ import logging import nw -from os import path, mkdir, listdir -from lxml import etree -from hashlib import sha256 -from datetime import datetime -from time import time +from os import path, mkdir, listdir +from lxml import etree +from hashlib import sha256 +from datetime import datetime +from time import time -from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert -from nw.common import checkString, checkBool -from nw.project.item import NWItem +from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert +from nw.common import checkString, checkBool +from nw.project.item import NWItem +from nw.project.status import NWStatus logger = logging.getLogger(__name__) @@ -54,8 +55,8 @@ class NWProject(): # Project Settings self.spellCheck = False - self.statusCols = None - self.importCols = None + self.statusItems = NWStatus() + self.importItems = NWStatus() self.lastEdited = None self.lastViewed = None @@ -75,7 +76,7 @@ class NWProject(): if not self.checkRootUnique(rootClass): self.makeAlert("Duplicate root item detected!", nwAlert.ERROR) return None - newItem = NWItem() + newItem = NWItem(self) newItem.setName(rootName) newItem.setType(nwItemType.ROOT) newItem.setClass(rootClass) @@ -83,7 +84,7 @@ class NWProject(): return newItem.itemHandle def newFolder(self, folderName, folderClass, pHandle): - newItem = NWItem() + newItem = NWItem(self) newItem.setName(folderName) newItem.setType(nwItemType.FOLDER) newItem.setClass(folderClass) @@ -91,7 +92,7 @@ class NWProject(): return newItem.itemHandle def newFile(self, fileName, fileClass, pHandle): - newItem = NWItem() + newItem = NWItem(self) newItem.setName(fileName) newItem.setType(nwItemType.FILE) if fileClass == nwItemClass.NOVEL: @@ -103,7 +104,7 @@ class NWProject(): return newItem.itemHandle def addTrash(self): - newItem = NWItem() + newItem = NWItem(self) newItem.setName("Trash") newItem.setType(nwItemType.TRASH) newItem.setClass(nwItemClass.TRASH) @@ -144,18 +145,16 @@ class NWProject(): self.bookTitle = "" self.bookAuthors = [] self.spellCheck = False - self.statusCols = [ - ("New", 100,100,100), - ("Note", 200, 50, 0), - ("Draft", 200,150, 0), - ("Finished", 50,200, 0), - ] - self.importCols = [ - ("None", 100,100,100), - ("Minor", 200, 50, 0), - ("Major", 200,150, 0), - ("Main", 50,200, 0), - ] + self.statusItems = NWStatus() + self.statusItems.addEntry("New", (100,100,100)) + self.statusItems.addEntry("Note", (200, 50, 0)) + self.statusItems.addEntry("Draft", (200,150, 0)) + self.statusItems.addEntry("Finished",( 50,200, 0)) + self.importItems = NWStatus() + self.importItems.addEntry("None", (100,100,100)) + self.importItems.addEntry("Minor", (200, 50, 0)) + self.importItems.addEntry("Major", (200,150, 0)) + self.importItems.addEntry("Main", ( 50,200, 0)) return @@ -228,7 +227,7 @@ class NWProject(): pHandle = itemAttrib["parent"] else: pHandle = None - nwItem = NWItem() + nwItem = NWItem(self) for xValue in xItem: nwItem.setFromTag(xValue.tag,xValue.text) self._appendItem(tHandle,pHandle,nwItem) @@ -353,11 +352,13 @@ class NWProject(): self.setProjectChanged(True) return True - def setStatusColours(self, newCols): + def setStatusColours(self, newCols, colChanged): + print(newCols,colChanged) self.setProjectChanged(True) return - def setImportColours(self, newCols): + def setImportColours(self, newCols, colChanged): + print(newCols,colChanged) self.setProjectChanged(True) return @@ -500,7 +501,7 @@ class NWProject(): nOrph = 0 for oHandle in orphanFiles: nOrph += 1 - orItem = NWItem() + orItem = NWItem(self) orItem.setName("Orphaned File %d" % nOrph) orItem.setType(nwItemType.FILE) orItem.setClass(nwItemClass.NO_CLASS) diff --git a/nw/project/status.py b/nw/project/status.py new file mode 100644 index 00000000..7197e1da --- /dev/null +++ b/nw/project/status.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +"""novelWriter Item Status + + novelWriter – Item Status +=========================== + Class holding the project's item statuses + + File History: + Created: 2019-05-19 [0.1.3] + +""" + +import logging +import nw + +from nw.enum import nwItemClass +from nw.common import checkInt + +logger = logging.getLogger(__name__) + +class NWStatus(): + + def __init__(self): + self.theLabels = [] + self.theColours = [] + self.theMap = {} + self.theCount = 0 + self.theIndex = 0 + return + + def addEntry(self, theLabel, theColours): + theLabel = theLabel.strip() + if self.lookupEntry(theLabel) is None: + self.theLabels.append(theLabel) + self.theColours.append(theColours) + self.theMap[theLabel] = self.theCount + self.theCount += 1 + return True + + def lookupEntry(self, theLabel): + theLabel = theLabel.strip() + if theLabel in self.theMap.keys(): + return self.theMap[theLabel] + return None + + def checkEntry(self, theStatus): + theStatus = theStatus.strip() + if isinstance(theStatus, str): + if self.lookupEntry(theStatus) is not None: + return theStatus + theStatus = checkInt(theStatus, None, False) + if theStatus is None: + return None + if theStatus >= 0 and theStatus < self.theCount: + return self.theLabels[theStatus] + + ## + # Iterator Bits + ## + + def __getitem__(self, n): + if n >= 0 and n < self.theCount: + return self.theLabels[n], self.theColours[n] + return None, None + + def __iter__(self): + self.theIndex = 0 + return self + + def __next__(self): + if self.theIndex < self.theCount: + theLabel, theColour = self.__getitem__(self.theIndex) + self.theIndex += 1 + return theLabel, theColour + else: + raise StopIteration + +# END Class NWStatus diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx index 0d421f0e..89cd44e8 100644 --- a/sample/sampleNovel/nwProject.nwx +++ b/sample/sampleNovel/nwProject.nwx @@ -1,5 +1,5 @@ - + Sample Project Sample Project @@ -16,14 +16,14 @@ Novel ROOT NOVEL - 0 + New True Title Page FILE NOVEL - 2 + Draft False TITLE 23 @@ -35,14 +35,14 @@ Some Chapter FOLDER NOVEL - 1 + Note True New Scene FILE NOVEL - 2 + Draft False SCENE 2571 @@ -54,7 +54,7 @@ File With Stuff FILE NOVEL - 1 + Note False SCENE 578 @@ -66,7 +66,7 @@ New File FILE NOVEL - 0 + Note False SCENE 69 @@ -78,21 +78,21 @@ Characters ROOT CHARACTER - 0 + None True Main Characters FOLDER CHARACTER - 0 + None True John Smith FILE CHARACTER - 0 + Minor False NOTE 42 @@ -104,7 +104,7 @@ Jane Smith FILE CHARACTER - 0 + Major False NOTE 51 @@ -116,14 +116,14 @@ Locations ROOT WORLD - 0 + None True Earth FILE WORLD - 0 + None False NOTE 0 @@ -135,14 +135,14 @@ Trash TRASH TRASH - 0 + None True Orphaned File 2 FILE NO_CLASS - 0 + None False NO_LAYOUT 14