Handle item consistency in the nodes tree
This commit is contained in:
@@ -45,7 +45,6 @@ COL_MASK = 0x0100
|
||||
|
||||
C_LABEL_TEXT = 0x0000 | Qt.ItemDataRole.DisplayRole
|
||||
C_LABEL_ICON = 0x0000 | Qt.ItemDataRole.DecorationRole
|
||||
C_LABEL_TIP = 0x0000 | Qt.ItemDataRole.ToolTipRole
|
||||
C_COUNT_TEXT = 0x0100 | Qt.ItemDataRole.DisplayRole
|
||||
C_COUNT_ICON = 0x0100 | Qt.ItemDataRole.DecorationRole
|
||||
C_COUNT_ALIGN = 0x0100 | Qt.ItemDataRole.TextAlignmentRole
|
||||
@@ -95,34 +94,31 @@ class ProjectNode:
|
||||
##
|
||||
|
||||
def refresh(self) -> None:
|
||||
cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {}
|
||||
|
||||
"""Refresh data values."""
|
||||
# Label
|
||||
cache[C_LABEL_ICON] = SHARED.theme.getItemIcon(
|
||||
self._cache[C_LABEL_ICON] = SHARED.theme.getItemIcon(
|
||||
self._item.itemType, self._item.itemClass,
|
||||
self._item.itemLayout, self._item.mainHeading
|
||||
)
|
||||
cache[C_LABEL_TEXT] = self._item.itemName
|
||||
cache[C_LABEL_TIP] = self._item.itemName
|
||||
self._cache[C_LABEL_TEXT] = self._item.itemName
|
||||
|
||||
# Count
|
||||
cache[C_COUNT_ALIGN] = QtAlignRight
|
||||
self._cache[C_COUNT_ALIGN] = QtAlignRight
|
||||
|
||||
# Active
|
||||
if self._item.isFileType():
|
||||
if self._item.isActive:
|
||||
cache[C_ACTIVE_ICON] = SHARED.theme.getIcon("checked")
|
||||
self._cache[C_ACTIVE_ICON] = SHARED.theme.getIcon("checked")
|
||||
else:
|
||||
cache[C_ACTIVE_ICON] = SHARED.theme.getIcon("unchecked")
|
||||
self._cache[C_ACTIVE_ICON] = SHARED.theme.getIcon("unchecked")
|
||||
else:
|
||||
cache[C_ACTIVE_ICON] = SHARED.theme.getIcon("noncheckable")
|
||||
self._cache[C_ACTIVE_ICON] = SHARED.theme.getIcon("noncheckable")
|
||||
|
||||
# Status
|
||||
sText, sIcon = self._item.getImportStatus()
|
||||
cache[C_STATUS_ICON] = sIcon
|
||||
cache[C_STATUS_TIP] = sText
|
||||
self._cache[C_STATUS_ICON] = sIcon
|
||||
self._cache[C_STATUS_TIP] = sText
|
||||
|
||||
self._cache = cache
|
||||
self.updateCount()
|
||||
|
||||
return
|
||||
@@ -145,7 +141,7 @@ class ProjectNode:
|
||||
return len(self._children)
|
||||
|
||||
def data(self, column: int, role: Qt.ItemDataRole) -> T_NodeData:
|
||||
""""""
|
||||
"""Return cached node data."""
|
||||
return self._cache.get(COL_MASK*column | role)
|
||||
|
||||
def parent(self) -> ProjectNode | None:
|
||||
@@ -157,6 +153,7 @@ class ProjectNode:
|
||||
return None
|
||||
|
||||
def allChildren(self) -> list[ProjectNode]:
|
||||
"""Return a recursive list of all children."""
|
||||
nodes: list[ProjectNode] = []
|
||||
self._recursiveAppendChildren(nodes)
|
||||
return nodes
|
||||
@@ -168,15 +165,24 @@ class ProjectNode:
|
||||
def addChild(self, child: ProjectNode, pos: int = -1) -> None:
|
||||
"""Add a child item to this item."""
|
||||
child._parent = self
|
||||
self._updateRelationships(child)
|
||||
if 0 <= pos < len(self._children):
|
||||
self._children.insert(pos, child)
|
||||
self._refreshChildrenPos()
|
||||
else:
|
||||
child._row = len(self._children)
|
||||
self._children.append(child)
|
||||
self.refresh()
|
||||
self.updateCount()
|
||||
return
|
||||
|
||||
def takeChild(self, pos: int) -> ProjectNode | None:
|
||||
"""Remove a child item and return it."""
|
||||
if 0 <= pos < len(self._children):
|
||||
node = self._children.pop()
|
||||
self._refreshChildrenPos()
|
||||
return node
|
||||
return None
|
||||
|
||||
def moveChild(self, source: int, target: int) -> None:
|
||||
"""Move a child internally."""
|
||||
count = len(self._children)
|
||||
@@ -203,6 +209,16 @@ class ProjectNode:
|
||||
child._row = n
|
||||
return
|
||||
|
||||
def _updateRelationships(self, child: ProjectNode) -> None:
|
||||
"""Update a child item's relationships."""
|
||||
if self._parent:
|
||||
child.item.setParent(self.item.itemHandle)
|
||||
child.item.setRoot(self.item.itemRoot)
|
||||
else:
|
||||
child.item.setParent(None)
|
||||
child.item.setRoot(child.item.itemHandle)
|
||||
return
|
||||
|
||||
|
||||
class ProjectModel(QAbstractItemModel):
|
||||
|
||||
|
||||
@@ -87,10 +87,10 @@ class NWTree:
|
||||
# Properties
|
||||
##
|
||||
|
||||
# @property
|
||||
# def trashRoot(self) -> str | None:
|
||||
# """Return the handle of the trash folder, or None."""
|
||||
# return self._trash
|
||||
@property
|
||||
def trash(self) -> ProjectNode | None:
|
||||
"""Return trash node, if it exists."""
|
||||
return self._getTrashNode()
|
||||
|
||||
@property
|
||||
def model(self) -> ProjectModel:
|
||||
@@ -158,7 +158,6 @@ class NWTree:
|
||||
nwItem.setType(itemType)
|
||||
nwItem.setClass(itemClass)
|
||||
if self.add(nwItem, pos):
|
||||
self.updateItemData(tHandle)
|
||||
self._project.setProjectChanged(True)
|
||||
return tHandle
|
||||
return None
|
||||
@@ -238,23 +237,15 @@ class NWTree:
|
||||
mark recovered files.
|
||||
"""
|
||||
storage = self._project.storage
|
||||
files = set(storage.scanContent())
|
||||
for tHandle in self._nodes:
|
||||
if self.updateItemData(tHandle):
|
||||
logger.debug("Checking item '%s' ... OK", tHandle)
|
||||
files.discard(tHandle) # Remove it from the record
|
||||
else:
|
||||
logger.error("Checking item '%s' ... ERROR", tHandle)
|
||||
self.__delitem__(tHandle) # The file will be re-added as orphaned
|
||||
|
||||
orphans = len(files)
|
||||
remains = set(storage.scanContent()).difference(set(self._nodes.keys()))
|
||||
orphans = len(remains)
|
||||
if orphans == 0:
|
||||
logger.info("Checked project files: OK")
|
||||
return 0, 0
|
||||
|
||||
logger.warning("Found %d file(s) not tracked in project", orphans)
|
||||
recovered = 0
|
||||
for cHandle in files:
|
||||
for cHandle in remains:
|
||||
aDoc = storage.getDocument(cHandle)
|
||||
aDoc.readDocument(isOrphan=True)
|
||||
oName, oParent, oClass, oLayout = aDoc.getMeta()
|
||||
@@ -282,7 +273,6 @@ class NWTree:
|
||||
newItem.setClass(oClass)
|
||||
newItem.setLayout(oLayout)
|
||||
if self.add(newItem):
|
||||
self.updateItemData(cHandle)
|
||||
recovered += 1
|
||||
|
||||
return orphans, recovered
|
||||
@@ -346,25 +336,6 @@ class NWTree:
|
||||
# Tree Item Methods
|
||||
##
|
||||
|
||||
def updateItemData(self, tHandle: str) -> bool:
|
||||
"""Update the root item handle of a given item. Returns True if
|
||||
a root was found and data updated, otherwise False.
|
||||
"""
|
||||
if tItem := self._items.get(tHandle):
|
||||
iItem = tItem
|
||||
for _ in range(MAX_DEPTH):
|
||||
if iItem.itemParent is None:
|
||||
tItem.setRoot(iItem.itemHandle)
|
||||
tItem.setClassDefaults(iItem.itemClass)
|
||||
return True
|
||||
else:
|
||||
iItem = self.__getitem__(iItem.itemParent)
|
||||
if iItem is None:
|
||||
return False
|
||||
else:
|
||||
raise RecursionError("Critical internal error")
|
||||
return False
|
||||
|
||||
def checkType(self, tHandle: str, itemType: nwItemType) -> bool:
|
||||
"""Check if item exists and is of the specified item type."""
|
||||
tItem = self.__getitem__(tHandle)
|
||||
@@ -515,8 +486,6 @@ class NWTree:
|
||||
elif pHandle in items:
|
||||
remains[handle] = item
|
||||
logger.warning("Item '%s' found before its parent", handle)
|
||||
else:
|
||||
logger.error("Item '%s' has no parent in current tree", handle)
|
||||
elif item.isRootType():
|
||||
node = ProjectNode(item)
|
||||
self._model.root.addChild(node)
|
||||
|
||||
Reference in New Issue
Block a user