Complete build initial tree and save tree logic
This commit is contained in:
@@ -256,6 +256,8 @@ class NWItem:
|
||||
self._paraCount = 0
|
||||
self._cursorPos = 0
|
||||
|
||||
self._initCount = self._wordCount
|
||||
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -60,13 +60,17 @@ class ProjectNode:
|
||||
|
||||
def __init__(self, item: NWItem) -> None:
|
||||
self._item = item
|
||||
self._children = []
|
||||
self._children: list[ProjectNode] = []
|
||||
self._parent: ProjectNode | None = None
|
||||
self._row = 0
|
||||
self._cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {}
|
||||
self.refresh()
|
||||
return
|
||||
|
||||
@property
|
||||
def item(self) -> NWItem:
|
||||
return self._item
|
||||
|
||||
def refresh(self) -> None:
|
||||
cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {}
|
||||
|
||||
@@ -132,17 +136,38 @@ class ProjectNode:
|
||||
self.refresh()
|
||||
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):
|
||||
|
||||
__slots__ = ("_root", "_map")
|
||||
|
||||
def __init__(self, tree: NWTree) -> None:
|
||||
super().__init__(None)
|
||||
self._root = ProjectNode(NWItem(tree._project, ""))
|
||||
return
|
||||
|
||||
def setRoot(self, root: ProjectNode) -> None:
|
||||
self._root = root
|
||||
return
|
||||
@property
|
||||
def root(self) -> ProjectNode:
|
||||
return self._root
|
||||
|
||||
##
|
||||
# Model Access
|
||||
##
|
||||
|
||||
def rowCount(self, index: QModelIndex) -> int:
|
||||
if index.isValid():
|
||||
@@ -159,7 +184,7 @@ class ProjectModel(QAbstractItemModel):
|
||||
return QModelIndex()
|
||||
|
||||
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
|
||||
if parent and parent.isValid():
|
||||
if parent.isValid():
|
||||
item = parent.internalPointer()
|
||||
else:
|
||||
item = self._root
|
||||
@@ -178,10 +203,22 @@ class ProjectModel(QAbstractItemModel):
|
||||
node = index.internalPointer()
|
||||
return node.data(index.column(), role)
|
||||
|
||||
def addChild(self, node: ProjectNode, parent: QModelIndex) -> None:
|
||||
if parent and parent.isValid():
|
||||
item = parent.internalPointer()
|
||||
else:
|
||||
item = self._root
|
||||
item.addChild(node)
|
||||
return
|
||||
# def addChild(self, node: ProjectNode, parent: QModelIndex) -> None:
|
||||
# if parent.isValid():
|
||||
# item = parent.internalPointer()
|
||||
# else:
|
||||
# item = self._root
|
||||
# item.addChild(node)
|
||||
# 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
@@ -63,7 +63,10 @@ class NWTree:
|
||||
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:
|
||||
|
||||
@@ -74,6 +77,7 @@ class NWTree:
|
||||
self._roots: dict[str, NWItem] = {} # The root items of the tree
|
||||
|
||||
self._model = ProjectModel(self)
|
||||
self._items: dict[str, NWItem] = {}
|
||||
self._nodes: dict[str, ProjectNode] = {}
|
||||
|
||||
self._trash = None # The handle of the trash root folder
|
||||
@@ -103,6 +107,11 @@ class NWTree:
|
||||
self._tree = {}
|
||||
self._order = []
|
||||
self._roots = {}
|
||||
|
||||
self._model = ProjectModel(self)
|
||||
self._items = {}
|
||||
self._nodes = {}
|
||||
|
||||
self._trash = None
|
||||
self._changed = False
|
||||
return
|
||||
@@ -185,12 +194,20 @@ class NWTree:
|
||||
"""Pack the content of the tree into a list of dictionaries of
|
||||
items. In the order defined by the _treeOrder list.
|
||||
"""
|
||||
tree = []
|
||||
for tHandle in self._order:
|
||||
tItem = self.__getitem__(tHandle)
|
||||
if tItem:
|
||||
tree.append(tItem.pack())
|
||||
return tree
|
||||
nodes = self._model.root.allChildren()
|
||||
if len(nodes) != len(self._nodes):
|
||||
logger.warning(
|
||||
"Model tree is inconsitent with nodes map, %d != %d",
|
||||
len(nodes), len(self._nodes)
|
||||
)
|
||||
|
||||
# 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:
|
||||
"""Iterate through all items of a list and add them to the
|
||||
@@ -200,31 +217,51 @@ class NWTree:
|
||||
for item in data:
|
||||
nwItem = NWItem(self._project, "") # Handle is set by unpack()
|
||||
if nwItem.unpack(item):
|
||||
self._items[nwItem.itemHandle] = nwItem
|
||||
self.append(nwItem)
|
||||
nwItem.saveInitialCount()
|
||||
|
||||
return
|
||||
|
||||
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.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.layoutChanged.emit()
|
||||
|
||||
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]:
|
||||
"""Check the project tree consistency. Also check the content
|
||||
folder and add back files that were discovered but were not
|
||||
|
||||
@@ -535,6 +535,11 @@ class GuiProjectTree2(QTreeView):
|
||||
treeHeader.resizeSection(self.C_ACTIVE, 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
|
||||
|
||||
|
||||
|
||||
+7
-1
@@ -20,7 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtGui import QIcon, QPixmap
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
|
||||
@@ -73,6 +73,12 @@ class MockTheme:
|
||||
def getPixmap(self, *a):
|
||||
return QPixmap()
|
||||
|
||||
def getIcon(self, *a) -> QIcon:
|
||||
return QIcon()
|
||||
|
||||
def getItemIcon(self, *a, **k) -> QIcon:
|
||||
return QIcon()
|
||||
|
||||
|
||||
class MockApp:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user