Make adding new docs smarter (#1110)

This commit is contained in:
Veronica Berglyd Olsen
2022-09-11 17:40:47 +02:00
committed by GitHub
10 changed files with 80 additions and 45 deletions
+2 -2
View File
@@ -221,7 +221,7 @@ class NWIndex:
if theItem is None: if theItem is None:
logger.info("Not indexing unknown item '%s'", tHandle) logger.info("Not indexing unknown item '%s'", tHandle)
return False return False
if theItem.itemType != nwItemType.FILE: if not theItem.isFileType():
logger.info("Not indexing non-file item '%s'", tHandle) logger.info("Not indexing non-file item '%s'", tHandle)
return False return False
@@ -792,7 +792,7 @@ class ItemIndex:
for tItem in self.theProject.tree: for tItem in self.theProject.tree:
if tItem is None: if tItem is None:
continue continue
if tItem.itemLayout == nwItemLayout.NOTE: if tItem.isNoteLayout():
continue continue
if skipExcl and not tItem.isExported: if skipExcl and not tItem.isExported:
continue continue
+30 -11
View File
@@ -292,6 +292,22 @@ class NWItem():
return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, "")) return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, ""))
def getImportStatus(self):
"""Return the relevant importance or status label and icon for
the current item based on its class.
"""
if self.isNovelLike():
stName = self.theProject.statusItems.name(self._status)
stIcon = self.theProject.statusItems.icon(self._status)
else:
stName = self.theProject.importItems.name(self._import)
stIcon = self.theProject.importItems.icon(self._import)
return stName, stIcon
##
# Checker Methods
##
def isNovelLike(self): def isNovelLike(self):
"""Returns true if the item is of a novel-like class. """Returns true if the item is of a novel-like class.
""" """
@@ -307,17 +323,20 @@ class NWItem():
""" """
return self._class in (nwItemClass.NO_CLASS, nwItemClass.ARCHIVE, nwItemClass.TRASH) return self._class in (nwItemClass.NO_CLASS, nwItemClass.ARCHIVE, nwItemClass.TRASH)
def getImportStatus(self): def isRootType(self):
"""Return the relevant importance or status label and icon for return self._type == nwItemType.ROOT
the current item based on its class.
""" def isFolderType(self):
if self.isNovelLike(): return self._type == nwItemType.FOLDER
stName = self.theProject.statusItems.name(self._status)
stIcon = self.theProject.statusItems.icon(self._status) def isFileType(self):
else: return self._type == nwItemType.FILE
stName = self.theProject.importItems.name(self._import)
stIcon = self.theProject.importItems.icon(self._import) def isNoteLayout(self):
return stName, stIcon return self._layout == nwItemLayout.NOTE
def isDocumentLayout(self):
return self._layout == nwItemLayout.DOCUMENT
## ##
# Special Setters # Special Setters
+1 -1
View File
@@ -183,7 +183,7 @@ class NWProject():
tItem = self._projTree[tHandle] tItem = self._projTree[tHandle]
if tItem is None: if tItem is None:
return False return False
if tItem.itemType != nwItemType.FILE: if not tItem.isFileType():
return False return False
newDoc = NWDoc(self, tHandle) newDoc = NWDoc(self, tHandle)
+3 -3
View File
@@ -29,7 +29,7 @@ import logging
from lxml import etree from lxml import etree
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout from novelwriter.enum import nwItemClass, nwItemLayout
from novelwriter.error import logException from novelwriter.error import logException
from novelwriter.common import checkHandle from novelwriter.common import checkHandle
from novelwriter.constants import nwFiles from novelwriter.constants import nwFiles
@@ -94,7 +94,7 @@ class NWTree():
nwItem.setHandle(tHandle) nwItem.setHandle(tHandle)
nwItem.setParent(pHandle) nwItem.setParent(pHandle)
if nwItem.itemType == nwItemType.ROOT: if nwItem.isRootType():
logger.verbose("Item '%s' is a root item", str(tHandle)) logger.verbose("Item '%s' is a root item", str(tHandle))
self._treeRoots[tHandle] = nwItem self._treeRoots[tHandle] = nwItem
if nwItem.itemClass == nwItemClass.ARCHIVE: if nwItem.itemClass == nwItemClass.ARCHIVE:
@@ -357,7 +357,7 @@ class NWTree():
tItem = self.__getitem__(tHandle) tItem = self.__getitem__(tHandle)
if tItem is None: if tItem is None:
return False return False
if tItem.itemType != nwItemType.FILE: if not tItem.isFileType():
logger.error("Item '%s' is not a file", tHandle) logger.error("Item '%s' is not a file", tHandle)
return False return False
if not isinstance(itemLayout, nwItemLayout): if not isinstance(itemLayout, nwItemLayout):
+1 -1
View File
@@ -183,7 +183,7 @@ class GuiDocMerge(QDialog):
for sHandle in self.mainGui.projView.getTreeFromHandle(tHandle): for sHandle in self.mainGui.projView.getTreeFromHandle(tHandle):
newItem = QListWidgetItem() newItem = QListWidgetItem()
nwItem = self.theProject.tree[sHandle] nwItem = self.theProject.tree[sHandle]
if nwItem.itemType is not nwItemType.FILE: if not nwItem.isFileType():
continue continue
newItem.setText(nwItem.itemName) newItem.setText(nwItem.itemName)
newItem.setData(Qt.UserRole, sHandle) newItem.setData(Qt.UserRole, sHandle)
+2 -2
View File
@@ -33,7 +33,7 @@ from PyQt5.QtWidgets import (
) )
from novelwriter.core import NWDoc from novelwriter.core import NWDoc
from novelwriter.enum import nwAlert, nwItemType from novelwriter.enum import nwAlert
from novelwriter.gui.custom import QHelpLabel from novelwriter.gui.custom import QHelpLabel
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -235,7 +235,7 @@ class GuiDocSplit(QDialog):
if nwItem is None: if nwItem is None:
return False return False
if nwItem.itemType is not nwItemType.FILE: if not nwItem.isFileType():
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Element selected in the project tree must be a file." "Element selected in the project tree must be a file."
), nwAlert.ERROR) ), nwAlert.ERROR)
+2 -3
View File
@@ -30,7 +30,6 @@ from PyQt5.QtCore import Qt, pyqtSlot
from PyQt5.QtGui import QFont, QPixmap from PyQt5.QtGui import QFont, QPixmap
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
from novelwriter.enum import nwItemType
from novelwriter.constants import trConst, nwLabels from novelwriter.constants import trConst, nwLabels
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -247,7 +246,7 @@ class GuiItemDetails(QWidget):
if len(theLabel) > 100: if len(theLabel) > 100:
theLabel = theLabel[:96].rstrip()+" ..." theLabel = theLabel[:96].rstrip()+" ..."
if nwItem.itemType == nwItemType.FILE: if nwItem.isFileType():
if nwItem.isExported: if nwItem.isExported:
self.labelIcon.setPixmap(self._expCheck) self.labelIcon.setPixmap(self._expCheck)
else: else:
@@ -284,7 +283,7 @@ class GuiItemDetails(QWidget):
# Counts # Counts
# ====== # ======
if nwItem.itemType == nwItemType.FILE: if nwItem.isFileType():
self.cCountData.setText(f"{nwItem.charCount:n}") self.cCountData.setText(f"{nwItem.charCount:n}")
self.wCountData.setText(f"{nwItem.wordCount:n}") self.wCountData.setText(f"{nwItem.wordCount:n}")
self.pCountData.setText(f"{nwItem.paraCount:n}") self.pCountData.setText(f"{nwItem.paraCount:n}")
+32 -20
View File
@@ -41,7 +41,7 @@ from PyQt5.QtWidgets import (
from novelwriter.core import NWDoc from novelwriter.core import NWDoc
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
from novelwriter.constants import trConst, nwLabels from novelwriter.constants import nwHeaders, trConst, nwLabels
from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.dialogs.editlabel import GuiEditLabel
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -447,16 +447,11 @@ class GuiProjectTree(QTreeWidget):
), nwAlert.ERROR) ), nwAlert.ERROR)
return False return False
# If the selected item is a file, the new item will be a # Collect some information about the selected item that
# sibling if the file has no children, otherwise a child
pItem = self.theProject.tree[sHandle] pItem = self.theProject.tree[sHandle]
qItem = self._getTreeItem(sHandle) qItem = self._getTreeItem(sHandle)
if pItem.itemType == nwItemType.FILE and qItem.childCount() == 0: sLevel = nwHeaders.H_LEVEL.get(self.theProject.index.getHandleHeaderLevel(sHandle), 0)
nHandle = sHandle sIsParent = False if qItem is None else qItem.childCount() > 0
sHandle = pItem.itemParent
if sHandle is None:
logger.error("Internal error") # Bug
return False
if self.theProject.tree.isTrash(sHandle): if self.theProject.tree.isTrash(sHandle):
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
@@ -464,19 +459,36 @@ class GuiProjectTree(QTreeWidget):
), nwAlert.ERROR) ), nwAlert.ERROR)
return False return False
# Ask for label # Set default label and determine if new item is to be added
# as child or sibling to the selected item
if itemType == nwItemType.FILE: if itemType == nwItemType.FILE:
if isNote: if isNote:
newLabel = self.tr("New Note") newLabel = self.tr("New Note")
asChild = sIsParent
elif hLevel == 2: elif hLevel == 2:
newLabel = self.tr("New Chapter") newLabel = self.tr("New Chapter")
asChild = sIsParent and pItem.isDocumentLayout() and sLevel < 2
elif hLevel == 3: elif hLevel == 3:
newLabel = self.tr("New Scene") newLabel = self.tr("New Scene")
asChild = sIsParent and pItem.isDocumentLayout() and sLevel < 3
else: else:
newLabel = self.tr("New Document") newLabel = self.tr("New Document")
asChild = sIsParent and pItem.isDocumentLayout()
else: else:
newLabel = self.tr("New Folder") newLabel = self.tr("New Folder")
asChild = False
if not (asChild or pItem.isFolderType() or pItem.isRootType()):
# Move to the parent item so that the new item is added
# as a sibling instead
nHandle = sHandle
sHandle = pItem.itemParent
if sHandle is None:
# Bug: We have a condition that is unhandled
logger.error("Internal error")
return False
# Ask for label
newLabel, dlgOk = GuiEditLabel.getLabel(self, text=newLabel) newLabel, dlgOk = GuiEditLabel.getLabel(self, text=newLabel)
if not dlgOk: if not dlgOk:
logger.info("New item creation cancelled by user") logger.info("New item creation cancelled by user")
@@ -688,7 +700,7 @@ class GuiProjectTree(QTreeWidget):
wCount = self._getItemWordCount(tHandle) wCount = self._getItemWordCount(tHandle)
autoFlush = not bulkAction autoFlush = not bulkAction
if nwItemS.itemType == nwItemType.ROOT: if nwItemS.isRootType():
# Only an empty ROOT folder can be deleted # Only an empty ROOT folder can be deleted
logger.debug("User requested a root folder '%s' deleted", tHandle) logger.debug("User requested a root folder '%s' deleted", tHandle)
tIndex = self.indexOfTopLevelItem(trItemS) tIndex = self.indexOfTopLevelItem(trItemS)
@@ -704,7 +716,7 @@ class GuiProjectTree(QTreeWidget):
), nwAlert.ERROR) ), nwAlert.ERROR)
return False return False
elif nwItemS.itemType == nwItemType.FOLDER and trItemS.childCount() == 0: elif nwItemS.isFolderType() and trItemS.childCount() == 0:
# An empty FOLDER is just deleted without any further checks # An empty FOLDER is just deleted without any further checks
logger.debug("User requested an empty folder '%s' deleted", tHandle) logger.debug("User requested an empty folder '%s' deleted", tHandle)
trItemP = trItemS.parent() trItemP = trItemS.parent()
@@ -791,12 +803,12 @@ class GuiProjectTree(QTreeWidget):
trItem.setIcon(self.C_STATUS, statusIcon) trItem.setIcon(self.C_STATUS, statusIcon)
trItem.setToolTip(self.C_STATUS, itemStatus) trItem.setToolTip(self.C_STATUS, itemStatus)
if nwItem.itemType == nwItemType.FILE: if nwItem.isFileType():
trItem.setIcon( trItem.setIcon(
self.C_EXPORT, self.mainTheme.getIcon("check" if nwItem.isExported else "cross") self.C_EXPORT, self.mainTheme.getIcon("check" if nwItem.isExported else "cross")
) )
if self.mainConf.emphLabels and nwItem.itemLayout == nwItemLayout.DOCUMENT: if self.mainConf.emphLabels and nwItem.isDocumentLayout():
trFont = trItem.font(self.C_NAME) trFont = trItem.font(self.C_NAME)
trFont.setBold(hLevel == "H1" or hLevel == "H2") trFont.setBold(hLevel == "H1" or hLevel == "H2")
trFont.setUnderline(hLevel == "H1") trFont.setUnderline(hLevel == "H1")
@@ -966,7 +978,7 @@ class GuiProjectTree(QTreeWidget):
if tItem is None: if tItem is None:
return return
if tItem.itemType == nwItemType.FILE: if tItem.isFileType():
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "") self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "")
else: else:
trItem = self._getTreeItem(tHandle) trItem = self._getTreeItem(tHandle)
@@ -1007,7 +1019,7 @@ class GuiProjectTree(QTreeWidget):
# Document Actions # Document Actions
# ================ # ================
isFile = tItem.itemType == nwItemType.FILE isFile = tItem.isFileType()
if isFile: if isFile:
ctxMenu.addAction( ctxMenu.addAction(
self.tr("Open Document"), self.tr("Open Document"),
@@ -1047,7 +1059,7 @@ class GuiProjectTree(QTreeWidget):
) )
if isFile and tItem.documentAllowed(): if isFile and tItem.documentAllowed():
if tItem.itemLayout == nwItemLayout.NOTE: if tItem.isNoteLayout():
ctxMenu.addAction( ctxMenu.addAction(
self.tr("Change to {0}").format( self.tr("Change to {0}").format(
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT]) trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
@@ -1067,7 +1079,7 @@ class GuiProjectTree(QTreeWidget):
# Delete Item # Delete Item
# =========== # ===========
if tItem.itemClass == nwItemClass.TRASH or tItem.itemType == nwItemType.ROOT: if tItem.itemClass == nwItemClass.TRASH or tItem.isRootType():
ctxMenu.addAction( ctxMenu.addAction(
self.tr("Delete Permanently"), lambda: self.deleteItem(tHandle) self.tr("Delete Permanently"), lambda: self.deleteItem(tHandle)
) )
@@ -1106,7 +1118,7 @@ class GuiProjectTree(QTreeWidget):
if tItem is None: if tItem is None:
return return
if tItem.itemType == nwItemType.FILE: if tItem.isFileType():
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "") self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
return return
@@ -1294,7 +1306,7 @@ class GuiProjectTree(QTreeWidget):
self._treeMap[tHandle] = newItem self._treeMap[tHandle] = newItem
if pHandle is None: if pHandle is None:
if nwItem.itemType == nwItemType.ROOT: if nwItem.isRootType():
newItem.setFlags(newItem.flags() ^ Qt.ItemIsDragEnabled) newItem.setFlags(newItem.flags() ^ Qt.ItemIsDragEnabled)
self.addTopLevelItem(newItem) self.addTopLevelItem(newItem)
else: else:
+2 -2
View File
@@ -784,11 +784,11 @@ class GuiBuildNovel(QDialog):
if not (theItem.isExported or ignoreFlag): if not (theItem.isExported or ignoreFlag):
return False return False
isNone = theItem.itemType != nwItemType.FILE isNone = not theItem.isFileType()
isNone |= theItem.itemLayout == nwItemLayout.NO_LAYOUT isNone |= theItem.itemLayout == nwItemLayout.NO_LAYOUT
isNone |= theItem.isInactive() isNone |= theItem.isInactive()
isNone |= theItem.itemParent is None isNone |= theItem.itemParent is None
isNote = theItem.itemLayout == nwItemLayout.NOTE isNote = theItem.isNoteLayout()
isNovel = not isNone and not isNote isNovel = not isNone and not isNote
if isNone: if isNone:
+5
View File
@@ -203,12 +203,16 @@ def testCoreItem_Methods(mockGUI):
theItem.setType("ROOT") theItem.setType("ROOT")
assert theItem.describeMe() == "Root Folder" assert theItem.describeMe() == "Root Folder"
assert theItem.isRootType() is True
theItem.setType("FOLDER") theItem.setType("FOLDER")
assert theItem.describeMe() == "Folder" assert theItem.describeMe() == "Folder"
assert theItem.isFolderType() is True
theItem.setType("FILE") theItem.setType("FILE")
theItem.setLayout("DOCUMENT") theItem.setLayout("DOCUMENT")
assert theItem.isFileType() is True
assert theItem.isDocumentLayout() is True
assert theItem.describeMe() == "Novel Document" assert theItem.describeMe() == "Novel Document"
assert theItem.describeMe("H0") == "Novel Document" assert theItem.describeMe("H0") == "Novel Document"
assert theItem.describeMe("H1") == "Novel Title Page" assert theItem.describeMe("H1") == "Novel Title Page"
@@ -217,6 +221,7 @@ def testCoreItem_Methods(mockGUI):
assert theItem.describeMe("H4") == "Novel Document" assert theItem.describeMe("H4") == "Novel Document"
theItem.setLayout("NOTE") theItem.setLayout("NOTE")
assert theItem.isNoteLayout() is True
assert theItem.describeMe() == "Project Note" assert theItem.describeMe() == "Project Note"
# Status + Icon # Status + Icon