Make adding new docs smarter (#1110)
This commit is contained in:
@@ -221,7 +221,7 @@ class NWIndex:
|
||||
if theItem is None:
|
||||
logger.info("Not indexing unknown item '%s'", tHandle)
|
||||
return False
|
||||
if theItem.itemType != nwItemType.FILE:
|
||||
if not theItem.isFileType():
|
||||
logger.info("Not indexing non-file item '%s'", tHandle)
|
||||
return False
|
||||
|
||||
@@ -792,7 +792,7 @@ class ItemIndex:
|
||||
for tItem in self.theProject.tree:
|
||||
if tItem is None:
|
||||
continue
|
||||
if tItem.itemLayout == nwItemLayout.NOTE:
|
||||
if tItem.isNoteLayout():
|
||||
continue
|
||||
if skipExcl and not tItem.isExported:
|
||||
continue
|
||||
|
||||
+30
-11
@@ -292,6 +292,22 @@ class NWItem():
|
||||
|
||||
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):
|
||||
"""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)
|
||||
|
||||
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
|
||||
def isRootType(self):
|
||||
return self._type == nwItemType.ROOT
|
||||
|
||||
def isFolderType(self):
|
||||
return self._type == nwItemType.FOLDER
|
||||
|
||||
def isFileType(self):
|
||||
return self._type == nwItemType.FILE
|
||||
|
||||
def isNoteLayout(self):
|
||||
return self._layout == nwItemLayout.NOTE
|
||||
|
||||
def isDocumentLayout(self):
|
||||
return self._layout == nwItemLayout.DOCUMENT
|
||||
|
||||
##
|
||||
# Special Setters
|
||||
|
||||
@@ -183,7 +183,7 @@ class NWProject():
|
||||
tItem = self._projTree[tHandle]
|
||||
if tItem is None:
|
||||
return False
|
||||
if tItem.itemType != nwItemType.FILE:
|
||||
if not tItem.isFileType():
|
||||
return False
|
||||
|
||||
newDoc = NWDoc(self, tHandle)
|
||||
|
||||
@@ -29,7 +29,7 @@ import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import checkHandle
|
||||
from novelwriter.constants import nwFiles
|
||||
@@ -94,7 +94,7 @@ class NWTree():
|
||||
nwItem.setHandle(tHandle)
|
||||
nwItem.setParent(pHandle)
|
||||
|
||||
if nwItem.itemType == nwItemType.ROOT:
|
||||
if nwItem.isRootType():
|
||||
logger.verbose("Item '%s' is a root item", str(tHandle))
|
||||
self._treeRoots[tHandle] = nwItem
|
||||
if nwItem.itemClass == nwItemClass.ARCHIVE:
|
||||
@@ -357,7 +357,7 @@ class NWTree():
|
||||
tItem = self.__getitem__(tHandle)
|
||||
if tItem is None:
|
||||
return False
|
||||
if tItem.itemType != nwItemType.FILE:
|
||||
if not tItem.isFileType():
|
||||
logger.error("Item '%s' is not a file", tHandle)
|
||||
return False
|
||||
if not isinstance(itemLayout, nwItemLayout):
|
||||
|
||||
@@ -183,7 +183,7 @@ class GuiDocMerge(QDialog):
|
||||
for sHandle in self.mainGui.projView.getTreeFromHandle(tHandle):
|
||||
newItem = QListWidgetItem()
|
||||
nwItem = self.theProject.tree[sHandle]
|
||||
if nwItem.itemType is not nwItemType.FILE:
|
||||
if not nwItem.isFileType():
|
||||
continue
|
||||
newItem.setText(nwItem.itemName)
|
||||
newItem.setData(Qt.UserRole, sHandle)
|
||||
|
||||
@@ -33,7 +33,7 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter.core import NWDoc
|
||||
from novelwriter.enum import nwAlert, nwItemType
|
||||
from novelwriter.enum import nwAlert
|
||||
from novelwriter.gui.custom import QHelpLabel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -235,7 +235,7 @@ class GuiDocSplit(QDialog):
|
||||
if nwItem is None:
|
||||
return False
|
||||
|
||||
if nwItem.itemType is not nwItemType.FILE:
|
||||
if not nwItem.isFileType():
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Element selected in the project tree must be a file."
|
||||
), nwAlert.ERROR)
|
||||
|
||||
@@ -30,7 +30,6 @@ from PyQt5.QtCore import Qt, pyqtSlot
|
||||
from PyQt5.QtGui import QFont, QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
|
||||
|
||||
from novelwriter.enum import nwItemType
|
||||
from novelwriter.constants import trConst, nwLabels
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -247,7 +246,7 @@ class GuiItemDetails(QWidget):
|
||||
if len(theLabel) > 100:
|
||||
theLabel = theLabel[:96].rstrip()+" ..."
|
||||
|
||||
if nwItem.itemType == nwItemType.FILE:
|
||||
if nwItem.isFileType():
|
||||
if nwItem.isExported:
|
||||
self.labelIcon.setPixmap(self._expCheck)
|
||||
else:
|
||||
@@ -284,7 +283,7 @@ class GuiItemDetails(QWidget):
|
||||
# Counts
|
||||
# ======
|
||||
|
||||
if nwItem.itemType == nwItemType.FILE:
|
||||
if nwItem.isFileType():
|
||||
self.cCountData.setText(f"{nwItem.charCount:n}")
|
||||
self.wCountData.setText(f"{nwItem.wordCount:n}")
|
||||
self.pCountData.setText(f"{nwItem.paraCount:n}")
|
||||
|
||||
+32
-20
@@ -41,7 +41,7 @@ from PyQt5.QtWidgets import (
|
||||
|
||||
from novelwriter.core import NWDoc
|
||||
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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -447,16 +447,11 @@ class GuiProjectTree(QTreeWidget):
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
# If the selected item is a file, the new item will be a
|
||||
# sibling if the file has no children, otherwise a child
|
||||
# Collect some information about the selected item that
|
||||
pItem = self.theProject.tree[sHandle]
|
||||
qItem = self._getTreeItem(sHandle)
|
||||
if pItem.itemType == nwItemType.FILE and qItem.childCount() == 0:
|
||||
nHandle = sHandle
|
||||
sHandle = pItem.itemParent
|
||||
if sHandle is None:
|
||||
logger.error("Internal error") # Bug
|
||||
return False
|
||||
sLevel = nwHeaders.H_LEVEL.get(self.theProject.index.getHandleHeaderLevel(sHandle), 0)
|
||||
sIsParent = False if qItem is None else qItem.childCount() > 0
|
||||
|
||||
if self.theProject.tree.isTrash(sHandle):
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
@@ -464,19 +459,36 @@ class GuiProjectTree(QTreeWidget):
|
||||
), nwAlert.ERROR)
|
||||
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 isNote:
|
||||
newLabel = self.tr("New Note")
|
||||
asChild = sIsParent
|
||||
elif hLevel == 2:
|
||||
newLabel = self.tr("New Chapter")
|
||||
asChild = sIsParent and pItem.isDocumentLayout() and sLevel < 2
|
||||
elif hLevel == 3:
|
||||
newLabel = self.tr("New Scene")
|
||||
asChild = sIsParent and pItem.isDocumentLayout() and sLevel < 3
|
||||
else:
|
||||
newLabel = self.tr("New Document")
|
||||
asChild = sIsParent and pItem.isDocumentLayout()
|
||||
else:
|
||||
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)
|
||||
if not dlgOk:
|
||||
logger.info("New item creation cancelled by user")
|
||||
@@ -688,7 +700,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
wCount = self._getItemWordCount(tHandle)
|
||||
autoFlush = not bulkAction
|
||||
if nwItemS.itemType == nwItemType.ROOT:
|
||||
if nwItemS.isRootType():
|
||||
# Only an empty ROOT folder can be deleted
|
||||
logger.debug("User requested a root folder '%s' deleted", tHandle)
|
||||
tIndex = self.indexOfTopLevelItem(trItemS)
|
||||
@@ -704,7 +716,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
), nwAlert.ERROR)
|
||||
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
|
||||
logger.debug("User requested an empty folder '%s' deleted", tHandle)
|
||||
trItemP = trItemS.parent()
|
||||
@@ -791,12 +803,12 @@ class GuiProjectTree(QTreeWidget):
|
||||
trItem.setIcon(self.C_STATUS, statusIcon)
|
||||
trItem.setToolTip(self.C_STATUS, itemStatus)
|
||||
|
||||
if nwItem.itemType == nwItemType.FILE:
|
||||
if nwItem.isFileType():
|
||||
trItem.setIcon(
|
||||
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.setBold(hLevel == "H1" or hLevel == "H2")
|
||||
trFont.setUnderline(hLevel == "H1")
|
||||
@@ -966,7 +978,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
if tItem is None:
|
||||
return
|
||||
|
||||
if tItem.itemType == nwItemType.FILE:
|
||||
if tItem.isFileType():
|
||||
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "")
|
||||
else:
|
||||
trItem = self._getTreeItem(tHandle)
|
||||
@@ -1007,7 +1019,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
# Document Actions
|
||||
# ================
|
||||
|
||||
isFile = tItem.itemType == nwItemType.FILE
|
||||
isFile = tItem.isFileType()
|
||||
if isFile:
|
||||
ctxMenu.addAction(
|
||||
self.tr("Open Document"),
|
||||
@@ -1047,7 +1059,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
)
|
||||
|
||||
if isFile and tItem.documentAllowed():
|
||||
if tItem.itemLayout == nwItemLayout.NOTE:
|
||||
if tItem.isNoteLayout():
|
||||
ctxMenu.addAction(
|
||||
self.tr("Change to {0}").format(
|
||||
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
|
||||
@@ -1067,7 +1079,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
# Delete Item
|
||||
# ===========
|
||||
|
||||
if tItem.itemClass == nwItemClass.TRASH or tItem.itemType == nwItemType.ROOT:
|
||||
if tItem.itemClass == nwItemClass.TRASH or tItem.isRootType():
|
||||
ctxMenu.addAction(
|
||||
self.tr("Delete Permanently"), lambda: self.deleteItem(tHandle)
|
||||
)
|
||||
@@ -1106,7 +1118,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
if tItem is None:
|
||||
return
|
||||
|
||||
if tItem.itemType == nwItemType.FILE:
|
||||
if tItem.isFileType():
|
||||
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
|
||||
|
||||
return
|
||||
@@ -1294,7 +1306,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
self._treeMap[tHandle] = newItem
|
||||
if pHandle is None:
|
||||
if nwItem.itemType == nwItemType.ROOT:
|
||||
if nwItem.isRootType():
|
||||
newItem.setFlags(newItem.flags() ^ Qt.ItemIsDragEnabled)
|
||||
self.addTopLevelItem(newItem)
|
||||
else:
|
||||
|
||||
@@ -784,11 +784,11 @@ class GuiBuildNovel(QDialog):
|
||||
if not (theItem.isExported or ignoreFlag):
|
||||
return False
|
||||
|
||||
isNone = theItem.itemType != nwItemType.FILE
|
||||
isNone = not theItem.isFileType()
|
||||
isNone |= theItem.itemLayout == nwItemLayout.NO_LAYOUT
|
||||
isNone |= theItem.isInactive()
|
||||
isNone |= theItem.itemParent is None
|
||||
isNote = theItem.itemLayout == nwItemLayout.NOTE
|
||||
isNote = theItem.isNoteLayout()
|
||||
isNovel = not isNone and not isNote
|
||||
|
||||
if isNone:
|
||||
|
||||
@@ -203,12 +203,16 @@ def testCoreItem_Methods(mockGUI):
|
||||
|
||||
theItem.setType("ROOT")
|
||||
assert theItem.describeMe() == "Root Folder"
|
||||
assert theItem.isRootType() is True
|
||||
|
||||
theItem.setType("FOLDER")
|
||||
assert theItem.describeMe() == "Folder"
|
||||
assert theItem.isFolderType() is True
|
||||
|
||||
theItem.setType("FILE")
|
||||
theItem.setLayout("DOCUMENT")
|
||||
assert theItem.isFileType() is True
|
||||
assert theItem.isDocumentLayout() is True
|
||||
assert theItem.describeMe() == "Novel Document"
|
||||
assert theItem.describeMe("H0") == "Novel Document"
|
||||
assert theItem.describeMe("H1") == "Novel Title Page"
|
||||
@@ -217,6 +221,7 @@ def testCoreItem_Methods(mockGUI):
|
||||
assert theItem.describeMe("H4") == "Novel Document"
|
||||
|
||||
theItem.setLayout("NOTE")
|
||||
assert theItem.isNoteLayout() is True
|
||||
assert theItem.describeMe() == "Project Note"
|
||||
|
||||
# Status + Icon
|
||||
|
||||
Reference in New Issue
Block a user