diff --git a/novelwriter/core/itemmodel.py b/novelwriter/core/itemmodel.py index 67253897..c88bd0da 100644 --- a/novelwriter/core/itemmodel.py +++ b/novelwriter/core/itemmodel.py @@ -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): diff --git a/novelwriter/core/tree.py b/novelwriter/core/tree.py index d159e383..d6d3a082 100644 --- a/novelwriter/core/tree.py +++ b/novelwriter/core/tree.py @@ -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) diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index adcaad09..637703bd 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -39,12 +39,11 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG, SHARED from novelwriter.common import qtLambda -from novelwriter.constants import nwLabels, nwStyles, nwUnicode, trConst +from novelwriter.constants import nwLabels, nwStyles, trConst from novelwriter.core.item import NWItem from novelwriter.core.itemmodel import ProjectModel, ProjectNode from novelwriter.dialogs.editlabel import GuiEditLabel -from novelwriter.dialogs.projectsettings import GuiProjectSettings -from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType +from novelwriter.enum import nwDocMode, nwItemClass, nwItemType from novelwriter.extensions.modified import NIconToolButton from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON from novelwriter.types import ( @@ -526,7 +525,6 @@ class GuiProjectTree(QTreeView): # Tree Settings iPx = SHARED.theme.baseIconHeight - # cMg = CONFIG.pxInt(6) self.setIconSize(SHARED.theme.baseIconSize) self.setFrameStyle(QFrame.Shape.NoFrame) @@ -536,18 +534,6 @@ class GuiProjectTree(QTreeView): self.setAutoExpandDelay(1000) self.setHeaderHidden(True) self.setIndentation(iPx) - # self.setColumnCount(4) - - # Lock the column sizes - # treeHeader = self.header() - # treeHeader.setStretchLastSection(False) - # treeHeader.setMinimumSectionSize(iPx + cMg) - # treeHeader.setSectionResizeMode(self.C_NAME, QHeaderView.ResizeMode.Stretch) - # treeHeader.setSectionResizeMode(self.C_COUNT, QHeaderView.ResizeMode.ResizeToContents) - # treeHeader.setSectionResizeMode(self.C_ACTIVE, QHeaderView.ResizeMode.Fixed) - # treeHeader.setSectionResizeMode(self.C_STATUS, QHeaderView.ResizeMode.Fixed) - # treeHeader.resizeSection(self.C_ACTIVE, iPx + cMg) - # treeHeader.resizeSection(self.C_STATUS, iPx + cMg) # Allow Move by Drag & Drop # self.setDragEnabled(True) @@ -732,13 +718,15 @@ class GuiProjectTree(QTreeView): if dlgOk: # Add the file or folder if itemType == nwItemType.FILE: - tHandle = SHARED.project.newFile(newLabel, sHandle, pos) - if tHandle and copyDoc: - SHARED.project.copyFileContent(tHandle, copyDoc) - elif tHandle and hLevel > 0: - SHARED.project.writeNewFile(tHandle, hLevel, not isNote) + if tHandle := SHARED.project.newFile(newLabel, sHandle, pos): + if copyDoc: + SHARED.project.copyFileContent(tHandle, copyDoc) + elif hLevel > 0: + SHARED.project.writeNewFile(tHandle, hLevel, not isNote) + SHARED.project.index.reIndexHandle(tHandle) + SHARED.project.tree.refreshItems([tHandle]) else: - tHandle = SHARED.project.newFolder(newLabel, sHandle, pos) + SHARED.project.newFolder(newLabel, sHandle, pos) return @@ -876,41 +864,6 @@ class GuiProjectTree(QTreeView): # self.revealNewTreeItem(tHandle, wordCount=True) return - def revealNewTreeItem(self, tHandle: str | None, nHandle: str | None = None, - wordCount: bool = False) -> bool: - """Reveal a newly added project item in the project tree.""" - # nwItem = SHARED.project.tree[tHandle] if tHandle else None - # if tHandle is None or nwItem is None: - # return False - - # trItem = self._addTreeItem(nwItem, nHandle) - # if trItem is None: - # return False - - # if nwItem.isFileType() and wordCount: - # wC = SHARED.project.index.getCounts(tHandle)[1] - # self.propagateCount(tHandle, wC) - # self.projView.wordCountsChanged.emit() - - # pHandle = nwItem.itemParent - # if pHandle is not None and pHandle in self._treeMap: - # self._treeMap[pHandle].setExpanded(True) - - # self._alertTreeChange(tHandle, flush=True) - # self.setCurrentItem(trItem) - - return True - - def getTreeFromHandle(self, tHandle: str) -> list[str]: - """Recursively return all the child items starting from a given - item handle. - """ - result = [] - # tIten = self._getTreeItem(tHandle) - # if tIten is not None: - # result = self._scanChildren(result, tIten, 0) - return result - def requestDeleteItem(self, tHandle: str | None = None) -> bool: """Request an item deleted from the project tree. This function can be called on any item, and will check whether to attempt a @@ -1768,358 +1721,358 @@ class _UpdatableMenu(QMenu): return -class _TreeContextMenu(QMenu): +# class _TreeContextMenu(QMenu): - def __init__(self, projTree: GuiProjectTree, nwItem: NWItem) -> None: - super().__init__(parent=projTree) +# def __init__(self, projTree: GuiProjectTree, nwItem: NWItem) -> None: +# super().__init__(parent=projTree) - self.projTree = projTree - self.projView = projTree.projView +# self.projTree = projTree +# self.projView = projTree.projView - self._item = nwItem - self._handle = nwItem.itemHandle - self._items: list[NWItem] = [] +# self._item = nwItem +# self._handle = nwItem.itemHandle +# self._items: list[NWItem] = [] - logger.debug("Ready: _TreeContextMenu") +# logger.debug("Ready: _TreeContextMenu") - return +# return - def __del__(self) -> None: # pragma: no cover - logger.debug("Delete: _TreeContextMenu") - return +# def __del__(self) -> None: # pragma: no cover +# logger.debug("Delete: _TreeContextMenu") +# return - ## - # Methods - ## +# ## +# # Methods +# ## - def buildTrashMenu(self) -> None: - """Build the special menu for the Trash folder.""" - action = self.addAction(self.tr("Empty Trash")) - action.triggered.connect(self.projTree.emptyTrash) - return +# def buildTrashMenu(self) -> None: +# """Build the special menu for the Trash folder.""" +# action = self.addAction(self.tr("Empty Trash")) +# action.triggered.connect(self.projTree.emptyTrash) +# return - def buildSingleSelectMenu(self, hasChild: bool) -> None: - """Build the single-select menu.""" - isFile = self._item.isFileType() - isFolder = self._item.isFolderType() - isRoot = self._item.isRootType() +# def buildSingleSelectMenu(self, hasChild: bool) -> None: +# """Build the single-select menu.""" +# isFile = self._item.isFileType() +# isFolder = self._item.isFolderType() +# isRoot = self._item.isRootType() - # Document Actions - if isFile: - self._docActions() - self.addSeparator() +# # Document Actions +# if isFile: +# self._docActions() +# self.addSeparator() - # Create New Items - self._itemCreation() - self.addSeparator() +# # Create New Items +# self._itemCreation() +# self.addSeparator() - # Edit Item Settings - action = self.addAction(self.tr("Rename")) - action.triggered.connect(qtLambda(self.projView.renameTreeItem, self._handle)) - if isFile: - self._itemHeader() - self._itemActive(False) - self._itemStatusImport(False) +# # Edit Item Settings +# action = self.addAction(self.tr("Rename")) +# action.triggered.connect(qtLambda(self.projView.renameTreeItem, self._handle)) +# if isFile: +# self._itemHeader() +# self._itemActive(False) +# self._itemStatusImport(False) - # Transform Item - if isFile or isFolder: - self._itemTransform(isFile, isFolder, hasChild) - self.addSeparator() +# # Transform Item +# if isFile or isFolder: +# self._itemTransform(isFile, isFolder, hasChild) +# self.addSeparator() - # Process Item - self._itemProcess(isFile, isFolder, isRoot, hasChild) +# # Process Item +# self._itemProcess(isFile, isFolder, isRoot, hasChild) - return +# return - def buildMultiSelectMenu(self, handles: list[str]) -> None: - """Build the multi-select menu.""" - self._items = [] - for tHandle in handles: - if (tItem := SHARED.project.tree[tHandle]): - self._items.append(tItem) +# def buildMultiSelectMenu(self, handles: list[str]) -> None: +# """Build the multi-select menu.""" +# self._items = [] +# for tHandle in handles: +# if (tItem := SHARED.project.tree[tHandle]): +# self._items.append(tItem) - self._itemActive(True) - self._itemStatusImport(True) - self.addSeparator() - self._multiMoveToTrash() - return +# self._itemActive(True) +# self._itemStatusImport(True) +# self.addSeparator() +# self._multiMoveToTrash() +# return - ## - # Menu Builders - ## +# ## +# # Menu Builders +# ## - def _docActions(self) -> None: - """Add document actions.""" - action = self.addAction(self.tr("Open Document")) - action.triggered.connect(qtLambda( - self.projView.openDocumentRequest.emit, - self._handle, nwDocMode.EDIT, "", True - )) - action = self.addAction(self.tr("View Document")) - action.triggered.connect(qtLambda( - self.projView.openDocumentRequest.emit, - self._handle, nwDocMode.VIEW, "", False - )) - return +# def _docActions(self) -> None: +# """Add document actions.""" +# action = self.addAction(self.tr("Open Document")) +# action.triggered.connect(qtLambda( +# self.projView.openDocumentRequest.emit, +# self._handle, nwDocMode.EDIT, "", True +# )) +# action = self.addAction(self.tr("View Document")) +# action.triggered.connect(qtLambda( +# self.projView.openDocumentRequest.emit, +# self._handle, nwDocMode.VIEW, "", False +# )) +# return - def _itemCreation(self) -> None: - """Add create item actions.""" - menu = self.addMenu(self.tr("Create New ...")) - menu.addAction(self.projView.projBar.aAddEmpty) - menu.addAction(self.projView.projBar.aAddChap) - menu.addAction(self.projView.projBar.aAddScene) - menu.addAction(self.projView.projBar.aAddNote) - menu.addAction(self.projView.projBar.aAddFolder) - return +# def _itemCreation(self) -> None: +# """Add create item actions.""" +# menu = self.addMenu(self.tr("Create New ...")) +# menu.addAction(self.projView.projBar.aAddEmpty) +# menu.addAction(self.projView.projBar.aAddChap) +# menu.addAction(self.projView.projBar.aAddScene) +# menu.addAction(self.projView.projBar.aAddNote) +# menu.addAction(self.projView.projBar.aAddFolder) +# return - def _itemHeader(self) -> None: - """Check if there is a header that can be used for rename.""" - SHARED.saveEditor() - if hItem := SHARED.project.index.getItemHeading(self._handle, "T0001"): - action = self.addAction(self.tr("Rename to Heading")) - action.triggered.connect( - qtLambda(self.projView.renameTreeItem, self._handle, hItem.title) - ) - return +# def _itemHeader(self) -> None: +# """Check if there is a header that can be used for rename.""" +# SHARED.saveEditor() +# if hItem := SHARED.project.index.getItemHeading(self._handle, "T0001"): +# action = self.addAction(self.tr("Rename to Heading")) +# action.triggered.connect( +# qtLambda(self.projView.renameTreeItem, self._handle, hItem.title) +# ) +# return - def _itemActive(self, multi: bool) -> None: - """Add Active/Inactive actions.""" - if multi: - mSub = self.addMenu(self.tr("Set Active to ...")) - aOne = mSub.addAction(SHARED.theme.getIcon("checked"), self.projTree.trActive) - aOne.triggered.connect(qtLambda(self._iterItemActive, True)) - aTwo = mSub.addAction(SHARED.theme.getIcon("unchecked"), self.projTree.trInactive) - aTwo.triggered.connect(qtLambda(self._iterItemActive, False)) - else: - action = self.addAction(self.tr("Toggle Active")) - action.triggered.connect(self._toggleItemActive) - return +# def _itemActive(self, multi: bool) -> None: +# """Add Active/Inactive actions.""" +# if multi: +# mSub = self.addMenu(self.tr("Set Active to ...")) +# aOne = mSub.addAction(SHARED.theme.getIcon("checked"), self.projTree.trActive) +# aOne.triggered.connect(qtLambda(self._iterItemActive, True)) +# aTwo = mSub.addAction(SHARED.theme.getIcon("unchecked"), self.projTree.trInactive) +# aTwo.triggered.connect(qtLambda(self._iterItemActive, False)) +# else: +# action = self.addAction(self.tr("Toggle Active")) +# action.triggered.connect(self._toggleItemActive) +# return - def _itemStatusImport(self, multi: bool) -> None: - """Add actions for changing status or importance.""" - if self._item.isNovelLike(): - menu = self.addMenu(self.tr("Set Status to ...")) - current = self._item.itemStatus - for key, entry in SHARED.project.data.itemStatus.iterItems(): - name = entry.name - if not multi and current == key: - name += f" ({nwUnicode.U_CHECK})" - action = menu.addAction(entry.icon, name) - if multi: - action.triggered.connect(qtLambda(self._iterSetItemStatus, key)) - else: - action.triggered.connect(qtLambda(self._changeItemStatus, key)) - menu.addSeparator() - action = menu.addAction(self.tr("Manage Labels ...")) - action.triggered.connect(qtLambda( - self.projView.projectSettingsRequest.emit, - GuiProjectSettings.PAGE_STATUS - )) - else: - menu = self.addMenu(self.tr("Set Importance to ...")) - current = self._item.itemImport - for key, entry in SHARED.project.data.itemImport.iterItems(): - name = entry.name - if not multi and current == key: - name += f" ({nwUnicode.U_CHECK})" - action = menu.addAction(entry.icon, name) - if multi: - action.triggered.connect(qtLambda(self._iterSetItemImport, key)) - else: - action.triggered.connect(qtLambda(self._changeItemImport, key)) - menu.addSeparator() - action = menu.addAction(self.tr("Manage Labels ...")) - action.triggered.connect(qtLambda( - self.projView.projectSettingsRequest.emit, - GuiProjectSettings.PAGE_IMPORT - )) - return +# def _itemStatusImport(self, multi: bool) -> None: +# """Add actions for changing status or importance.""" +# if self._item.isNovelLike(): +# menu = self.addMenu(self.tr("Set Status to ...")) +# current = self._item.itemStatus +# for key, entry in SHARED.project.data.itemStatus.iterItems(): +# name = entry.name +# if not multi and current == key: +# name += f" ({nwUnicode.U_CHECK})" +# action = menu.addAction(entry.icon, name) +# if multi: +# action.triggered.connect(qtLambda(self._iterSetItemStatus, key)) +# else: +# action.triggered.connect(qtLambda(self._changeItemStatus, key)) +# menu.addSeparator() +# action = menu.addAction(self.tr("Manage Labels ...")) +# action.triggered.connect(qtLambda( +# self.projView.projectSettingsRequest.emit, +# GuiProjectSettings.PAGE_STATUS +# )) +# else: +# menu = self.addMenu(self.tr("Set Importance to ...")) +# current = self._item.itemImport +# for key, entry in SHARED.project.data.itemImport.iterItems(): +# name = entry.name +# if not multi and current == key: +# name += f" ({nwUnicode.U_CHECK})" +# action = menu.addAction(entry.icon, name) +# if multi: +# action.triggered.connect(qtLambda(self._iterSetItemImport, key)) +# else: +# action.triggered.connect(qtLambda(self._changeItemImport, key)) +# menu.addSeparator() +# action = menu.addAction(self.tr("Manage Labels ...")) +# action.triggered.connect(qtLambda( +# self.projView.projectSettingsRequest.emit, +# GuiProjectSettings.PAGE_IMPORT +# )) +# return - def _itemTransform(self, isFile: bool, isFolder: bool, hasChild: bool) -> None: - """Add actions for the Transform menu.""" - menu = self.addMenu(self.tr("Transform ...")) +# def _itemTransform(self, isFile: bool, isFolder: bool, hasChild: bool) -> None: +# """Add actions for the Transform menu.""" +# menu = self.addMenu(self.tr("Transform ...")) - tree = self.projTree - tHandle = self._handle +# tree = self.projTree +# tHandle = self._handle - trDoc = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT]) - trNote = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE]) - loDoc = nwItemLayout.DOCUMENT - loNote = nwItemLayout.NOTE - isDocFile = isFile and self._item.isDocumentLayout() - isNoteFile = isFile and self._item.isNoteLayout() +# trDoc = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT]) +# trNote = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE]) +# loDoc = nwItemLayout.DOCUMENT +# loNote = nwItemLayout.NOTE +# isDocFile = isFile and self._item.isDocumentLayout() +# isNoteFile = isFile and self._item.isNoteLayout() - if isNoteFile and self._item.documentAllowed(): - action = menu.addAction(self.tr("Convert to {0}").format(trDoc)) - action.triggered.connect(qtLambda(self._changeItemLayout, loDoc)) +# if isNoteFile and self._item.documentAllowed(): +# action = menu.addAction(self.tr("Convert to {0}").format(trDoc)) +# action.triggered.connect(qtLambda(self._changeItemLayout, loDoc)) - if isDocFile: - action = menu.addAction(self.tr("Convert to {0}").format(trNote)) - action.triggered.connect(qtLambda(self._changeItemLayout, loNote)) +# if isDocFile: +# action = menu.addAction(self.tr("Convert to {0}").format(trNote)) +# action.triggered.connect(qtLambda(self._changeItemLayout, loNote)) - if isFolder and self._item.documentAllowed(): - action = menu.addAction(self.tr("Convert to {0}").format(trDoc)) - action.triggered.connect(qtLambda(self._covertFolderToFile, loDoc)) +# if isFolder and self._item.documentAllowed(): +# action = menu.addAction(self.tr("Convert to {0}").format(trDoc)) +# action.triggered.connect(qtLambda(self._covertFolderToFile, loDoc)) - if isFolder: - action = menu.addAction(self.tr("Convert to {0}").format(trNote)) - action.triggered.connect(qtLambda(self._covertFolderToFile, loNote)) +# if isFolder: +# action = menu.addAction(self.tr("Convert to {0}").format(trNote)) +# action.triggered.connect(qtLambda(self._covertFolderToFile, loNote)) - if hasChild and isFile: - action = menu.addAction(self.tr("Merge Child Items into Self")) - action.triggered.connect(qtLambda(tree._mergeDocuments, tHandle, False)) - action = menu.addAction(self.tr("Merge Child Items into New")) - action.triggered.connect(qtLambda(tree._mergeDocuments, tHandle, True)) +# if hasChild and isFile: +# action = menu.addAction(self.tr("Merge Child Items into Self")) +# action.triggered.connect(qtLambda(tree._mergeDocuments, tHandle, False)) +# action = menu.addAction(self.tr("Merge Child Items into New")) +# action.triggered.connect(qtLambda(tree._mergeDocuments, tHandle, True)) - if hasChild and isFolder: - action = menu.addAction(self.tr("Merge Documents in Folder")) - action.triggered.connect(qtLambda(tree._mergeDocuments, tHandle, True)) +# if hasChild and isFolder: +# action = menu.addAction(self.tr("Merge Documents in Folder")) +# action.triggered.connect(qtLambda(tree._mergeDocuments, tHandle, True)) - if isFile: - action = menu.addAction(self.tr("Split Document by Headings")) - action.triggered.connect(qtLambda(tree._splitDocument, tHandle)) +# if isFile: +# action = menu.addAction(self.tr("Split Document by Headings")) +# action.triggered.connect(qtLambda(tree._splitDocument, tHandle)) - return +# return - def _itemProcess(self, isFile: bool, isFolder: bool, isRoot: bool, hasChild: bool) -> None: - """Add actions for item processing.""" - tree = self.projTree - tHandle = self._handle - if hasChild: - action = self.addAction(self.tr("Expand All")) - action.triggered.connect(qtLambda(tree.setExpandedFromHandle, tHandle, True)) - action = self.addAction(self.tr("Collapse All")) - action.triggered.connect(qtLambda(tree.setExpandedFromHandle, tHandle, False)) +# def _itemProcess(self, isFile: bool, isFolder: bool, isRoot: bool, hasChild: bool) -> None: +# """Add actions for item processing.""" +# tree = self.projTree +# tHandle = self._handle +# if hasChild: +# action = self.addAction(self.tr("Expand All")) +# action.triggered.connect(qtLambda(tree.setExpandedFromHandle, tHandle, True)) +# action = self.addAction(self.tr("Collapse All")) +# action.triggered.connect(qtLambda(tree.setExpandedFromHandle, tHandle, False)) - action = self.addAction(self.tr("Duplicate")) - action.triggered.connect(qtLambda(tree._duplicateFromHandle, tHandle)) +# action = self.addAction(self.tr("Duplicate")) +# action.triggered.connect(qtLambda(tree._duplicateFromHandle, tHandle)) - if self._item.itemClass == nwItemClass.TRASH or isRoot or (isFolder and not hasChild): - action = self.addAction(self.tr("Delete Permanently")) - action.triggered.connect(qtLambda(tree.permDeleteItem, tHandle)) - else: - action = self.addAction(self.tr("Move to Trash")) - action.triggered.connect(qtLambda(tree.moveItemToTrash, tHandle)) +# if self._item.itemClass == nwItemClass.TRASH or isRoot or (isFolder and not hasChild): +# action = self.addAction(self.tr("Delete Permanently")) +# action.triggered.connect(qtLambda(tree.permDeleteItem, tHandle)) +# else: +# action = self.addAction(self.tr("Move to Trash")) +# action.triggered.connect(qtLambda(tree.moveItemToTrash, tHandle)) - return +# return - def _multiMoveToTrash(self) -> None: - """Add move to Trash action.""" - areTrash = [i.itemClass == nwItemClass.TRASH for i in self._items] - if all(areTrash): - action = self.addAction(self.tr("Delete Permanently")) - action.triggered.connect(self._iterPermDelete) - elif not any(areTrash): - action = self.addAction(self.tr("Move to Trash")) - action.triggered.connect(self._iterMoveToTrash) - return +# def _multiMoveToTrash(self) -> None: +# """Add move to Trash action.""" +# areTrash = [i.itemClass == nwItemClass.TRASH for i in self._items] +# if all(areTrash): +# action = self.addAction(self.tr("Delete Permanently")) +# action.triggered.connect(self._iterPermDelete) +# elif not any(areTrash): +# action = self.addAction(self.tr("Move to Trash")) +# action.triggered.connect(self._iterMoveToTrash) +# return - ## - # Private Slots - ## +# ## +# # Private Slots +# ## - @pyqtSlot() - def _iterMoveToTrash(self) -> None: - """Iterate through files and move them to Trash.""" - if SHARED.question(self.tr("Move {0} items to Trash?").format(len(self._items))): - for tItem in self._items: - if tItem.isFileType() and tItem.itemClass != nwItemClass.TRASH: - self.projTree.moveItemToTrash(tItem.itemHandle, askFirst=False, flush=False) - # self.projTree.saveTreeOrder() - return +# @pyqtSlot() +# def _iterMoveToTrash(self) -> None: +# """Iterate through files and move them to Trash.""" +# if SHARED.question(self.tr("Move {0} items to Trash?").format(len(self._items))): +# for tItem in self._items: +# if tItem.isFileType() and tItem.itemClass != nwItemClass.TRASH: +# self.projTree.moveItemToTrash(tItem.itemHandle, askFirst=False, flush=False) +# # self.projTree.saveTreeOrder() +# return - @pyqtSlot() - def _iterPermDelete(self) -> None: - """Iterate through files and delete them.""" - if SHARED.question(self.projTree.trPermDelete.format(len(self._items))): - for tItem in self._items: - if tItem.isFileType() and tItem.itemClass == nwItemClass.TRASH: - self.projTree.permDeleteItem(tItem.itemHandle, askFirst=False, flush=False) - # self.projTree.saveTreeOrder() - return +# @pyqtSlot() +# def _iterPermDelete(self) -> None: +# """Iterate through files and delete them.""" +# if SHARED.question(self.projTree.trPermDelete.format(len(self._items))): +# for tItem in self._items: +# if tItem.isFileType() and tItem.itemClass == nwItemClass.TRASH: +# self.projTree.permDeleteItem(tItem.itemHandle, askFirst=False, flush=False) +# # self.projTree.saveTreeOrder() +# return - @pyqtSlot() - def _toggleItemActive(self) -> None: - """Toggle the active status of an item.""" - self._item.setActive(not self._item.isActive) - self.projTree.setTreeItemValues(self._item) - self.projTree._alertTreeChange(self._handle, flush=False) - return +# @pyqtSlot() +# def _toggleItemActive(self) -> None: +# """Toggle the active status of an item.""" +# self._item.setActive(not self._item.isActive) +# self.projTree.setTreeItemValues(self._item) +# self.projTree._alertTreeChange(self._handle, flush=False) +# return - ## - # Internal Functions - ## +# ## +# # Internal Functions +# ## - def _iterItemActive(self, isActive: bool) -> None: - """Set the active status of multiple items.""" - for tItem in self._items: - if tItem and tItem.isFileType(): - tItem.setActive(isActive) - self.projTree.setTreeItemValues(tItem) - self.projTree._alertTreeChange(tItem.itemHandle, flush=False) - return +# def _iterItemActive(self, isActive: bool) -> None: +# """Set the active status of multiple items.""" +# for tItem in self._items: +# if tItem and tItem.isFileType(): +# tItem.setActive(isActive) +# self.projTree.setTreeItemValues(tItem) +# self.projTree._alertTreeChange(tItem.itemHandle, flush=False) +# return - def _changeItemStatus(self, key: str) -> None: - """Set a new status value of an item.""" - self._item.setStatus(key) - self.projTree.setTreeItemValues(self._item) - self.projTree._alertTreeChange(self._handle, flush=False) - return +# def _changeItemStatus(self, key: str) -> None: +# """Set a new status value of an item.""" +# self._item.setStatus(key) +# self.projTree.setTreeItemValues(self._item) +# self.projTree._alertTreeChange(self._handle, flush=False) +# return - def _iterSetItemStatus(self, key: str) -> None: - """Change the status value for multiple items.""" - for tItem in self._items: - if tItem and tItem.isNovelLike(): - tItem.setStatus(key) - self.projTree.setTreeItemValues(tItem) - self.projTree._alertTreeChange(tItem.itemHandle, flush=False) - return +# def _iterSetItemStatus(self, key: str) -> None: +# """Change the status value for multiple items.""" +# for tItem in self._items: +# if tItem and tItem.isNovelLike(): +# tItem.setStatus(key) +# self.projTree.setTreeItemValues(tItem) +# self.projTree._alertTreeChange(tItem.itemHandle, flush=False) +# return - def _changeItemImport(self, key: str) -> None: - """Set a new importance value of an item.""" - self._item.setImport(key) - self.projTree.setTreeItemValues(self._item) - self.projTree._alertTreeChange(self._handle, flush=False) - return +# def _changeItemImport(self, key: str) -> None: +# """Set a new importance value of an item.""" +# self._item.setImport(key) +# self.projTree.setTreeItemValues(self._item) +# self.projTree._alertTreeChange(self._handle, flush=False) +# return - def _iterSetItemImport(self, key: str) -> None: - """Change the status value for multiple items.""" - for tItem in self._items: - if tItem and not tItem.isNovelLike(): - tItem.setImport(key) - self.projTree.setTreeItemValues(tItem) - self.projTree._alertTreeChange(tItem.itemHandle, flush=False) - return +# def _iterSetItemImport(self, key: str) -> None: +# """Change the status value for multiple items.""" +# for tItem in self._items: +# if tItem and not tItem.isNovelLike(): +# tItem.setImport(key) +# self.projTree.setTreeItemValues(tItem) +# self.projTree._alertTreeChange(tItem.itemHandle, flush=False) +# return - def _changeItemLayout(self, itemLayout: nwItemLayout) -> None: - """Set a new item layout value of an item.""" - if itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed(): - self._item.setLayout(nwItemLayout.DOCUMENT) - self.projTree.setTreeItemValues(self._item) - self.projTree._alertTreeChange(self._handle, flush=False) - elif itemLayout == nwItemLayout.NOTE: - self._item.setLayout(nwItemLayout.NOTE) - self.projTree.setTreeItemValues(self._item) - self.projTree._alertTreeChange(self._handle, flush=False) - return +# def _changeItemLayout(self, itemLayout: nwItemLayout) -> None: +# """Set a new item layout value of an item.""" +# if itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed(): +# self._item.setLayout(nwItemLayout.DOCUMENT) +# self.projTree.setTreeItemValues(self._item) +# self.projTree._alertTreeChange(self._handle, flush=False) +# elif itemLayout == nwItemLayout.NOTE: +# self._item.setLayout(nwItemLayout.NOTE) +# self.projTree.setTreeItemValues(self._item) +# self.projTree._alertTreeChange(self._handle, flush=False) +# return - def _covertFolderToFile(self, itemLayout: nwItemLayout) -> None: - """Convert a folder to a note or document.""" - if self._item.isFolderType(): - msgYes = SHARED.question(self.tr( - "Do you want to convert the folder to a {0}? " - "This action cannot be reversed." - ).format(trConst(nwLabels.LAYOUT_NAME[itemLayout]))) - if msgYes and itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed(): - self._item.setType(nwItemType.FILE) - self._item.setLayout(nwItemLayout.DOCUMENT) - self.projTree.setTreeItemValues(self._item) - self.projTree._alertTreeChange(self._handle, flush=False) - elif msgYes and itemLayout == nwItemLayout.NOTE: - self._item.setType(nwItemType.FILE) - self._item.setLayout(nwItemLayout.NOTE) - self.projTree.setTreeItemValues(self._item) - self.projTree._alertTreeChange(self._handle, flush=False) - else: - logger.info("Folder conversion cancelled") - return +# def _covertFolderToFile(self, itemLayout: nwItemLayout) -> None: +# """Convert a folder to a note or document.""" +# if self._item.isFolderType(): +# msgYes = SHARED.question(self.tr( +# "Do you want to convert the folder to a {0}? " +# "This action cannot be reversed." +# ).format(trConst(nwLabels.LAYOUT_NAME[itemLayout]))) +# if msgYes and itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed(): +# self._item.setType(nwItemType.FILE) +# self._item.setLayout(nwItemLayout.DOCUMENT) +# self.projTree.setTreeItemValues(self._item) +# self.projTree._alertTreeChange(self._handle, flush=False) +# elif msgYes and itemLayout == nwItemLayout.NOTE: +# self._item.setType(nwItemType.FILE) +# self._item.setLayout(nwItemLayout.NOTE) +# self.projTree.setTreeItemValues(self._item) +# self.projTree._alertTreeChange(self._handle, flush=False) +# else: +# logger.info("Folder conversion cancelled") +# return