Move status and importance to data class

This commit is contained in:
Veronica Berglyd Olsen
2022-10-31 17:01:50 +01:00
parent cc2ef85afd
commit 522acc479b
9 changed files with 110 additions and 115 deletions
+6 -6
View File
@@ -271,11 +271,11 @@ class NWItem:
the current item based on its class.
"""
if self.isNovelLike():
stName = self.theProject.statusItems.name(self._status)
stIcon = self.theProject.statusItems.icon(self._status) if incIcon else None
stName = self.theProject.data.itemStatus.name(self._status)
stIcon = self.theProject.data.itemStatus.icon(self._status) if incIcon else None
else:
stName = self.theProject.importItems.name(self._import)
stIcon = self.theProject.importItems.icon(self._import) if incIcon else None
stName = self.theProject.data.itemImport.name(self._import)
stIcon = self.theProject.data.itemImport.icon(self._import) if incIcon else None
return stName, stIcon
##
@@ -447,14 +447,14 @@ class NWItem:
"""Set the item status by looking it up in the valid status
items of the current project.
"""
self._status = self.theProject.statusItems.check(value)
self._status = self.theProject.data.itemStatus.check(value)
return
def setImport(self, value):
"""Set the item importance by looking it up in the valid import
items of the current project.
"""
self._import = self.theProject.importItems.check(value)
self._import = self.theProject.data.itemImport.check(value)
return
def setActive(self, state):
+17 -24
View File
@@ -45,7 +45,6 @@ from novelwriter.constants import trConst, nwFiles, nwLabels
from novelwriter.core.tree import NWTree
from novelwriter.core.item import NWItem
from novelwriter.core.index import NWIndex
from novelwriter.core.status import NWStatus
from novelwriter.core.options import OptionState
from novelwriter.core.document import NWDoc
from novelwriter.core.projectxml import ProjectXMLReader, XMLReadState
@@ -92,8 +91,6 @@ class NWProject:
self.autoReplace = {} # Text to auto-replace on exports
self.titleFormat = {} # The formatting of titles for exports
self.spellCheck = False # Controls the spellcheck-as-you-type feature
self.statusItems = None # Novel file progress status values
self.importItems = None # Note file importance values
# Internal Mapping
self.tr = partial(QCoreApplication.translate, "NWProject")
@@ -268,17 +265,15 @@ class NWProject:
"scene": "* * *",
"section": "",
}
self.spellCheck = False
self.statusItems = NWStatus(NWStatus.STATUS)
self.statusItems.write(None, self.tr("New"), (100, 100, 100))
self.statusItems.write(None, self.tr("Note"), (200, 50, 0))
self.statusItems.write(None, self.tr("Draft"), (200, 150, 0))
self.statusItems.write(None, self.tr("Finished"), (50, 200, 0))
self.importItems = NWStatus(NWStatus.IMPORT)
self.importItems.write(None, self.tr("New"), (100, 100, 100))
self.importItems.write(None, self.tr("Minor"), (200, 50, 0))
self.importItems.write(None, self.tr("Major"), (200, 150, 0))
self.importItems.write(None, self.tr("Main"), (50, 200, 0))
self.spellCheck = False
self._data.itemStatus.write(None, self.tr("New"), (100, 100, 100))
self._data.itemStatus.write(None, self.tr("Note"), (200, 50, 0))
self._data.itemStatus.write(None, self.tr("Draft"), (200, 150, 0))
self._data.itemStatus.write(None, self.tr("Finished"), (50, 200, 0))
self._data.itemImport.write(None, self.tr("New"), (100, 100, 100))
self._data.itemImport.write(None, self.tr("Minor"), (200, 50, 0))
self._data.itemImport.write(None, self.tr("Major"), (200, 150, 0))
self._data.itemImport.write(None, self.tr("Main"), (50, 200, 0))
return
@@ -548,8 +543,6 @@ class NWProject:
self.spellCheck = self._data.spellCheck
self.projSpell = self._data.spellLang
self.statusItems.unpack(xmlSettings.get("status", {}))
self.importItems.unpack(xmlSettings.get("import", {}))
self.autoReplace = xmlSettings.get("autoReplace", {})
self.titleFormat.update(xmlSettings.get("titleFormat", {}))
@@ -665,9 +658,9 @@ class NWProject:
# Save Status/Importance
self.countStatus()
xStatus = etree.SubElement(xSettings, "status")
self.statusItems.packXML(xStatus)
self._data.itemStatus.packXML(xStatus)
xStatus = etree.SubElement(xSettings, "importance")
self.importItems.packXML(xStatus)
self._data.itemImport.packXML(xStatus)
# Save Tree Content
logger.debug("Writing project content")
@@ -970,12 +963,12 @@ class NWProject:
def setStatusColours(self, newCols, delCols):
"""Update the list of novel file status flags.
"""
return self._setStatusImport(newCols, delCols, self.statusItems)
return self._setStatusImport(newCols, delCols, self._data.itemStatus)
def setImportColours(self, newCols, delCols):
"""Update the list of note file importance flags.
"""
return self._setStatusImport(newCols, delCols, self.importItems)
return self._setStatusImport(newCols, delCols, self._data.itemImport)
def setAutoReplace(self, autoReplace):
"""Update the auto-replace dictionary.
@@ -1096,13 +1089,13 @@ class NWProject:
project tree. The counts themselves are kept in the NWStatus
objects. This is essentially a refresh.
"""
self.statusItems.resetCounts()
self.importItems.resetCounts()
self._data.itemStatus.resetCounts()
self._data.itemImport.resetCounts()
for nwItem in self._projTree:
if nwItem.isNovelLike():
self.statusItems.increment(nwItem.itemStatus)
self._data.itemStatus.increment(nwItem.itemStatus)
else:
self.importItems.increment(nwItem.itemImport)
self._data.itemImport.increment(nwItem.itemImport)
return
def localLookup(self, theWord):
+12
View File
@@ -28,6 +28,7 @@ import logging
from novelwriter.common import (
checkBool, checkInt, checkStringNone, simplified
)
from novelwriter.core.status import NWStatus
logger = logging.getLogger(__name__)
@@ -53,6 +54,9 @@ class NWProjectData:
self._lastCount = {}
self._currCount = {}
self._status = NWStatus(NWStatus.STATUS)
self._import = NWStatus(NWStatus.IMPORT)
# Internal
self._changed = False
@@ -102,6 +106,14 @@ class NWProjectData:
def spellLang(self):
return self._spellLang
@property
def itemStatus(self):
return self._status
@property
def itemImport(self):
return self._import
@property
def changed(self):
return self._changed
+19 -32
View File
@@ -31,7 +31,7 @@ from enum import Enum
from lxml import etree
from novelwriter.common import (
checkBool, checkInt, checkStringNone, minmax, simplified, checkString
checkBool, checkInt, checkStringNone, simplified, checkString
)
logger = logging.getLogger(__name__)
@@ -192,6 +192,7 @@ class ProjectXMLReader:
if self._version >= 0x0104:
status &= self._parseProjectContent(xSection)
else:
self._genLegacyImportStatysMap(projData)
status &= self._parseProjectContentLegacy(xSection)
else:
logger.warning("Ignored <root/%s> in xml", xSection.tag)
@@ -264,9 +265,9 @@ class ProjectXMLReader:
elif xItem.tag == "notesWordCount":
projData.setLastCount(xItem.text, "notes")
elif xItem.tag == "status":
data["status"] = self._parseStatusImport(xItem, "status")
self._parseStatusImport(xItem, projData.itemStatus)
elif xItem.tag in ("import", "importance"):
data["import"] = self._parseStatusImport(xItem, "import")
self._parseStatusImport(xItem, projData.itemImport)
elif xItem.tag == "autoReplace":
if self._version >= 0x0102:
for xEntry in xItem:
@@ -375,9 +376,9 @@ class ProjectXMLReader:
# Status was split into separate status/import with a key in 1.4
if item.get("class", "") in ("NOVEL", "ARCHIVE"):
item["status"] = self._getLegacyUnportStatus(tmpStatus, "status")
item["status"] = self._statusMap.get(tmpStatus, None)
else:
item["import"] = self._getLegacyUnportStatus(tmpStatus, "import")
item["import"] = self._importMap.get(tmpStatus, None)
# A number of layouts were removed in 1.3
if item.get("layout", "") in depLayout:
@@ -396,39 +397,25 @@ class ProjectXMLReader:
return True
def _parseStatusImport(self, xItem, type):
def _parseStatusImport(self, xItem, sObject):
"""Parse a status or importance entry.
"""
data = self._statusData.get(type, {})
for xEntry in xItem:
if xEntry.tag == "entry":
key = xEntry.attrib.get("key", f"{type[0]}{len(data):06x}")
data[key] = {
"label": xEntry.text,
"count": checkInt(xEntry.attrib.get("count", 0), 0),
"colour": (
minmax(checkInt(xEntry.attrib.get("red", 0), 0), 0, 255),
minmax(checkInt(xEntry.attrib.get("green", 0), 0), 0, 255),
minmax(checkInt(xEntry.attrib.get("blue", 0), 0), 0, 255),
),
}
self._statusData[type] = data
key = xEntry.attrib.get("key", None)
red = checkInt(xEntry.attrib.get("red", 0), 0)
green = checkInt(xEntry.attrib.get("green", 0), 0)
blue = checkInt(xEntry.attrib.get("blue", 0), 0)
count = checkInt(xEntry.attrib.get("count", 0), 0)
sObject.write(key, xEntry.text, (red, green, blue), count)
return
return data
def _getLegacyUnportStatus(self, label, type):
"""Look up the label in defined status or importance values.
This is needed for file formats prior to 1.4 where the status
was saved as the label, not the key.
def _genLegacyImportStatysMap(self, projData):
"""Generate a map of legacy import/status values.
"""
if not self._statusMap.get(type):
lookup = {}
for key, entry in self._statusData.get(type, {}).items():
lookup[entry.get("label", "")] = key
self._statusMap[type] = lookup
print(lookup)
return self._statusMap.get(type, {}).get(label, None)
self._statusMap = {entry["name"]: key for key, entry in projData.itemStatus.items()}
self._importMap = {entry["name"]: key for key, entry in projData.itemImport.items()}
return
# END Class ProjectXMLReader
+10 -7
View File
@@ -33,7 +33,7 @@ from lxml import etree
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor
from PyQt5.QtCore import QRectF, Qt
from novelwriter.common import simplified
from novelwriter.common import minmax, simplified
logger = logging.getLogger(__name__)
@@ -57,7 +57,7 @@ class NWStatus:
self._iconPath = QPainterPath()
self._iconPath.addRoundedRect(QRectF(pA, pA, pB, pB), pR, pR)
self._defaultIcon = self._createIcon([100, 100, 100])
self._defaultIcon = self._createIcon(100, 100, 100)
if self._type == self.STATUS:
self._prefix = "s"
@@ -79,14 +79,17 @@ class NWStatus:
if len(col) != 3:
col = (100, 100, 100)
cR = minmax(col[0], 0, 255)
cG = minmax(col[1], 0, 255)
cB = minmax(col[2], 0, 255)
name = simplified(name)
if count is None:
count = self._store[key]["count"] if key in self._store else 0
count = self._store.get(key, {}).get("count", 0)
self._store[key] = {
"name": name,
"icon": self._createIcon(col),
"cols": col,
"icon": self._createIcon(cR, cG, cB),
"cols": (cR, cG, cB),
"count": count,
}
@@ -261,7 +264,7 @@ class NWStatus:
return False
return True
def _createIcon(self, col):
def _createIcon(self, red, green, blue):
"""Generate an icon for a status label.
"""
pixmap = QPixmap(self._iPX, self._iPX)
@@ -269,7 +272,7 @@ class NWStatus:
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
painter.fillPath(self._iconPath, QColor(*col))
painter.fillPath(self._iconPath, QColor(red, green, blue))
painter.end()
return QIcon(pixmap)
+2 -2
View File
@@ -288,11 +288,11 @@ class GuiProjectEditStatus(QWidget):
self.mainTheme = projGui.mainGui.mainTheme
if isStatus:
self.theStatus = self.theProject.statusItems
self.theStatus = self.theProject.data.itemStatus
pageLabel = self.tr("Novel File Status Levels")
colSetting = "statusColW"
else:
self.theStatus = self.theProject.importItems
self.theStatus = self.theProject.data.itemImport
pageLabel = self.tr("Note File Importance Levels")
colSetting = "importColW"
+2 -2
View File
@@ -1208,7 +1208,7 @@ class GuiProjectTree(QTreeWidget):
checkMark = f" ({nwUnicode.U_CHECK})"
if tItem.isNovelLike():
mStatus = ctxMenu.addMenu(self.tr("Set Status to ..."))
for n, (key, entry) in enumerate(self.theProject.statusItems.items()):
for n, (key, entry) in enumerate(self.theProject.data.itemStatus.items()):
entryName = entry["name"] + (checkMark if tItem.itemStatus == key else "")
aStatus = mStatus.addAction(entry["icon"], entryName)
aStatus.triggered.connect(
@@ -1221,7 +1221,7 @@ class GuiProjectTree(QTreeWidget):
)
else:
mImport = ctxMenu.addMenu(self.tr("Set Importance to ..."))
for n, (key, entry) in enumerate(self.theProject.importItems.items()):
for n, (key, entry) in enumerate(self.theProject.data.itemImport.items()):
entryName = entry["name"] + (checkMark if tItem.itemImport == key else "")
aImport = mImport.addAction(entry["icon"], entryName)
aImport.triggered.connect(
+40 -40
View File
@@ -783,24 +783,24 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
assert theProject.setStatusColours([], []) is False
assert theProject.setStatusColours(newList, []) is True
assert theProject.statusItems.name(statusKeys[0]) == "New"
assert theProject.statusItems.name(statusKeys[1]) == "Draft"
assert theProject.statusItems.name(statusKeys[2]) == "Note"
assert theProject.statusItems.name(statusKeys[3]) == "Edited"
assert theProject.statusItems.cols(statusKeys[0]) == (1, 1, 1)
assert theProject.statusItems.cols(statusKeys[1]) == (2, 2, 2)
assert theProject.statusItems.cols(statusKeys[2]) == (3, 3, 3)
assert theProject.statusItems.cols(statusKeys[3]) == (4, 4, 4)
assert theProject.data.itemStatus.name(statusKeys[0]) == "New"
assert theProject.data.itemStatus.name(statusKeys[1]) == "Draft"
assert theProject.data.itemStatus.name(statusKeys[2]) == "Note"
assert theProject.data.itemStatus.name(statusKeys[3]) == "Edited"
assert theProject.data.itemStatus.cols(statusKeys[0]) == (1, 1, 1)
assert theProject.data.itemStatus.cols(statusKeys[1]) == (2, 2, 2)
assert theProject.data.itemStatus.cols(statusKeys[2]) == (3, 3, 3)
assert theProject.data.itemStatus.cols(statusKeys[3]) == (4, 4, 4)
# Check the new entry
lastKey = theProject.statusItems.check("s000018")
lastKey = theProject.data.itemStatus.check("s000018")
assert lastKey == "s000018"
assert theProject.statusItems.name(lastKey) == "Finished"
assert theProject.statusItems.cols(lastKey) == (5, 5, 5)
assert theProject.data.itemStatus.name(lastKey) == "Finished"
assert theProject.data.itemStatus.cols(lastKey) == (5, 5, 5)
# Delete last entry
assert theProject.setStatusColours([], [lastKey]) is True
assert theProject.statusItems.name(lastKey) == "New"
assert theProject.data.itemStatus.name(lastKey) == "New"
# Change Importance
# =================
@@ -820,52 +820,52 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
assert theProject.setImportColours([], []) is False
assert theProject.setImportColours(newList, []) is True
assert theProject.importItems.name(importKeys[0]) == "New"
assert theProject.importItems.name(importKeys[1]) == "Minor"
assert theProject.importItems.name(importKeys[2]) == "Major"
assert theProject.importItems.name(importKeys[3]) == "Min"
assert theProject.importItems.cols(importKeys[0]) == (1, 1, 1)
assert theProject.importItems.cols(importKeys[1]) == (2, 2, 2)
assert theProject.importItems.cols(importKeys[2]) == (3, 3, 3)
assert theProject.importItems.cols(importKeys[3]) == (4, 4, 4)
assert theProject.data.itemImport.name(importKeys[0]) == "New"
assert theProject.data.itemImport.name(importKeys[1]) == "Minor"
assert theProject.data.itemImport.name(importKeys[2]) == "Major"
assert theProject.data.itemImport.name(importKeys[3]) == "Min"
assert theProject.data.itemImport.cols(importKeys[0]) == (1, 1, 1)
assert theProject.data.itemImport.cols(importKeys[1]) == (2, 2, 2)
assert theProject.data.itemImport.cols(importKeys[2]) == (3, 3, 3)
assert theProject.data.itemImport.cols(importKeys[3]) == (4, 4, 4)
# Check the new entry
lastKey = theProject.importItems.check("i00001a")
lastKey = theProject.data.itemImport.check("i00001a")
assert lastKey == "i00001a"
assert theProject.importItems.name(lastKey) == "Max"
assert theProject.importItems.cols(lastKey) == (5, 5, 5)
assert theProject.data.itemImport.name(lastKey) == "Max"
assert theProject.data.itemImport.cols(lastKey) == (5, 5, 5)
# Delete last entry
assert theProject.setImportColours([], [lastKey]) is True
assert theProject.importItems.name(lastKey) == "New"
assert theProject.data.itemImport.name(lastKey) == "New"
# Delete Status/Import
# ====================
theProject.statusItems.resetCounts()
for key in list(theProject.statusItems.keys()):
assert theProject.statusItems.remove(key) is True
theProject.data.itemStatus.resetCounts()
for key in list(theProject.data.itemStatus.keys()):
assert theProject.data.itemStatus.remove(key) is True
theProject.importItems.resetCounts()
for key in list(theProject.importItems.keys()):
assert theProject.importItems.remove(key) is True
theProject.data.itemImport.resetCounts()
for key in list(theProject.data.itemImport.keys()):
assert theProject.data.itemImport.remove(key) is True
assert len(theProject.statusItems) == 0
assert len(theProject.importItems) == 0
assert len(theProject.data.itemStatus) == 0
assert len(theProject.data.itemImport) == 0
assert theProject.saveProject() is True
assert theProject.closeProject() is True
# This should restore the default status/import labels
assert theProject.openProject(fncDir) is True
assert theProject.saveProject() is True
assert theProject.statusItems.name("s000023") == "New"
assert theProject.statusItems.name("s000024") == "Note"
assert theProject.statusItems.name("s000025") == "Draft"
assert theProject.statusItems.name("s000026") == "Finished"
assert theProject.importItems.name("i000027") == "New"
assert theProject.importItems.name("i000028") == "Minor"
assert theProject.importItems.name("i000029") == "Major"
assert theProject.importItems.name("i00002a") == "Main"
assert theProject.data.itemStatus.name("s000023") == "New"
assert theProject.data.itemStatus.name("s000024") == "Note"
assert theProject.data.itemStatus.name("s000025") == "Draft"
assert theProject.data.itemStatus.name("s000026") == "Finished"
assert theProject.data.itemImport.name("i000027") == "New"
assert theProject.data.itemImport.name("i000028") == "Minor"
assert theProject.data.itemImport.name("i000029") == "Major"
assert theProject.data.itemImport.name("i00002a") == "Main"
# END Test testCoreProject_StatusImport
+2 -2
View File
@@ -330,13 +330,13 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncDir, fncProj,
# Check Project
projSettings._doSave()
statusItems = dict(theProject.statusItems.items())
statusItems = dict(theProject.data.itemStatus.items())
assert statusItems[C.sNew]["name"] == "New"
assert statusItems[C.sDraft]["name"] == "Draft"
assert statusItems[C.sFinished]["name"] == "Finished"
assert statusItems["s000013"]["name"] == "Final"
importItems = dict(theProject.importItems.items())
importItems = dict(theProject.data.itemImport.items())
assert importItems[C.iNew]["name"] == "New"
assert importItems[C.iMajor]["name"] == "Major"
assert importItems[C.iMain]["name"] == "Main"