Complete build initial tree and save tree logic

This commit is contained in:
Veronica Berglyd Olsen
2024-11-17 21:24:55 +01:00
parent cbe557507f
commit 27b3dde6f6
5 changed files with 121 additions and 34 deletions
+2
View File
@@ -256,6 +256,8 @@ class NWItem:
self._paraCount = 0 self._paraCount = 0
self._cursorPos = 0 self._cursorPos = 0
self._initCount = self._wordCount
return True return True
@classmethod @classmethod
+49 -12
View File
@@ -60,13 +60,17 @@ class ProjectNode:
def __init__(self, item: NWItem) -> None: def __init__(self, item: NWItem) -> None:
self._item = item self._item = item
self._children = [] self._children: list[ProjectNode] = []
self._parent: ProjectNode | None = None self._parent: ProjectNode | None = None
self._row = 0 self._row = 0
self._cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {} self._cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {}
self.refresh() self.refresh()
return return
@property
def item(self) -> NWItem:
return self._item
def refresh(self) -> None: def refresh(self) -> None:
cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {} cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {}
@@ -132,17 +136,38 @@ class ProjectNode:
self.refresh() self.refresh()
return return
def allChildren(self) -> list[ProjectNode]:
nodes: list[ProjectNode] = []
self._recursiveAppendChildren(nodes)
return nodes
##
# Internal Functions
##
def _recursiveAppendChildren(self, children: list[ProjectNode]) -> None:
for node in self._children:
children.append(node)
node._recursiveAppendChildren(children)
return
class ProjectModel(QAbstractItemModel): class ProjectModel(QAbstractItemModel):
__slots__ = ("_root", "_map")
def __init__(self, tree: NWTree) -> None: def __init__(self, tree: NWTree) -> None:
super().__init__(None) super().__init__(None)
self._root = ProjectNode(NWItem(tree._project, "")) self._root = ProjectNode(NWItem(tree._project, ""))
return return
def setRoot(self, root: ProjectNode) -> None: @property
self._root = root def root(self) -> ProjectNode:
return return self._root
##
# Model Access
##
def rowCount(self, index: QModelIndex) -> int: def rowCount(self, index: QModelIndex) -> int:
if index.isValid(): if index.isValid():
@@ -159,7 +184,7 @@ class ProjectModel(QAbstractItemModel):
return QModelIndex() return QModelIndex()
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex: def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
if parent and parent.isValid(): if parent.isValid():
item = parent.internalPointer() item = parent.internalPointer()
else: else:
item = self._root item = self._root
@@ -178,10 +203,22 @@ class ProjectModel(QAbstractItemModel):
node = index.internalPointer() node = index.internalPointer()
return node.data(index.column(), role) return node.data(index.column(), role)
def addChild(self, node: ProjectNode, parent: QModelIndex) -> None: # def addChild(self, node: ProjectNode, parent: QModelIndex) -> None:
if parent and parent.isValid(): # if parent.isValid():
item = parent.internalPointer() # item = parent.internalPointer()
else: # else:
item = self._root # item = self._root
item.addChild(node) # item.addChild(node)
return # return
##
# Methods
##
def allExpanded(self) -> list[QModelIndex]:
"""Return a list of all expanded items."""
expanded = []
for node in self._root.allChildren():
if node._item.isExpanded:
expanded.append(self.createIndex(node.row(), 0, node))
return expanded
+58 -21
View File
@@ -63,7 +63,10 @@ class NWTree:
also used for file names. also used for file names.
""" """
__slots__ = ("_project", "_tree", "_order", "_roots", "_model", "_nodes", "_trash", "_changed") __slots__ = (
"_project", "_tree", "_order", "_roots",
"_model", "_items", "_nodes", "_trash", "_changed",
)
def __init__(self, project: NWProject) -> None: def __init__(self, project: NWProject) -> None:
@@ -74,6 +77,7 @@ class NWTree:
self._roots: dict[str, NWItem] = {} # The root items of the tree self._roots: dict[str, NWItem] = {} # The root items of the tree
self._model = ProjectModel(self) self._model = ProjectModel(self)
self._items: dict[str, NWItem] = {}
self._nodes: dict[str, ProjectNode] = {} self._nodes: dict[str, ProjectNode] = {}
self._trash = None # The handle of the trash root folder self._trash = None # The handle of the trash root folder
@@ -103,6 +107,11 @@ class NWTree:
self._tree = {} self._tree = {}
self._order = [] self._order = []
self._roots = {} self._roots = {}
self._model = ProjectModel(self)
self._items = {}
self._nodes = {}
self._trash = None self._trash = None
self._changed = False self._changed = False
return return
@@ -185,12 +194,20 @@ class NWTree:
"""Pack the content of the tree into a list of dictionaries of """Pack the content of the tree into a list of dictionaries of
items. In the order defined by the _treeOrder list. items. In the order defined by the _treeOrder list.
""" """
tree = [] nodes = self._model.root.allChildren()
for tHandle in self._order: if len(nodes) != len(self._nodes):
tItem = self.__getitem__(tHandle) logger.warning(
if tItem: "Model tree is inconsitent with nodes map, %d != %d",
tree.append(tItem.pack()) len(nodes), len(self._nodes)
return tree )
# tree = []
# for tHandle in self._order:
# tItem = self.__getitem__(tHandle)
# if tItem:
# tree.append(tItem.pack())
return [node.item.pack() for node in nodes]
def unpack(self, data: list[dict]) -> None: def unpack(self, data: list[dict]) -> None:
"""Iterate through all items of a list and add them to the """Iterate through all items of a list and add them to the
@@ -200,31 +217,51 @@ class NWTree:
for item in data: for item in data:
nwItem = NWItem(self._project, "") # Handle is set by unpack() nwItem = NWItem(self._project, "") # Handle is set by unpack()
if nwItem.unpack(item): if nwItem.unpack(item):
self._items[nwItem.itemHandle] = nwItem
self.append(nwItem) self.append(nwItem)
nwItem.saveInitialCount()
return return
def buildModel(self) -> None: def buildModel(self) -> None:
"""""" """"""
root = ProjectNode(NWItem(self._project, ""))
for item in self._tree.values():
node = ProjectNode(item)
self._nodes[item.itemHandle] = node
if pHandle := item.itemParent:
if parent := self._nodes.get(pHandle):
parent.addChild(node)
else:
logger.error("Could not add item '%s'", item.itemHandle)
else:
root.addChild(node)
self._model.beginInsertRows(self._model.index(0, 0), 0, 0) self._model.beginInsertRows(self._model.index(0, 0), 0, 0)
self._model.setRoot(root) later: dict[str, NWItem] = self._items.copy()
for _ in range(999):
later = self._buildTree(later)
if len(later) == 0:
break
else:
logger.error("Not all items could be added to project tree")
for item in later.values():
item.setParent(None)
self._model.endInsertRows() self._model.endInsertRows()
self._model.layoutChanged.emit() self._model.layoutChanged.emit()
return return
def _buildTree(self, items: dict[str, NWItem]) -> dict[str, NWItem]:
""""""
remains: dict[str, NWItem] = {}
for handle, item in items.items():
if pHandle := item.itemParent:
if parent := self._nodes.get(pHandle):
node = ProjectNode(item)
parent.addChild(node)
self._nodes[handle] = node
elif pHandle in items:
remains[handle] = item
logger.warning("Item '%s' found before its parent", handle)
else:
item.setParent(None)
logger.error("Item '%s' has no parent in current tree", handle)
elif item.isRootType():
node = ProjectNode(item)
self._model.root.addChild(node)
self._nodes[handle] = node
return remains
def checkConsistency(self, prefix: str) -> tuple[int, int]: def checkConsistency(self, prefix: str) -> tuple[int, int]:
"""Check the project tree consistency. Also check the content """Check the project tree consistency. Also check the content
folder and add back files that were discovered but were not folder and add back files that were discovered but were not
+5
View File
@@ -535,6 +535,11 @@ class GuiProjectTree2(QTreeView):
treeHeader.resizeSection(self.C_ACTIVE, iPx + cMg) treeHeader.resizeSection(self.C_ACTIVE, iPx + cMg)
treeHeader.resizeSection(self.C_STATUS, iPx + cMg) treeHeader.resizeSection(self.C_STATUS, iPx + cMg)
self.blockSignals(True)
for index in SHARED.project.tree.model.allExpanded():
self.setExpanded(index, True)
self.blockSignals(False)
return return
+7 -1
View File
@@ -20,7 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations from __future__ import annotations
from PyQt5.QtGui import QPixmap from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import QWidget from PyQt5.QtWidgets import QWidget
@@ -73,6 +73,12 @@ class MockTheme:
def getPixmap(self, *a): def getPixmap(self, *a):
return QPixmap() return QPixmap()
def getIcon(self, *a) -> QIcon:
return QIcon()
def getItemIcon(self, *a, **k) -> QIcon:
return QIcon()
class MockApp: class MockApp: