diff --git a/novelwriter/core/item.py b/novelwriter/core/item.py index 67dd836c..993b183c 100644 --- a/novelwriter/core/item.py +++ b/novelwriter/core/item.py @@ -50,6 +50,7 @@ class NWItem(): self._class = nwItemClass.NO_CLASS self._layout = nwItemLayout.NO_LAYOUT self._status = None + self._import = None self._expanded = False self._exported = True @@ -104,6 +105,10 @@ class NWItem(): def itemStatus(self): return self._status + @property + def itemImport(self): + return self._import + @property def isExpanded(self): return self._expanded @@ -159,12 +164,13 @@ class NWItem(): nameAttrib = {} nameAttrib["status"] = str(self._status) + nameAttrib["import"] = str(self._import) if self._type == nwItemType.FILE: nameAttrib["exported"] = str(self._exported) xPack = etree.SubElement(xParent, "item", attrib=itemAttrib) - self._subPack(xPack, "meta", attrib=metaAttrib) - self._subPack(xPack, "name", text=str(self._name), attrib=nameAttrib) + self._subPack(xPack, "meta", attrib=metaAttrib) + self._subPack(xPack, "name", text=str(self._name), attrib=nameAttrib) return @@ -197,11 +203,12 @@ class NWItem(): elif xValue.tag == "name": self.setName(xValue.text) self.setStatus(xValue.attrib.get("status", None)) + self.setImport(xValue.attrib.get("import", None)) self.setExported(xValue.attrib.get("exported", True)) # Legacy Format (1.3 and earlier) elif xValue.tag == "status": - self.setStatus(xValue.text) + self.setImportStatus(xValue.text) elif xValue.tag == "type": self.setType(xValue.text) elif xValue.tag == "class": @@ -268,6 +275,28 @@ class NWItem(): return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, "")) + def getImportStatus(self): + """Return the relevant importance or status label and icon for + the current item based on its class. + """ + if self._class in nwLists.CLS_NOVEL: + stName = self.theProject.statusItems.checkEntry(self._status) + stIcon = self.theProject.statusItems.getIcon(stName) + else: + stName = self.theProject.importItems.checkEntry(self._import) + stIcon = self.theProject.importItems.getIcon(stName) + return stName, stIcon + + def setImportStatus(self, theLabel): + """Update the importance or status value based on class. This is + a wrapper setter for setStatus and setImport. + """ + if self._class in nwLists.CLS_NOVEL: + self.setStatus(theLabel) + else: + self.setImport(theLabel) + return + ## # Set Item Values ## @@ -354,10 +383,14 @@ class NWItem(): """Set the item status by looking it up in the valid status items of the current project. """ - if self._class in nwLists.CLS_NOVEL: - self._status = self.theProject.statusItems.checkEntry(theStatus) - else: - self._status = self.theProject.importItems.checkEntry(theStatus) + self._status = self.theProject.statusItems.checkEntry(theStatus) + return + + def setImport(self, theImport): + """Set the item importance by looking it up in the valid import + items of the current project. + """ + self._import = self.theProject.importItems.checkEntry(theImport) return def setExpanded(self, expState): diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py index 556f6e18..ff2c2774 100644 --- a/novelwriter/core/project.py +++ b/novelwriter/core/project.py @@ -46,7 +46,7 @@ from novelwriter.common import ( checkString, checkBool, checkInt, isHandle, formatTimeStamp, makeFileNameSafe, hexToInt ) -from novelwriter.constants import trConst, nwFiles, nwLabels +from novelwriter.constants import nwLists, trConst, nwFiles, nwLabels logger = logging.getLogger(__name__) @@ -1071,7 +1071,7 @@ class NWProject(): """ replaceMap = self.statusItems.setNewEntries(newCols) for nwItem in self.projTree: - if nwItem.itemClass == nwItemClass.NOVEL: + if nwItem.itemClass in nwLists.CLS_NOVEL: if nwItem.itemStatus in replaceMap: nwItem.setStatus(replaceMap[nwItem.itemStatus]) self.setProjectChanged(True) @@ -1083,9 +1083,9 @@ class NWProject(): """ replaceMap = self.importItems.setNewEntries(newCols) for nwItem in self.projTree: - if nwItem.itemClass != nwItemClass.NOVEL: - if nwItem.itemStatus in replaceMap: - nwItem.setStatus(replaceMap[nwItem.itemStatus]) + if nwItem.itemClass not in nwLists.CLS_NOVEL: + if nwItem.itemImport in replaceMap: + nwItem.setImport(replaceMap[nwItem.itemImport]) self.setProjectChanged(True) return True @@ -1206,10 +1206,10 @@ class NWProject(): self.statusItems.resetCounts() self.importItems.resetCounts() for nwItem in self.projTree: - if nwItem.itemClass == nwItemClass.NOVEL: + if nwItem.itemClass in nwLists.CLS_NOVEL: self.statusItems.countEntry(nwItem.itemStatus) else: - self.importItems.countEntry(nwItem.itemStatus) + self.importItems.countEntry(nwItem.itemImport) return def localLookup(self, theWord): diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py index 4318344f..2ca8ed53 100644 --- a/novelwriter/core/status.py +++ b/novelwriter/core/status.py @@ -24,9 +24,12 @@ along with this program. If not, see . """ import logging +import novelwriter from lxml import etree +from PyQt5.QtGui import QIcon, QPixmap, QColor + from novelwriter.common import checkInt logger = logging.getLogger(__name__) @@ -39,9 +42,11 @@ class NWStatus(): self._theLabels = [] self._theColours = [] self._theCounts = [] + self._theIcons = [] self._theMap = {} self._theLength = 0 self._theIndex = 0 + self._iconSize = novelwriter.CONFIG.pxInt(32) return @@ -50,38 +55,35 @@ class NWStatus(): a duplicate. """ theLabel = theLabel.strip() - if self.lookupEntry(theLabel) is None: + if self._getIndex(theLabel) is None: + theIcon = QPixmap(self._iconSize, self._iconSize) + theIcon.fill(QColor(*theColours)) + self._theIcons.append(QIcon(theIcon)) self._theLabels.append(theLabel) self._theColours.append(theColours) self._theCounts.append(0) self._theMap[theLabel] = self._theLength self._theLength += 1 - return True - def lookupEntry(self, theLabel): - """Look up a status entry in the object lists, and return it if - it exists. - """ - if theLabel is None: - return None - theLabel = theLabel.strip() - if theLabel in self._theMap.keys(): - return self._theMap[theLabel] - return None + return True def checkEntry(self, theStatus): """Check if a status value is valid, and returns the safe reference to be used internally. """ if isinstance(theStatus, str): - theStatus = theStatus.strip() - if self.lookupEntry(theStatus) is not None: - return theStatus - theStatus = checkInt(theStatus, 0, False) - if theStatus >= 0 and theStatus < self._theLength: - return self._theLabels[theStatus] + if self._getIndex(theStatus) is not None: + return theStatus.strip() return self._theLabels[0] + def getIcon(self, theLabel): + """Return the icon for the given status item. + """ + theIndex = self._getIndex(theLabel) + if theIndex is not None: + return self._theIcons[theIndex] + return QIcon() + def setNewEntries(self, newList): """Update the list of entries after they have been modified by the GUI tool. @@ -92,6 +94,7 @@ class NWStatus(): self._theLabels = [] self._theColours = [] self._theCounts = [] + self._theIcons = [] self._theMap = {} self._theLength = 0 self._theIndex = 0 @@ -113,7 +116,7 @@ class NWStatus(): """Increment the counter for a given label. This should be used together with resetCounts in a loop over project items. """ - theIndex = self.lookupEntry(theLabel) + theIndex = self._getIndex(theLabel) if theIndex is not None: self._theCounts[theIndex] += 1 return @@ -124,9 +127,9 @@ class NWStatus(): """ for n in range(self._theLength): xSub = etree.SubElement(xParent, "entry", attrib={ - "blue": str(self._theColours[n][2]), - "green": str(self._theColours[n][1]), "red": str(self._theColours[n][0]), + "green": str(self._theColours[n][1]), + "blue": str(self._theColours[n][2]), }) xSub.text = self._theLabels[n] return True @@ -145,18 +148,31 @@ class NWStatus(): theColours.append((cR, cG, cB)) if len(theLabels) > 0: - self._theLabels = [] + self._theLabels = [] self._theColours = [] - self._theCounts = [] - self._theMap = {} - self._theLength = 0 - self._theIndex = 0 + self._theCounts = [] + self._theIcons = [] + self._theMap = {} + self._theLength = 0 + self._theIndex = 0 for n in range(len(theLabels)): self.addEntry(theLabels[n], theColours[n]) return True + ## + # Internal Functions + ## + + def _getIndex(self, theLabel): + """Look up a status entry in the object lists, and return it if + it exists. + """ + if theLabel is None: + return None + return self._theMap.get(theLabel.strip(), None) + ## # Iterator Bits ## @@ -165,8 +181,8 @@ class NWStatus(): """Return an entry by its index. """ if n >= 0 and n < self._theLength: - return self._theLabels[n], self._theColours[n], self._theCounts[n] - return None, None, None + return self._theLabels[n], self._theColours[n], self._theCounts[n], self._theIcons[n] + return None, None, None, QIcon() def __iter__(self): """Initialise the iterator. @@ -178,9 +194,9 @@ class NWStatus(): """Return the next entry for the iterator. """ if self._theIndex < self._theLength: - theLabel, theColour, theCount = self.__getitem__(self._theIndex) + theLabel, theColour, theCount, theIcon = self.__getitem__(self._theIndex) self._theIndex += 1 - return theLabel, theColour, theCount + return theLabel, theColour, theCount, theIcon else: raise StopIteration diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py index f9ee01af..f7695b9a 100644 --- a/novelwriter/dialogs/docmerge.py +++ b/novelwriter/dialogs/docmerge.py @@ -133,6 +133,7 @@ class GuiDocMerge(QDialog): nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemClass, srcItem.itemParent) newItem = self.theProject.projTree[nHandle] newItem.setStatus(srcItem.itemStatus) + newItem.setImport(srcItem.itemImport) outDoc = NWDoc(self.theProject, nHandle) if not outDoc.writeDocument(theText): diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py index 1138ec58..cdf0757a 100644 --- a/novelwriter/dialogs/docsplit.py +++ b/novelwriter/dialogs/docsplit.py @@ -203,6 +203,7 @@ class GuiDocSplit(QDialog): newItem = self.theProject.projTree[nHandle] newItem.setLayout(itemLayout) newItem.setStatus(srcItem.itemStatus) + newItem.setImport(srcItem.itemImport) logger.verbose( "Creating new document '%s' with text from line %d to %d", nHandle, iStart+1, iEnd diff --git a/novelwriter/dialogs/itemeditor.py b/novelwriter/dialogs/itemeditor.py index 9ab1e4ac..a39d93f4 100644 --- a/novelwriter/dialogs/itemeditor.py +++ b/novelwriter/dialogs/itemeditor.py @@ -75,15 +75,11 @@ class GuiItemEditor(QDialog): self.editStatus = QComboBox() self.editStatus.setMinimumWidth(mVd) if self.theItem.itemClass in nwLists.CLS_NOVEL: - for sLabel, _, _ in self.theProject.statusItems: - self.editStatus.addItem( - self.theParent.statusIcons[sLabel], sLabel, sLabel - ) + for sLabel, _, _, sIcon in self.theProject.statusItems: + self.editStatus.addItem(sIcon, sLabel, sLabel) else: - for sLabel, _, _ in self.theProject.importItems: - self.editStatus.addItem( - self.theParent.importIcons[sLabel], sLabel, sLabel - ) + for sLabel, _, _, sIcon in self.theProject.importItems: + self.editStatus.addItem(sIcon, sLabel, sLabel) # Item Layout self.editLayout = QComboBox() @@ -120,7 +116,8 @@ class GuiItemEditor(QDialog): self.editName.setText(self.theItem.itemName) self.editName.selectAll() - statusIdx = self.editStatus.findData(self.theItem.itemStatus) + currStatus, _ = self.theItem.getImportStatus() + statusIdx = self.editStatus.findData(currStatus) if statusIdx != -1: self.editStatus.setCurrentIndex(statusIdx) @@ -180,7 +177,7 @@ class GuiItemEditor(QDialog): isExported = self.editExport.isChecked() self.theItem.setName(itemName) - self.theItem.setStatus(itemStatus) + self.theItem.setImportStatus(itemStatus) self.theItem.setLayout(itemLayout) self.theItem.setExported(isExported) diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py index 3989f7eb..f6e4b611 100644 --- a/novelwriter/dialogs/projsettings.py +++ b/novelwriter/dialogs/projsettings.py @@ -285,7 +285,7 @@ class GuiProjectEditStatus(QWidget): self.listBox.setColumnWidth(self.COL_LABEL, wCol0) self.listBox.setIndentation(0) - for iName, iCol, nUse in self.theStatus: + for iName, iCol, nUse, _ in self.theStatus: self._addItem(iName, iCol, iName, nUse) # List Controls diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 4d35c978..64c2b73d 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -50,7 +50,7 @@ from PyQt5.QtWidgets import ( ) from novelwriter.core import NWDoc, NWSpellEnchant, countWords -from novelwriter.enum import nwAlert, nwDocAction, nwDocInsert, nwItemClass +from novelwriter.enum import nwAlert, nwDocAction, nwDocInsert from novelwriter.common import transferCase from novelwriter.constants import nwConst, nwKeyWords, nwUnicode from novelwriter.gui.dochighlight import GuiDocHighlighter @@ -2940,17 +2940,10 @@ class GuiDocEditFooter(QWidget): sIcon = QPixmap() sText = "" else: - iStatus = self._theItem.itemStatus - if self._theItem.itemClass == nwItemClass.NOVEL: - iStatus = self.theProject.statusItems.checkEntry(iStatus) - theIcon = self.theParent.statusIcons[iStatus] - else: - iStatus = self.theProject.importItems.checkEntry(iStatus) - theIcon = self.theParent.importIcons[iStatus] - + theStatus, theIcon = self._theItem.getImportStatus() sIcon = theIcon.pixmap(self.sPx, self.sPx) hLevel = self.theParent.theIndex.getHandleHeaderLevel(self._docHandle) - sText = f"{self._theItem.itemStatus} / {self._theItem.describeMe(hLevel)}" + sText = f"{theStatus} / {self._theItem.describeMe(hLevel)}" self.statusIcon.setPixmap(sIcon) self.statusText.setText(sText) diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py index 0596f7a8..21df9b80 100644 --- a/novelwriter/gui/itemdetails.py +++ b/novelwriter/gui/itemdetails.py @@ -30,7 +30,7 @@ from PyQt5.QtCore import Qt, pyqtSlot from PyQt5.QtGui import QFont, QPixmap from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel -from novelwriter.enum import nwItemClass, nwItemType +from novelwriter.enum import nwItemType from novelwriter.constants import trConst, nwLabels logger = logging.getLogger(__name__) @@ -249,16 +249,9 @@ class GuiItemDetails(QWidget): # Status # ====== - itStatus = nwItem.itemStatus - if nwItem.itemClass == nwItemClass.NOVEL: - itStatus = self.theProject.statusItems.checkEntry(itStatus) # Make sure it's valid - flagIcon = self.theParent.statusIcons[itStatus] - else: - itStatus = self.theProject.importItems.checkEntry(itStatus) # Make sure it's valid - flagIcon = self.theParent.importIcons[itStatus] - - self.statusIcon.setPixmap(flagIcon.pixmap(iPx, iPx)) - self.statusData.setText(nwItem.itemStatus) + theStatus, theIcon = nwItem.getImportStatus() + self.statusIcon.setPixmap(theIcon.pixmap(iPx, iPx)) + self.statusData.setText(theStatus) # Class # ===== diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 9f55cbe4..7c0ec69e 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -610,14 +610,7 @@ class GuiProjectTree(QTreeWidget): else: expIcon = self.theTheme.getIcon("cross") - iStatus = nwItem.itemStatus - if nwItem.itemClass == nwItemClass.NOVEL: - iStatus = self.theProject.statusItems.checkEntry(iStatus) # Make sure it's valid - statIcon = self.theParent.statusIcons[iStatus] - else: - iStatus = self.theProject.importItems.checkEntry(iStatus) # Make sure it's valid - statIcon = self.theParent.importIcons[iStatus] - + itempStatus, statusIcon = nwItem.getImportStatus() hLevel = self.theIndex.getHandleHeaderLevel(tHandle) itemIcon = self.theTheme.getItemIcon( nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel @@ -626,8 +619,8 @@ class GuiProjectTree(QTreeWidget): trItem.setIcon(self.C_NAME, itemIcon) trItem.setText(self.C_NAME, nwItem.itemName) trItem.setIcon(self.C_EXPORT, expIcon) - trItem.setIcon(self.C_STATUS, statIcon) - trItem.setToolTip(self.C_STATUS, nwItem.itemStatus) + trItem.setIcon(self.C_STATUS, statusIcon) + trItem.setToolTip(self.C_STATUS, itempStatus) if self.mainConf.emphLabels and nwItem.itemLayout == nwItemLayout.DOCUMENT: trFont = trItem.font(self.C_NAME) diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 2eaea912..9db27659 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -31,7 +31,7 @@ from time import time from datetime import datetime from PyQt5.QtCore import Qt, QTimer, QSize, QThreadPool, pyqtSlot -from PyQt5.QtGui import QIcon, QPixmap, QColor, QKeySequence, QCursor +from PyQt5.QtGui import QIcon, QKeySequence, QCursor from PyQt5.QtWidgets import ( qApp, QMainWindow, QVBoxLayout, QWidget, QSplitter, QFileDialog, QShortcut, QMessageBox, QDialog, QTabWidget, QToolBar, QAction @@ -129,10 +129,6 @@ class GuiMain(QMainWindow): self.treeView.novelItemChanged.connect(self._treeNovelItemChanged) self.treeView.wordCountsChanged.connect(self._updateStatusWordCount) - # Minor GUI Elements - self.statusIcons = [] - self.importIcons = [] - # Project Tree Tabs self.projTabs = QTabWidget() self.projTabs.setTabPosition(QTabWidget.South) @@ -869,8 +865,6 @@ class GuiMain(QMainWindow): def rebuildTrees(self): """Rebuild the project tree. """ - self._makeStatusIcons() - self._makeImportIcons() self.treeView.buildTree() self.novelView.refreshTree() return @@ -1462,29 +1456,6 @@ class GuiMain(QMainWindow): self.saveDocument() return - def _makeStatusIcons(self): - """Generate all the item status icons based on project settings. - """ - self.statusIcons = {} - iPx = self.mainConf.pxInt(32) - for sLabel, sCol, _ in self.theProject.statusItems: - theIcon = QPixmap(iPx, iPx) - theIcon.fill(QColor(*sCol)) - self.statusIcons[sLabel] = QIcon(theIcon) - return - - def _makeImportIcons(self): - """Generate all the item importance icons based on project - settings. - """ - self.importIcons = {} - iPx = self.mainConf.pxInt(32) - for sLabel, sCol, _ in self.theProject.importItems: - theIcon = QPixmap(iPx, iPx) - theIcon.fill(QColor(*sCol)) - self.importIcons[sLabel] = QIcon(theIcon) - return - def _assembleProjectWizardData(self, newProj): """Extract the user choices from the New Project Wizard and store them in a dictionary. diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx index bf40e1ee..68265de5 100644 --- a/sample/nwProject.nwx +++ b/sample/nwProject.nwx @@ -1,5 +1,5 @@ - + Sample Project Sample Project @@ -7,7 +7,7 @@ Jay Doh 1303 199 - 64457 + 65005 False @@ -33,121 +33,121 @@
- New - Notes - Started - 1st Draft - 2nd Draft - 3rd Draft - Finished + New + Notes + Started + 1st Draft + 2nd Draft + 3rd Draft + Finished - None - Minor - Major - Main + None + Minor + Major + Main
- Novel + Novel - Title Page + Title Page - Page + Page - Part One + Part One - A Folder + A Folder - Chapter One + Chapter One - Making a Scene + Making a Scene - Another Scene + Another Scene - Interlude + Interlude - A Note on Structure + A Note on Structure - Chapter Two + Chapter Two - We Found John! + We Found John! - Characters + Characters - Main Characters + Main Characters - John Smith + John Smith - Jane Smith + Jane Smith - Locations + Locations - Earth + Earth - Space + Space - Mars + Mars - Archive + Archive - Scenes + Scenes - Old File + Old File - Trash + Trash - Delete Me! + Delete Me!
diff --git a/tests/conftest.py b/tests/conftest.py index cf348870..4d8d7183 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -36,6 +36,13 @@ from PyQt5.QtWidgets import QMessageBox # noqa: E402 from novelwriter.config import Config # noqa: E402 +@pytest.fixture(autouse=True) +def initQt(qtbot): + """Ensures that the qt main thread is always available in all tests. + """ + return + + ## # Core Test Folders ## diff --git a/tests/lipsum/nwProject.nwx b/tests/lipsum/nwProject.nwx index c6eab805..55a582ad 100644 --- a/tests/lipsum/nwProject.nwx +++ b/tests/lipsum/nwProject.nwx @@ -1,12 +1,12 @@ - + Lorem Ipsum Lorem Ipsum lipsum.com - 21 + 23 24 - 1847 + 1854 False @@ -31,102 +31,102 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main
- Novel + Novel - Lorem Ipsum + Lorem Ipsum - Front Matter + Front Matter - Prologue + Prologue - Act One + Act One - Chapter One + Chapter One - Chapter One + Chapter One - Scene One + Scene One - Scene Two + Scene Two - Interlude + Interlude - Chapter Two + Chapter Two - Chapter Two + Chapter Two - Scene Three + Scene Three - Scene Four + Scene Four - Scene Five + Scene Five - Characters + Characters - Mr. Nobody + Mr. Nobody - Plot + Plot - Main + Main - World + World - Ancient Europe + Ancient Europe
diff --git a/tests/minimal/nwProject.nwx b/tests/minimal/nwProject.nwx index 991d8b68..6f45815d 100644 --- a/tests/minimal/nwProject.nwx +++ b/tests/minimal/nwProject.nwx @@ -1,13 +1,13 @@ - + Test Minimal Minimal Jane Doe John Doh - 12 + 14 2 - 129 + 135 True @@ -29,50 +29,50 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main
- Novel + Novel - Title Page + Title Page - New Chapter + New Chapter - New Chapter + New Chapter - New Scene + New Scene - Plot + Plot - Characters + Characters - World + World
diff --git a/tests/reference/coreProject_NewCustomA_nwProject.nwx b/tests/reference/coreProject_NewCustomA_nwProject.nwx index 4b8a67bf..10398c21 100644 --- a/tests/reference/coreProject_NewCustomA_nwProject.nwx +++ b/tests/reference/coreProject_NewCustomA_nwProject.nwx @@ -1,5 +1,5 @@ - + Test Custom Test Novel @@ -29,110 +29,110 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main - Novel + Novel - Plot + Plot - Characters + Characters - Locations + Locations - Timeline + Timeline - Objects + Objects - Entities + Entities - Title Page + Title Page - Chapter 1 + Chapter 1 - Chapter 1 + Chapter 1 - Scene 1.1 + Scene 1.1 - Scene 1.2 + Scene 1.2 - Scene 1.3 + Scene 1.3 - Chapter 2 + Chapter 2 - Chapter 2 + Chapter 2 - Scene 2.1 + Scene 2.1 - Scene 2.2 + Scene 2.2 - Scene 2.3 + Scene 2.3 - Chapter 3 + Chapter 3 - Chapter 3 + Chapter 3 - Scene 3.1 + Scene 3.1 - Scene 3.2 + Scene 3.2 - Scene 3.3 + Scene 3.3
diff --git a/tests/reference/coreProject_NewCustomB_nwProject.nwx b/tests/reference/coreProject_NewCustomB_nwProject.nwx index 3f55663e..2bb2df31 100644 --- a/tests/reference/coreProject_NewCustomB_nwProject.nwx +++ b/tests/reference/coreProject_NewCustomB_nwProject.nwx @@ -1,5 +1,5 @@ - + Test Custom Test Novel @@ -29,74 +29,74 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main - Novel + Novel - Plot + Plot - Characters + Characters - Locations + Locations - Timeline + Timeline - Objects + Objects - Entities + Entities - Title Page + Title Page - Scene 1 + Scene 1 - Scene 2 + Scene 2 - Scene 3 + Scene 3 - Scene 4 + Scene 4 - Scene 5 + Scene 5 - Scene 6 + Scene 6
diff --git a/tests/reference/coreProject_NewFile_nwProject.nwx b/tests/reference/coreProject_NewFile_nwProject.nwx index d623ee2d..d4ffb126 100644 --- a/tests/reference/coreProject_NewFile_nwProject.nwx +++ b/tests/reference/coreProject_NewFile_nwProject.nwx @@ -1,5 +1,5 @@ - + New Project @@ -27,58 +27,58 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main - Novel + Novel - Plot + Plot - Characters + Characters - World + World - Title Page + Title Page - New Chapter + New Chapter - New Chapter + New Chapter - New Scene + New Scene - Hello + Hello - Jane + Jane
diff --git a/tests/reference/coreProject_NewMinimal_nwProject.nwx b/tests/reference/coreProject_NewMinimal_nwProject.nwx index 6becb112..20fa4d71 100644 --- a/tests/reference/coreProject_NewMinimal_nwProject.nwx +++ b/tests/reference/coreProject_NewMinimal_nwProject.nwx @@ -1,5 +1,5 @@ - + New Project @@ -27,50 +27,50 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main - Novel + Novel - Plot + Plot - Characters + Characters - World + World - Title Page + Title Page - New Chapter + New Chapter - New Chapter + New Chapter - New Scene + New Scene
diff --git a/tests/reference/coreProject_NewRoot_nwProject.nwx b/tests/reference/coreProject_NewRoot_nwProject.nwx index cf55336e..22d51fd7 100644 --- a/tests/reference/coreProject_NewRoot_nwProject.nwx +++ b/tests/reference/coreProject_NewRoot_nwProject.nwx @@ -1,5 +1,5 @@ - + New Project @@ -27,66 +27,66 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main - Novel + Novel - Plot + Plot - Characters + Characters - World + World - Title Page + Title Page - New Chapter + New Chapter - New Chapter + New Chapter - New Scene + New Scene - Timeline + Timeline - Object + Object - Custom1 + Custom1 - Custom2 + Custom2
diff --git a/tests/reference/guiEditor_Main_Final_nwProject.nwx b/tests/reference/guiEditor_Main_Final_nwProject.nwx index 4dd43b9a..685095bb 100644 --- a/tests/reference/guiEditor_Main_Final_nwProject.nwx +++ b/tests/reference/guiEditor_Main_Final_nwProject.nwx @@ -1,5 +1,5 @@ - + New Project @@ -27,66 +27,66 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main - Novel + Novel - Title Page + Title Page - New Chapter + New Chapter - New Chapter + New Chapter - New Scene + New Scene - Plot + Plot - New File + New File - Characters + Characters - New File + New File - World + World - New File + New File - Trash + Trash
diff --git a/tests/reference/guiEditor_Main_Initial_nwProject.nwx b/tests/reference/guiEditor_Main_Initial_nwProject.nwx index f1b17740..a42552cf 100644 --- a/tests/reference/guiEditor_Main_Initial_nwProject.nwx +++ b/tests/reference/guiEditor_Main_Initial_nwProject.nwx @@ -1,5 +1,5 @@ - + New Project @@ -27,50 +27,50 @@
- New - Note - Draft - Finished + New + Note + Draft + Finished - New - Minor - Major - Main + New + Minor + Major + Main - Novel + Novel - Title Page + Title Page - New Chapter + New Chapter - New Chapter + New Chapter - New Scene + New Scene - Plot + Plot - Characters + Characters - World + World
diff --git a/tests/reference/guiProjSettings_Dialog_nwProject.nwx b/tests/reference/guiProjSettings_Dialog_nwProject.nwx index b88e7f17..c6652f72 100644 --- a/tests/reference/guiProjSettings_Dialog_nwProject.nwx +++ b/tests/reference/guiProjSettings_Dialog_nwProject.nwx @@ -1,5 +1,5 @@ - + Project Name Project Title @@ -33,50 +33,50 @@
- New - Note - Finished - Final + New + Note + Finished + Final - New - Minor - Major - Final + New + Minor + Major + Final - Novel + Novel - Title Page + Title Page - New Chapter + New Chapter - New Chapter + New Chapter - New Scene + New Scene - Plot + Plot - Characters + Characters - World + World
diff --git a/tests/test_core/test_core_item.py b/tests/test_core/test_core_item.py index 368592f1..61c67987 100644 --- a/tests/test_core/test_core_item.py +++ b/tests/test_core/test_core_item.py @@ -23,6 +23,8 @@ import pytest from lxml import etree +from PyQt5.QtGui import QIcon + from novelwriter.core import NWProject from novelwriter.core.item import NWItem from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout @@ -74,16 +76,17 @@ def testCoreItem_Setters(mockGUI): assert theItem.itemOrder == 1 # Importance - theItem.setStatus("Nonsense") - assert theItem.itemStatus == "New" - theItem.setStatus("New") - assert theItem.itemStatus == "New" - theItem.setStatus("Minor") - assert theItem.itemStatus == "Minor" - theItem.setStatus("Major") - assert theItem.itemStatus == "Major" - theItem.setStatus("Main") - assert theItem.itemStatus == "Main" + theItem._class = nwItemClass.CHARACTER + theItem.setImport("Nonsense") + assert theItem.itemImport == "New" + theItem.setImport("New") + assert theItem.itemImport == "New" + theItem.setImport("Minor") + assert theItem.itemImport == "Minor" + theItem.setImport("Major") + assert theItem.itemImport == "Major" + theItem.setImport("Main") + assert theItem.itemImport == "Main" # Status theItem._class = nwItemClass.NOVEL @@ -98,6 +101,27 @@ def testCoreItem_Setters(mockGUI): theItem.setStatus("Finished") assert theItem.itemStatus == "Finished" + # Status/Importance Wrapper + theItem._class = nwItemClass.CHARACTER + theItem.setImportStatus("New") + assert theItem.itemImport == "New" + theItem.setImportStatus("Minor") + assert theItem.itemImport == "Minor" + theItem.setImportStatus("Note") + assert theItem.itemImport == "New" + theItem.setImportStatus("Draft") + assert theItem.itemImport == "New" + + theItem._class = nwItemClass.NOVEL + theItem.setImportStatus("New") + assert theItem.itemStatus == "New" + theItem.setImportStatus("Minor") + assert theItem.itemStatus == "New" + theItem.setImportStatus("Note") + assert theItem.itemStatus == "Note" + theItem.setImportStatus("Draft") + assert theItem.itemStatus == "Draft" + # Expanded theItem.setExpanded(8) assert theItem.isExpanded is False @@ -196,6 +220,22 @@ def testCoreItem_Methods(mockGUI): theItem.setLayout("NOTE") assert theItem.describeMe() == "Project Note" + # Status + Icon + # ============= + theItem.setType("FILE") + theItem.setStatus("Note") + theItem.setImport("Minor") + + theItem.setClass("NOVEL") + stT, stI = theItem.getImportStatus() + assert stT == "Note" + assert isinstance(stI, QIcon) + + theItem.setClass("CHARACTER") + stT, stI = theItem.getImportStatus() + assert stT == "Minor" + assert isinstance(stI, QIcon) + # Representation # ============== @@ -342,9 +382,11 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog): xContent = etree.SubElement(nwXML, "content") theItem.packXML(xContent) assert etree.tostring(xContent, pretty_print=False, encoding="utf-8") == ( - b'A Name' + b'' + b'' + b'A Name' + b'' ) # Unpack @@ -385,8 +427,11 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog): xContent = etree.SubElement(nwXML, "content") theItem.packXML(xContent) assert etree.tostring(xContent, pretty_print=False, encoding="utf-8") == ( - b'A Name' + b'' + b'A Name' + b'' + b'' ) # Unpack diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py index 7ae461eb..311fca8c 100644 --- a/tests/test_core/test_core_project.py +++ b/tests/test_core/test_core_project.py @@ -61,10 +61,6 @@ def testCoreProject_NewMinimal(fncDir, outDir, refDir, mockGUI): # Creating the project once more should fail assert theProject.newProject({"projPath": fncDir}) is False - # Check the new project - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) - # Open again assert theProject.openProject(projFile) is True @@ -857,7 +853,7 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir): # Change importance fHandle = theProject.newFile("Jane Doe", nwItemClass.CHARACTER, "afb3043c7b2b3") - theProject.projTree[fHandle].setStatus("Main") + theProject.projTree[fHandle].setImport("Main") newList = [ ("New", 1, 1, 1, "New"), ("Minor", 2, 2, 2, "Minor"), @@ -872,7 +868,7 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir): assert theProject.importItems._theColours == [ (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5) ] - assert theProject.projTree[fHandle].itemStatus == "Min" + assert theProject.projTree[fHandle].itemImport == "Min" # Check status counts assert theProject.statusItems._theCounts == [0, 0, 0, 0, 0] diff --git a/tests/test_core/test_core_status.py b/tests/test_core/test_core_status.py index ab5af333..a7a2d55e 100644 --- a/tests/test_core/test_core_status.py +++ b/tests/test_core/test_core_status.py @@ -23,6 +23,8 @@ import pytest from lxml import etree +from PyQt5.QtGui import QIcon + from novelwriter.core.status import NWStatus @@ -48,9 +50,9 @@ def testCoreStatus_Entries(): assert theStatus._theLength == 4 # Lookups - assert theStatus.lookupEntry(None) is None - assert theStatus.lookupEntry("stuff") is None - assert theStatus.lookupEntry("Main") == 3 + assert theStatus._getIndex(None) is None + assert theStatus._getIndex("stuff") is None + assert theStatus._getIndex("Main") == 3 # Checks assert theStatus.checkEntry(123) == "New" @@ -58,6 +60,10 @@ def testCoreStatus_Entries(): assert theStatus.checkEntry("New ") == "New" assert theStatus.checkEntry(" Main ") == "Main" + # Icons + assert isinstance(theStatus.getIcon("Stuff"), QIcon) + assert isinstance(theStatus.getIcon("New"), QIcon) + # Set new list newList = [ ("New", 1, 1, 1, "New"), @@ -87,12 +93,17 @@ def testCoreStatus_Entries(): assert theStatus._theCounts == countTo # Iterate - for i, (sA, sB, sC) in enumerate(theStatus): + for i, (sA, sB, sC, sD) in enumerate(theStatus): assert sA == theStatus._theLabels[i] assert sB == theStatus._theColours[i] assert sC == theStatus._theCounts[i] + assert sD == theStatus._theIcons[i] - assert theStatus[9] == (None, None, None) + sA, sB, sC, sD = theStatus[9] + assert sA is None + assert sB is None + assert sC is None + assert isinstance(sD, QIcon) # Clear counts theStatus.resetCounts() @@ -122,12 +133,12 @@ def testCoreStatus_XMLPackUnpack(): xStatus = etree.SubElement(nwXML, "status") theStatus.packXML(xStatus) assert etree.tostring(xStatus, pretty_print=False, encoding="utf-8") == ( - b"" - b"New" - b"Minor" - b"Major" - b"Main" - b"" + b'' + b'New' + b'Minor' + b'Major' + b'Main' + b'' ) # Unpack diff --git a/tests/test_core/test_core_tokenizer.py b/tests/test_core/test_core_tokenizer.py index d277a601..088de786 100644 --- a/tests/test_core/test_core_tokenizer.py +++ b/tests/test_core/test_core_tokenizer.py @@ -30,7 +30,7 @@ from novelwriter.core.tokenizer import Tokenizer class BareTokenizer(Tokenizer): def doConvert(self): - pass + super().doConvert() @pytest.mark.core @@ -219,6 +219,10 @@ def testCoreToken_TextOps(monkeypatch, nwMinimal, mockGUI): "# Notes: Plot\n\n" ) + # Ckeck abstract method + with pytest.raises(NotImplementedError): + theToken.doConvert() + # END Test testCoreToken_TextOps diff --git a/tests/test_core/test_core_tree.py b/tests/test_core/test_core_tree.py index e0e82f39..b9ad0473 100644 --- a/tests/test_core/test_core_tree.py +++ b/tests/test_core/test_core_tree.py @@ -387,25 +387,26 @@ def testCoreTree_XMLPackUnpack(mockGUI, mockItems): assert etree.tostring(nwXML, pretty_print=False, encoding="utf-8") == ( b'' b'' - b'' - b'Novel' + b'Novel' b'Act One' + b'class="NOVEL">Act One' + b'' b'' - b'Chapter One' + b'Chapter One' b'' - b'Scene One' - b'' - b'Outtakes' - b'' - b'Trash' + b'Scene One' + b'Outtakes' + b'Trash' b'' - b'Characters' + b'Characters' b'Jane Doe' + b'cursorPos="0"/>Jane Doe' b'' b'' ) diff --git a/tests/test_dialogs/test_dlg_itemeditor.py b/tests/test_dialogs/test_dlg_itemeditor.py index 4d183408..79038345 100644 --- a/tests/test_dialogs/test_dlg_itemeditor.py +++ b/tests/test_dialogs/test_dlg_itemeditor.py @@ -174,11 +174,12 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj): itemEdit.editName.setText("New Character") itemEdit.editStatus.setCurrentIndex(1) itemEdit.editExport.setChecked(False) + itemEdit._doSave() # Check New Settings - itemEdit._doSave() assert itemEdit.theItem.itemName == "New Character" - assert itemEdit.theItem.itemStatus == "Minor" + assert itemEdit.theItem.itemStatus == "New" + assert itemEdit.theItem.itemImport == "Minor" assert itemEdit.theItem.itemLayout == nwItemLayout.NOTE assert itemEdit.theItem.isExported is False