Simplify further how status labels are added and updated
This commit is contained in:
@@ -104,7 +104,7 @@ class DocMerger:
|
||||
docText = self._project.storage.getDocumentText(srcHandle).rstrip("\n")
|
||||
if addComment:
|
||||
docInfo = srcItem.describeMe()
|
||||
docSt, _ = srcItem.getImportStatus(incIcon=False)
|
||||
docSt, _ = srcItem.getImportStatus()
|
||||
cmtLine = f"% {cmtPrefix} {docInfo}: {srcItem.itemName} [{docSt}]\n\n"
|
||||
docText = cmtLine + docText
|
||||
|
||||
|
||||
+21
-43
@@ -26,34 +26,32 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from collections.abc import Iterable
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
from functools import partial
|
||||
from collections.abc import Iterable
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from novelwriter import CONFIG, SHARED, __version__, __hexversion__
|
||||
from novelwriter.core.status import StatusEntry
|
||||
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.constants import trConst, nwLabels
|
||||
from novelwriter.core.tree import NWTree
|
||||
from novelwriter.core.index import NWIndex
|
||||
from novelwriter.core.options import OptionState
|
||||
from novelwriter.core.storage import NWStorage, NWStorageOpen
|
||||
from novelwriter.core.sessions import NWSessionLog
|
||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
|
||||
from novelwriter.core.projectdata import NWProjectData
|
||||
from novelwriter.common import (
|
||||
checkStringNone, formatInt, formatTimeStamp, getFileSize, hexToInt, makeFileNameSafe, minmax
|
||||
)
|
||||
from novelwriter.constants import trConst, nwLabels
|
||||
from novelwriter.core.index import NWIndex
|
||||
from novelwriter.core.options import OptionState
|
||||
from novelwriter.core.projectdata import NWProjectData
|
||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
|
||||
from novelwriter.core.sessions import NWSessionLog
|
||||
from novelwriter.core.storage import NWStorage, NWStorageOpen
|
||||
from novelwriter.core.tree import NWTree
|
||||
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.status import NWStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -462,14 +460,14 @@ class NWProject:
|
||||
|
||||
def setDefaultStatusImport(self) -> None:
|
||||
"""Set the default status and importance values."""
|
||||
self._data.itemStatus.write(None, self.tr("New"), (100, 100, 100), "SQUARE")
|
||||
self._data.itemStatus.write(None, self.tr("Note"), (200, 50, 0), "SQUARE")
|
||||
self._data.itemStatus.write(None, self.tr("Draft"), (200, 150, 0), "SQUARE")
|
||||
self._data.itemStatus.write(None, self.tr("Finished"), (50, 200, 0), "SQUARE")
|
||||
self._data.itemImport.write(None, self.tr("New"), (100, 100, 100), "SQUARE")
|
||||
self._data.itemImport.write(None, self.tr("Minor"), (200, 50, 0), "SQUARE")
|
||||
self._data.itemImport.write(None, self.tr("Major"), (200, 150, 0), "SQUARE")
|
||||
self._data.itemImport.write(None, self.tr("Main"), (50, 200, 0), "SQUARE")
|
||||
self._data.itemStatus.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
|
||||
self._data.itemStatus.add(None, self.tr("Note"), (200, 50, 0), "SQUARE", 0)
|
||||
self._data.itemStatus.add(None, self.tr("Draft"), (200, 150, 0), "SQUARE", 0)
|
||||
self._data.itemStatus.add(None, self.tr("Finished"), (50, 200, 0), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("Minor"), (200, 50, 0), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("Major"), (200, 150, 0), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("Main"), (50, 200, 0), "SQUARE", 0)
|
||||
return
|
||||
|
||||
def setProjectLang(self, language: str | None) -> None:
|
||||
@@ -492,14 +490,6 @@ class NWProject:
|
||||
self.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setStatus(self, update: list[tuple[str | None, StatusEntry]], remove: list[str]) -> None:
|
||||
"""Update the list of novel file status flags."""
|
||||
return self._setStatusImport(update, remove, self._data.itemStatus)
|
||||
|
||||
def setImport(self, update: list[tuple[str | None, StatusEntry]], remove: list[str]) -> None:
|
||||
"""Update the list of note file importance flags."""
|
||||
return self._setStatusImport(update, remove, self._data.itemImport)
|
||||
|
||||
def setProjectChanged(self, status: bool) -> bool:
|
||||
"""Toggle the project changed flag, and propagate the
|
||||
information to the GUI statusbar.
|
||||
@@ -585,18 +575,6 @@ class NWProject:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _setStatusImport(self, update: list[tuple[str | None, StatusEntry]],
|
||||
remove: list[str], target: NWStatus) -> None:
|
||||
"""Update the list of novel file status or importance flags, and
|
||||
delete those that have been requested deleted.
|
||||
"""
|
||||
if update or remove:
|
||||
order = [target.write(k, e.name, e.color, e.shape) for k, e in update]
|
||||
for key in remove:
|
||||
target.remove(key)
|
||||
target.reorder(order)
|
||||
return
|
||||
|
||||
def _loadProjectLocalisation(self) -> bool:
|
||||
"""Load the language data for the current project language."""
|
||||
if self._data.language is None or CONFIG._nwLangPath is None:
|
||||
|
||||
@@ -439,7 +439,7 @@ class ProjectXMLReader:
|
||||
blue = checkInt(xEntry.attrib.get("blue", 0), 0)
|
||||
count = checkInt(xEntry.attrib.get("count", 0), 0)
|
||||
shape = xEntry.attrib.get("shape", "")
|
||||
sObject.write(key, xEntry.text or "", (red, green, blue), shape, count)
|
||||
sObject.add(key, xEntry.text or "", (red, green, blue), shape, count)
|
||||
return
|
||||
|
||||
def _parseDictKeyText(self, xItem: ET.Element) -> dict:
|
||||
|
||||
+25
-62
@@ -35,7 +35,7 @@ from typing import TYPE_CHECKING, Literal
|
||||
from PyQt5.QtCore import QPointF, Qt
|
||||
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor, QPolygonF
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.common import simplified
|
||||
from novelwriter.enum import nwStatusShape
|
||||
from novelwriter.types import QtPaintAnitAlias, QtTransparent
|
||||
@@ -77,7 +77,7 @@ class NWStatus:
|
||||
self._store: dict[str, StatusEntry] = {}
|
||||
self._default = None
|
||||
|
||||
self._iPX = CONFIG.pxInt(24)
|
||||
self._iPx = SHARED.theme.baseIconHeight
|
||||
|
||||
if self._type == self.STATUS:
|
||||
self._prefix = "s"
|
||||
@@ -103,62 +103,42 @@ class NWStatus:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def write(self, key: str | None, name: str, color: tuple[int, int, int] | QColor,
|
||||
shape: nwStatusShape | str, count: int = 0) -> str:
|
||||
def add(self, key: str | None, name: str, color: tuple[int, int, int],
|
||||
shape: str, count: int) -> str:
|
||||
"""Add or update a status entry. If the key is invalid, a new
|
||||
key is generated.
|
||||
"""
|
||||
if not self._isKey(key):
|
||||
key = self._newKey()
|
||||
|
||||
if isinstance(color, QColor):
|
||||
qColor = color
|
||||
elif isinstance(color, tuple) and len(color) == 3:
|
||||
if isinstance(color, tuple) and len(color) == 3:
|
||||
qColor = QColor(*color)
|
||||
else:
|
||||
qColor = QColor(100, 100, 100)
|
||||
|
||||
if not isinstance(shape, nwStatusShape):
|
||||
try:
|
||||
shape = nwStatusShape[shape]
|
||||
except KeyError:
|
||||
shape = nwStatusShape.SQUARE
|
||||
try:
|
||||
iShape = nwStatusShape[shape]
|
||||
except KeyError:
|
||||
iShape = nwStatusShape.SQUARE
|
||||
|
||||
key = self._checkKey(key)
|
||||
name = simplified(name)
|
||||
icon = self.createIcon(self._iPX, qColor, shape)
|
||||
|
||||
if key and key in self._store:
|
||||
entry = self._store[key]
|
||||
entry.name = name
|
||||
entry.color = qColor
|
||||
entry.shape = shape
|
||||
entry.icon = icon
|
||||
entry.count = count
|
||||
else:
|
||||
self._store[key] = StatusEntry(name, qColor, shape, icon, count)
|
||||
icon = self.createIcon(self._iPx, qColor, iShape)
|
||||
self._store[key] = StatusEntry(name, qColor, iShape, icon, count)
|
||||
|
||||
if self._default is None:
|
||||
self._default = key
|
||||
|
||||
return key
|
||||
|
||||
def remove(self, key: str) -> bool:
|
||||
"""Remove an entry in the list, except if the count > 0."""
|
||||
if key not in self._store:
|
||||
return False
|
||||
if self._store[key].count > 0:
|
||||
return False
|
||||
def update(self, update: list[tuple[str | None, StatusEntry]]) -> None:
|
||||
"""Update the list of statuses, and from removed list."""
|
||||
self._store.clear()
|
||||
for key, entry in update:
|
||||
self._store[self._checkKey(key)] = entry
|
||||
|
||||
del self._store[key]
|
||||
# Check if we need a new default
|
||||
if self._default not in self._store:
|
||||
self._default = next(iter(self._store)) if self._store else None
|
||||
|
||||
keys = list(self._store.keys())
|
||||
if key == self._default:
|
||||
if len(keys) > 0:
|
||||
self._default = keys[0]
|
||||
else:
|
||||
self._default = None
|
||||
|
||||
return True
|
||||
return
|
||||
|
||||
def check(self, value: str) -> str:
|
||||
"""Check the key against the stored status names."""
|
||||
@@ -168,27 +148,6 @@ class NWStatus:
|
||||
return self._default
|
||||
return ""
|
||||
|
||||
def reorder(self, order: list[str]) -> bool:
|
||||
"""Reorder the items according to list."""
|
||||
if len(order) != len(self._store):
|
||||
logger.error("Length mismatch between new and old order")
|
||||
return False
|
||||
|
||||
if order == list(self._store.keys()):
|
||||
return False
|
||||
|
||||
store = {}
|
||||
for key in order:
|
||||
if key in self._store:
|
||||
store[key] = self._store[key]
|
||||
else:
|
||||
logger.error("Unknown key '%s' in order", key)
|
||||
return False
|
||||
|
||||
self._store = store
|
||||
|
||||
return True
|
||||
|
||||
def resetCounts(self) -> None:
|
||||
"""Clear the counts of references to the status entries."""
|
||||
for key in self._store:
|
||||
@@ -264,6 +223,10 @@ class NWStatus:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _checkKey(self, key: str | None) -> str:
|
||||
"""Check key is valid, and if not, generate one."""
|
||||
return key if self._isKey(key) else self._newKey()
|
||||
|
||||
# END Class NWStatus
|
||||
|
||||
|
||||
|
||||
@@ -181,19 +181,16 @@ class GuiProjectSettings(QDialog):
|
||||
|
||||
rebuildTrees = False
|
||||
|
||||
if self.statusPage.wasChanged:
|
||||
update, remove = self.statusPage.getNewList()
|
||||
project.setStatus(update, remove)
|
||||
if self.statusPage.changed:
|
||||
project.data.itemStatus.update(self.statusPage.getNewList())
|
||||
rebuildTrees = True
|
||||
|
||||
if self.importPage.wasChanged:
|
||||
update, remove = self.importPage.getNewList()
|
||||
project.setImport(update, remove)
|
||||
if self.importPage.changed:
|
||||
project.data.itemImport.update(self.importPage.getNewList())
|
||||
rebuildTrees = True
|
||||
|
||||
if self.replacePage.wasChanged:
|
||||
update = self.replacePage.getNewList()
|
||||
project.data.setAutoReplace(update)
|
||||
if self.replacePage.changed:
|
||||
project.data.setAutoReplace(self.replacePage.getNewList())
|
||||
|
||||
self.newProjectSettingsReady.emit(rebuildTrees)
|
||||
QApplication.processEvents()
|
||||
@@ -327,7 +324,6 @@ class _StatusPage(NFixedPage):
|
||||
)
|
||||
|
||||
self._changed = False
|
||||
self._colDeleted: list[str] = []
|
||||
self._selColour = QColor(100, 100, 100)
|
||||
|
||||
self._iPx = SHARED.theme.baseIconHeight
|
||||
@@ -415,7 +411,7 @@ class _StatusPage(NFixedPage):
|
||||
return
|
||||
|
||||
@property
|
||||
def wasChanged(self) -> bool:
|
||||
def changed(self) -> bool:
|
||||
"""The user changed these settings."""
|
||||
return self._changed
|
||||
|
||||
@@ -423,7 +419,7 @@ class _StatusPage(NFixedPage):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def getNewList(self) -> tuple[list[tuple[str | None, StatusEntry]], list[str]]:
|
||||
def getNewList(self) -> list[tuple[str | None, StatusEntry]]:
|
||||
"""Return list of entries."""
|
||||
if self._changed:
|
||||
update = []
|
||||
@@ -432,8 +428,8 @@ class _StatusPage(NFixedPage):
|
||||
key = item.data(self.C_DATA, self.D_KEY)
|
||||
entry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
update.append((key, entry))
|
||||
return update, self._colDeleted
|
||||
return [], []
|
||||
return update
|
||||
return []
|
||||
|
||||
def columnWidth(self) -> int:
|
||||
"""Return the size of the header column."""
|
||||
@@ -478,7 +474,6 @@ class _StatusPage(NFixedPage):
|
||||
SHARED.error(self.tr("Cannot delete a status item that is in use."))
|
||||
else:
|
||||
self.listBox.takeTopLevelItem(iRow)
|
||||
self._colDeleted.append(item.data(self.C_DATA, self.D_KEY))
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@@ -543,24 +538,15 @@ class _StatusPage(NFixedPage):
|
||||
|
||||
def _moveItem(self, step: int) -> None:
|
||||
"""Move and item up or down step."""
|
||||
selItem = self._getSelectedItem()
|
||||
if selItem is None:
|
||||
return
|
||||
|
||||
tIndex = self.listBox.indexOfTopLevelItem(selItem)
|
||||
nChild = self.listBox.topLevelItemCount()
|
||||
nIndex = tIndex + step
|
||||
if nIndex < 0 or nIndex >= nChild:
|
||||
return
|
||||
|
||||
cItem = self.listBox.takeTopLevelItem(tIndex)
|
||||
self.listBox.insertTopLevelItem(nIndex, cItem)
|
||||
self.listBox.clearSelection()
|
||||
|
||||
if cItem is not None:
|
||||
cItem.setSelected(True)
|
||||
self._changed = True
|
||||
|
||||
if item := self._getSelectedItem():
|
||||
tIdx = self.listBox.indexOfTopLevelItem(item)
|
||||
nItm = self.listBox.topLevelItemCount()
|
||||
nIdx = tIdx + step
|
||||
if (0 <= nIdx < nItm) and (cItem := self.listBox.takeTopLevelItem(tIdx)):
|
||||
self.listBox.insertTopLevelItem(nIdx, cItem)
|
||||
self.listBox.clearSelection()
|
||||
cItem.setSelected(True)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def _getSelectedItem(self) -> QTreeWidgetItem | None:
|
||||
@@ -665,7 +651,7 @@ class _ReplacePage(NFixedPage):
|
||||
return
|
||||
|
||||
@property
|
||||
def wasChanged(self) -> bool:
|
||||
def changed(self) -> bool:
|
||||
"""The user changed these settings."""
|
||||
return self._changed
|
||||
|
||||
@@ -673,7 +659,7 @@ class _ReplacePage(NFixedPage):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def getNewList(self) -> dict:
|
||||
def getNewList(self) -> dict[str, str]:
|
||||
"""Extract the list from the widget."""
|
||||
new = {}
|
||||
for n in range(self.listBox.topLevelItemCount()):
|
||||
|
||||
Reference in New Issue
Block a user