Merge branch 'main' into dev
This commit is contained in:
@@ -29,7 +29,6 @@ cls_archive = delete.svg
|
||||
cls_trash = trash.svg
|
||||
proj_document = document-text.svg
|
||||
proj_folder = folder.svg
|
||||
proj_orphan = warning.svg
|
||||
doc_h1 = heading1.svg
|
||||
doc_h2 = heading2.svg
|
||||
doc_h3 = heading3.svg
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4695"
|
||||
viewBox="0 0 24 24"
|
||||
height="24"
|
||||
width="24"
|
||||
version="1.2">
|
||||
<metadata
|
||||
id="metadata4701">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4699" />
|
||||
<path
|
||||
style="stroke-width:1.01740682;fill:#ffff84;fill-opacity:1"
|
||||
id="path4693"
|
||||
d="M 21.330638,15.197201 15.315729,5.1716738 C 14.526221,3.8561667 13.318559,3.1032856 12,3.1032856 c -1.31856,0 -2.5262214,0.7528811 -3.3157291,2.0663534 L 2.6693614,15.197201 c -0.7996818,1.331785 -0.8871787,2.752085 -0.2390906,3.896668 0.6470708,1.1456 1.9106901,1.802845 3.4652878,1.802845 H 18.104441 c 1.554598,0 2.818217,-0.657245 3.465288,-1.801828 0.648088,-1.144582 0.560591,-2.564882 -0.239091,-3.897685 z M 12,17.385643 c -0.868866,0 -1.576981,-0.707098 -1.576981,-1.575963 0,-0.869883 0.707098,-1.577998 1.576981,-1.577998 0.869882,0 1.57698,0.708115 1.57698,1.577998 0,0.868865 -0.708115,1.575963 -1.57698,1.575963 z m 1.661425,-7.5532283 c -0.01119,0.03154 -1.425387,3.5283663 -1.425387,3.5283663 -0.03866,0.09564 -0.132263,0.158716 -0.235021,0.158716 -0.102758,0 -0.19636,-0.06308 -0.235021,-0.158716 L 10.350783,9.8629369 c -0.09157,-0.2370558 -0.131245,-0.4507113 -0.131245,-0.6664015 0,-0.9817977 0.798664,-1.7804621 1.780462,-1.7804621 0.981797,0 1.780462,0.7986644 1.780462,1.7804621 0,0.2156902 -0.03968,0.4293457 -0.119037,0.6358793 z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -29,7 +29,6 @@ cls_archive = delete.svg
|
||||
cls_trash = trash.svg
|
||||
proj_document = document-text.svg
|
||||
proj_folder = folder.svg
|
||||
proj_orphan = warning.svg
|
||||
doc_h1 = heading1.svg
|
||||
doc_h2 = heading2.svg
|
||||
doc_h3 = heading3.svg
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4695"
|
||||
viewBox="0 0 24 24"
|
||||
height="24"
|
||||
width="24"
|
||||
version="1.2">
|
||||
<metadata
|
||||
id="metadata4701">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4699" />
|
||||
<path
|
||||
style="stroke-width:1.01740682;fill:#ad8700;fill-opacity:1"
|
||||
id="path4693"
|
||||
d="M 21.330638,15.197201 15.315729,5.1716738 C 14.526221,3.8561667 13.318559,3.1032856 12,3.1032856 c -1.31856,0 -2.5262214,0.7528811 -3.3157291,2.0663534 L 2.6693614,15.197201 c -0.7996818,1.331785 -0.8871787,2.752085 -0.2390906,3.896668 0.6470708,1.1456 1.9106901,1.802845 3.4652878,1.802845 H 18.104441 c 1.554598,0 2.818217,-0.657245 3.465288,-1.801828 0.648088,-1.144582 0.560591,-2.564882 -0.239091,-3.897685 z M 12,17.385643 c -0.868866,0 -1.576981,-0.707098 -1.576981,-1.575963 0,-0.869883 0.707098,-1.577998 1.576981,-1.577998 0.869882,0 1.57698,0.708115 1.57698,1.577998 0,0.868865 -0.708115,1.575963 -1.57698,1.575963 z m 1.661425,-7.5532283 c -0.01119,0.03154 -1.425387,3.5283663 -1.425387,3.5283663 -0.03866,0.09564 -0.132263,0.158716 -0.235021,0.158716 -0.102758,0 -0.19636,-0.06308 -0.235021,-0.158716 L 10.350783,9.8629369 c -0.09157,-0.2370558 -0.131245,-0.4507113 -0.131245,-0.6664015 0,-0.9817977 0.798664,-1.7804621 1.780462,-1.7804621 0.981797,0 1.780462,0.7986644 1.780462,1.7804621 0,0.2156902 -0.03968,0.4293457 -0.119037,0.6358793 z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -29,7 +29,6 @@ cls_archive = delete.svg
|
||||
cls_trash = trash.svg
|
||||
proj_document = document-text.svg
|
||||
proj_folder = folder.svg
|
||||
proj_orphan = warning.svg
|
||||
doc_h1 = heading1.svg
|
||||
doc_h2 = heading2.svg
|
||||
doc_h3 = heading3.svg
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4695"
|
||||
viewBox="0 0 24 24"
|
||||
height="24"
|
||||
width="24"
|
||||
version="1.2">
|
||||
<metadata
|
||||
id="metadata4701">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4699" />
|
||||
<path
|
||||
style="stroke-width:1.01740682;fill:#aeaeae;fill-opacity:1"
|
||||
id="path4693"
|
||||
d="M 21.330638,15.197201 15.315729,5.1716738 C 14.526221,3.8561667 13.318559,3.1032856 12,3.1032856 c -1.31856,0 -2.5262214,0.7528811 -3.3157291,2.0663534 L 2.6693614,15.197201 c -0.7996818,1.331785 -0.8871787,2.752085 -0.2390906,3.896668 0.6470708,1.1456 1.9106901,1.802845 3.4652878,1.802845 H 18.104441 c 1.554598,0 2.818217,-0.657245 3.465288,-1.801828 0.648088,-1.144582 0.560591,-2.564882 -0.239091,-3.897685 z M 12,17.385643 c -0.868866,0 -1.576981,-0.707098 -1.576981,-1.575963 0,-0.869883 0.707098,-1.577998 1.576981,-1.577998 0.869882,0 1.57698,0.708115 1.57698,1.577998 0,0.868865 -0.708115,1.575963 -1.57698,1.575963 z m 1.661425,-7.5532283 c -0.01119,0.03154 -1.425387,3.5283663 -1.425387,3.5283663 -0.03866,0.09564 -0.132263,0.158716 -0.235021,0.158716 -0.102758,0 -0.19636,-0.06308 -0.235021,-0.158716 L 10.350783,9.8629369 c -0.09157,-0.2370558 -0.131245,-0.4507113 -0.131245,-0.6664015 0,-0.9817977 0.798664,-1.7804621 1.780462,-1.7804621 0.981797,0 1.780462,0.7986644 1.780462,1.7804621 0,0.2156902 -0.03968,0.4293457 -0.119037,0.6358793 z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -29,7 +29,6 @@ cls_archive = delete.svg
|
||||
cls_trash = trash.svg
|
||||
proj_document = document-text.svg
|
||||
proj_folder = folder.svg
|
||||
proj_orphan = warning.svg
|
||||
doc_h1 = heading1.svg
|
||||
doc_h2 = heading2.svg
|
||||
doc_h3 = heading3.svg
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4695"
|
||||
viewBox="0 0 24 24"
|
||||
height="24"
|
||||
width="24"
|
||||
version="1.2">
|
||||
<metadata
|
||||
id="metadata4701">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4699" />
|
||||
<path
|
||||
style="stroke-width:1.01740682;fill:#000000;fill-opacity:0.78039217"
|
||||
id="path4693"
|
||||
d="M 21.330638,15.197201 15.315729,5.1716738 C 14.526221,3.8561667 13.318559,3.1032856 12,3.1032856 c -1.31856,0 -2.5262214,0.7528811 -3.3157291,2.0663534 L 2.6693614,15.197201 c -0.7996818,1.331785 -0.8871787,2.752085 -0.2390906,3.896668 0.6470708,1.1456 1.9106901,1.802845 3.4652878,1.802845 H 18.104441 c 1.554598,0 2.818217,-0.657245 3.465288,-1.801828 0.648088,-1.144582 0.560591,-2.564882 -0.239091,-3.897685 z M 12,17.385643 c -0.868866,0 -1.576981,-0.707098 -1.576981,-1.575963 0,-0.869883 0.707098,-1.577998 1.576981,-1.577998 0.869882,0 1.57698,0.708115 1.57698,1.577998 0,0.868865 -0.708115,1.575963 -1.57698,1.575963 z m 1.661425,-7.5532283 c -0.01119,0.03154 -1.425387,3.5283663 -1.425387,3.5283663 -0.03866,0.09564 -0.132263,0.158716 -0.235021,0.158716 -0.102758,0 -0.19636,-0.06308 -0.235021,-0.158716 L 10.350783,9.8629369 c -0.09157,-0.2370558 -0.131245,-0.4507113 -0.131245,-0.6664015 0,-0.9817977 0.798664,-1.7804621 1.780462,-1.7804621 0.981797,0 1.780462,0.7986644 1.780462,1.7804621 0,0.2156902 -0.03968,0.4293457 -0.119037,0.6358793 z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -25,7 +25,9 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from nw.constants.enum import nwItemClass, nwItemLayout, nwOutline
|
||||
from nw.constants.enum import (
|
||||
nwItemClass, nwItemLayout, nwItemType, nwOutline
|
||||
)
|
||||
|
||||
class nwConst():
|
||||
|
||||
@@ -43,6 +45,9 @@ class nwConst():
|
||||
SP_INTERNAL = "internal"
|
||||
SP_ENCHANT = "enchant"
|
||||
|
||||
# Check Lists
|
||||
REG_TYPES = {nwItemType.ROOT, nwItemType.FOLDER, nwItemType.FILE}
|
||||
|
||||
# END Class nwConst
|
||||
|
||||
class nwRegEx():
|
||||
|
||||
+3
-3
@@ -149,9 +149,9 @@ class NWDoc():
|
||||
docMeta = ""
|
||||
else:
|
||||
docMeta = (
|
||||
f"%%~name: {self._theItem.itemName:s}\n"
|
||||
f"%%~path: {self._theItem.itemParent:s}/{self._theItem.itemHandle:s}\n"
|
||||
f"%%~kind: {self._theItem.itemClass.name:s}/{self._theItem.itemLayout.name:s}\n"
|
||||
f"%%~name: {self._theItem.itemName}\n"
|
||||
f"%%~path: {self._theItem.itemParent}/{self._theItem.itemHandle}\n"
|
||||
f"%%~kind: {self._theItem.itemClass.name}/{self._theItem.itemLayout.name}\n"
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
+28
-6
@@ -1317,30 +1317,52 @@ class NWProject():
|
||||
# Handle orphans
|
||||
aDoc = NWDoc(self, self.theParent)
|
||||
nOrph = 0
|
||||
noWhere = False
|
||||
for oHandle in orphanFiles:
|
||||
|
||||
# Look for meta data
|
||||
oName = ""
|
||||
oParent = None
|
||||
oClass = None
|
||||
oLayout = None
|
||||
if aDoc.openDocument(oHandle, showStatus=False, isOrphan=True) is not None:
|
||||
oName, _, oClass, oLayout = aDoc.getMeta()
|
||||
oName, oParent, oClass, oLayout = aDoc.getMeta()
|
||||
|
||||
if oName == "":
|
||||
if oName:
|
||||
oName = "Recovered: %s" % oName.lstrip("Recovered: ")
|
||||
else:
|
||||
nOrph += 1
|
||||
oName = "Orphaned File %d" % nOrph
|
||||
oName = "Recovered File %d" % nOrph
|
||||
|
||||
# Recover file meta data
|
||||
if oClass is None:
|
||||
oClass = nwItemClass.NO_CLASS
|
||||
oClass = nwItemClass.NOVEL
|
||||
|
||||
if oLayout is None:
|
||||
oLayout = nwItemLayout.NO_LAYOUT
|
||||
oLayout = nwItemLayout.NOTE
|
||||
|
||||
if oParent is None or not self.projTree.handleExists(oParent):
|
||||
oParent = self.projTree.findRoot(oClass)
|
||||
if oParent is None:
|
||||
oParent = self.projTree.findRoot(nwItemClass.NOVEL)
|
||||
|
||||
# If the file still has no parent item, skip it
|
||||
if oParent is None:
|
||||
noWhere = True
|
||||
continue
|
||||
|
||||
orphItem = NWItem(self)
|
||||
orphItem.setName(oName)
|
||||
orphItem.setType(nwItemType.FILE)
|
||||
orphItem.setClass(oClass)
|
||||
orphItem.setLayout(oLayout)
|
||||
self.projTree.append(oHandle, None, orphItem)
|
||||
self.projTree.append(oHandle, oParent, orphItem)
|
||||
|
||||
if noWhere:
|
||||
self.makeAlert((
|
||||
"One or more orphaned files could not be added back into the "
|
||||
"project. Make sure at least a Novel root folder exists."
|
||||
), nwAlert.WARN)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -294,6 +294,11 @@ class NWTree():
|
||||
tTree.append(tHandle)
|
||||
return tTree
|
||||
|
||||
def handleExists(self, tHandle):
|
||||
"""Check if a handle exists in the project.
|
||||
"""
|
||||
return tHandle in self._treeOrder
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
+19
-21
@@ -774,14 +774,13 @@ class GuiBuildNovel(QDialog):
|
||||
if not os.path.isdir(saveDir):
|
||||
saveDir = self.mainConf.homePath
|
||||
|
||||
if self.mainConf.showGUI:
|
||||
dlgOpt = QFileDialog.Options()
|
||||
dlgOpt |= QFileDialog.DontUseNativeDialog
|
||||
savePath, _ = QFileDialog.getSaveFileName(
|
||||
self, "Save Document As", savePath, options=dlgOpt
|
||||
)
|
||||
if not savePath:
|
||||
return False
|
||||
dlgOpt = QFileDialog.Options()
|
||||
dlgOpt |= QFileDialog.DontUseNativeDialog
|
||||
savePath, _ = QFileDialog.getSaveFileName(
|
||||
self, "Save Document As", savePath, options=dlgOpt
|
||||
)
|
||||
if not savePath:
|
||||
return False
|
||||
|
||||
self.mainConf.setLastPath(savePath)
|
||||
|
||||
@@ -887,19 +886,18 @@ class GuiBuildNovel(QDialog):
|
||||
errMsg = "Unknown format"
|
||||
|
||||
# Report to user
|
||||
if self.mainConf.showGUI:
|
||||
if wSuccess:
|
||||
self.theParent.makeAlert(
|
||||
"%s file successfully written to:<br> %s" % (
|
||||
textFmt, savePath
|
||||
), nwAlert.INFO
|
||||
)
|
||||
else:
|
||||
self.theParent.makeAlert(
|
||||
"Failed to write %s file. %s" % (
|
||||
textFmt, errMsg
|
||||
), nwAlert.ERROR
|
||||
)
|
||||
if wSuccess:
|
||||
self.theParent.makeAlert(
|
||||
"%s file successfully written to:<br> %s" % (
|
||||
textFmt, savePath
|
||||
), nwAlert.INFO
|
||||
)
|
||||
else:
|
||||
self.theParent.makeAlert(
|
||||
"Failed to write %s file. %s" % (
|
||||
textFmt, errMsg
|
||||
), nwAlert.ERROR
|
||||
)
|
||||
|
||||
return wSuccess
|
||||
|
||||
|
||||
+67
-125
@@ -61,8 +61,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
self.theIndex = theParent.theIndex
|
||||
|
||||
# Tree Settings
|
||||
self.theMap = None
|
||||
self.orphRoot = None
|
||||
self.theMap = {}
|
||||
self.treeChanged = False
|
||||
|
||||
self.ctxMenu = GuiProjectTreeMenu(self)
|
||||
@@ -145,11 +144,11 @@ class GuiProjectTree(QTreeWidget):
|
||||
##
|
||||
|
||||
def clearTree(self):
|
||||
"""Clear the GUI content and the related maps.
|
||||
"""Clear the GUI content and the related map.
|
||||
"""
|
||||
self.clear()
|
||||
self.theMap = {}
|
||||
self.orphRoot = None
|
||||
self.treeChanged = False
|
||||
return
|
||||
|
||||
def newTreeItem(self, itemType, itemClass):
|
||||
@@ -165,6 +164,11 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.error("No project open")
|
||||
return False
|
||||
|
||||
if not isinstance(itemType, nwItemType):
|
||||
# This would indicate an internal bug
|
||||
logger.error("No itemType provided")
|
||||
return False
|
||||
|
||||
# The item needs to be assigned an item class, so one must be
|
||||
# provided, or it must be possible to extract it from the parent
|
||||
# item of the new item.
|
||||
@@ -173,21 +177,18 @@ class GuiProjectTree(QTreeWidget):
|
||||
if pItem is not None:
|
||||
itemClass = pItem.itemClass
|
||||
|
||||
# If class is still not set, alert the user and exit
|
||||
if itemClass is None:
|
||||
if itemType is not None:
|
||||
if itemType == nwItemType.FILE:
|
||||
self.makeAlert(
|
||||
"Please select a valid location in the tree to add a document.",
|
||||
nwAlert.ERROR
|
||||
)
|
||||
return False
|
||||
elif itemType == nwItemType.FOLDER:
|
||||
self.makeAlert(
|
||||
"Please select a valid location in the tree to add a folder.",
|
||||
nwAlert.ERROR
|
||||
)
|
||||
return False
|
||||
self.makeAlert("Failed to add new item.", nwAlert.BUG)
|
||||
if itemType == nwItemType.FILE:
|
||||
self.makeAlert(
|
||||
"Please select a valid location in the tree to add the document.",
|
||||
nwAlert.ERROR
|
||||
)
|
||||
else:
|
||||
self.makeAlert(
|
||||
"Please select a valid location in the tree to add the folder.",
|
||||
nwAlert.ERROR
|
||||
)
|
||||
return False
|
||||
|
||||
# Everything is fine, we have what we need, so we proceed
|
||||
@@ -260,8 +261,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
# Add the new item to the tree
|
||||
if tHandle is not None:
|
||||
self.revealNewTreeItem(tHandle, nHandle)
|
||||
if self.mainConf.showGUI:
|
||||
self.theParent.editItem(tHandle)
|
||||
self.theParent.editItem(tHandle)
|
||||
|
||||
return True
|
||||
|
||||
@@ -270,6 +270,9 @@ class GuiProjectTree(QTreeWidget):
|
||||
"""
|
||||
nwItem = self.theProject.projTree[tHandle]
|
||||
trItem = self._addTreeItem(nwItem, nHandle)
|
||||
if trItem is None:
|
||||
return False
|
||||
|
||||
pHandle = nwItem.itemParent
|
||||
if pHandle is not None and pHandle in self.theMap:
|
||||
self.theMap[pHandle].setExpanded(True)
|
||||
@@ -285,7 +288,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.error("No project open")
|
||||
return False
|
||||
|
||||
if qApp.focusWidget() != self and self.mainConf.showGUI:
|
||||
if qApp.focusWidget() != self:
|
||||
return False
|
||||
|
||||
tHandle = self.getSelectedHandle()
|
||||
@@ -326,8 +329,6 @@ class GuiProjectTree(QTreeWidget):
|
||||
"""
|
||||
theList = []
|
||||
for i in range(self.topLevelItemCount()):
|
||||
if self.topLevelItem(i) == self.orphRoot:
|
||||
continue
|
||||
theList = self._scanChildren(theList, self.topLevelItem(i), i)
|
||||
logger.debug("Saving project tree item order")
|
||||
self.theProject.setTreeOrder(theList)
|
||||
@@ -391,14 +392,12 @@ class GuiProjectTree(QTreeWidget):
|
||||
return False
|
||||
|
||||
msgYes = self.theParent.askQuestion(
|
||||
"Empty Trash", "Permanently delete %d file%s from Trash?" % (
|
||||
nTrash, "s" if nTrash > 1 else ""
|
||||
)
|
||||
"Empty Trash", "Permanently delete %d file(s) from Trash?" % nTrash
|
||||
)
|
||||
if not msgYes:
|
||||
return False
|
||||
|
||||
logger.verbose("Deleting %d files from Trash" % nTrash)
|
||||
logger.verbose("Deleting %d file(s) from Trash" % nTrash)
|
||||
for tHandle in self.getTreeFromHandle(trashHandle):
|
||||
if tHandle == trashHandle:
|
||||
continue
|
||||
@@ -603,13 +602,11 @@ class GuiProjectTree(QTreeWidget):
|
||||
relevant values in the project and on the status bar. This call
|
||||
is a fast way of getting this number, and depends on the
|
||||
propagateCount function being called when it should to maintain
|
||||
the correct count. Orphan folder is not included in the total.
|
||||
the correct count.
|
||||
"""
|
||||
nWords = 0
|
||||
for n in range(self.topLevelItemCount()):
|
||||
tItem = self.topLevelItem(n)
|
||||
if tItem == self.orphRoot:
|
||||
continue
|
||||
nWords += int(tItem.data(self.C_COUNT, Qt.UserRole))
|
||||
|
||||
self.theProject.setProjectWordCount(nWords)
|
||||
@@ -640,11 +637,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
selected, return the first.
|
||||
"""
|
||||
selItem = self.selectedItems()
|
||||
|
||||
if len(selItem) == 0:
|
||||
return None
|
||||
|
||||
if isinstance(selItem[0], QTreeWidgetItem):
|
||||
if selItem:
|
||||
return selItem[0].data(self.C_NAME, Qt.UserRole)
|
||||
|
||||
return None
|
||||
@@ -663,18 +656,21 @@ class GuiProjectTree(QTreeWidget):
|
||||
def setSelectedHandle(self, tHandle, doScroll=False):
|
||||
"""Set a specific handle as the selected item.
|
||||
"""
|
||||
if tHandle in self.theMap:
|
||||
self.clearSelection()
|
||||
self.theMap[tHandle].setSelected(True)
|
||||
if tHandle not in self.theMap:
|
||||
return False
|
||||
|
||||
selItems = self.selectedIndexes()
|
||||
if selItems and doScroll:
|
||||
self.scrollTo(
|
||||
selItems[0], QAbstractItemView.PositionAtCenter
|
||||
)
|
||||
return True
|
||||
tItem = self._getTreeItem(tHandle)
|
||||
if tItem is None:
|
||||
return False
|
||||
|
||||
return False
|
||||
self.clearSelection()
|
||||
self.theMap[tHandle].setSelected(True)
|
||||
|
||||
selItems = self.selectedIndexes()
|
||||
if selItems and doScroll:
|
||||
self.scrollTo(selItems[0], QAbstractItemView.PositionAtCenter)
|
||||
|
||||
return True
|
||||
|
||||
##
|
||||
# Slots
|
||||
@@ -687,12 +683,12 @@ class GuiProjectTree(QTreeWidget):
|
||||
selItem = self.itemAt(clickPos)
|
||||
if isinstance(selItem, QTreeWidgetItem):
|
||||
tHandle = selItem.data(self.C_NAME, Qt.UserRole)
|
||||
tItem = self.theProject.projTree[tHandle]
|
||||
self.setSelectedHandle(tHandle) # Just to be safe
|
||||
|
||||
if self.ctxMenu.filterActions(tItem):
|
||||
# Only open menu if any actions remain after filter
|
||||
self.ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
|
||||
tItem = self.theProject.projTree[tHandle]
|
||||
if tItem is not None:
|
||||
if self.ctxMenu.filterActions(tItem):
|
||||
# Only open menu if any actions remain after filter
|
||||
self.ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
|
||||
|
||||
return
|
||||
|
||||
@@ -764,17 +760,11 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.debug("Drag'n'drop of item %s accepted" % sHandle)
|
||||
self.propagateCount(sHandle, 0)
|
||||
QTreeWidget.dropEvent(self, theEvent)
|
||||
|
||||
# Handle orphaned files differently than tracked files
|
||||
if isNone:
|
||||
self._moveOrphanedItem(sHandle, dHandle)
|
||||
self._cleanOrphanedRoot()
|
||||
else:
|
||||
self._updateItemParent(sHandle)
|
||||
self._updateItemParent(sHandle)
|
||||
|
||||
# If the item does not have the same class as the target,
|
||||
# and the target is not a free root folder, update its class
|
||||
if not isSame and not onFree:
|
||||
if not (isSame or onFree):
|
||||
logger.debug("Item %s class has been changed from %s to %s" % (
|
||||
sHandle,
|
||||
snItem.itemClass.name,
|
||||
@@ -807,9 +797,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
def _getTreeItem(self, tHandle):
|
||||
"""Returns the QTreeWidgetItem of a given item handle.
|
||||
"""
|
||||
if tHandle in self.theMap.keys():
|
||||
return self.theMap[tHandle]
|
||||
return None
|
||||
return self.theMap.get(tHandle, None)
|
||||
|
||||
def _scanChildren(self, theList, theItem, theIndex):
|
||||
"""This is a recursive function returning all items in a tree
|
||||
@@ -833,15 +821,15 @@ class GuiProjectTree(QTreeWidget):
|
||||
tClass = nwItem.itemClass
|
||||
newItem = QTreeWidgetItem([""]*4)
|
||||
|
||||
newItem.setText(self.C_NAME, "")
|
||||
newItem.setText(self.C_COUNT, "0")
|
||||
newItem.setText(self.C_NAME, "")
|
||||
newItem.setText(self.C_COUNT, "0")
|
||||
newItem.setText(self.C_EXPORT, "")
|
||||
newItem.setText(self.C_FLAGS, "")
|
||||
newItem.setText(self.C_FLAGS, "")
|
||||
|
||||
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_EXPORT, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_FLAGS, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft)
|
||||
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
||||
newItem.setTextAlignment(self.C_EXPORT, Qt.AlignLeft)
|
||||
newItem.setTextAlignment(self.C_FLAGS, Qt.AlignLeft)
|
||||
|
||||
newItem.setData(self.C_NAME, Qt.UserRole, tHandle)
|
||||
newItem.setData(self.C_COUNT, Qt.UserRole, 0)
|
||||
@@ -854,8 +842,12 @@ class GuiProjectTree(QTreeWidget):
|
||||
elif nwItem.itemType == nwItemType.TRASH:
|
||||
self.addTopLevelItem(newItem)
|
||||
else:
|
||||
self._addOrphanedRoot()
|
||||
self.orphRoot.addChild(newItem)
|
||||
self.makeAlert(
|
||||
"There is nowhere to add item with name '%s'" % nwItem.itemName, nwAlert.ERROR
|
||||
)
|
||||
del self.theMap[tHandle]
|
||||
return None
|
||||
|
||||
else:
|
||||
byIndex = -1
|
||||
if nHandle is not None and nHandle in self.theMap:
|
||||
@@ -898,39 +890,12 @@ class GuiProjectTree(QTreeWidget):
|
||||
trItem = self._addTreeItem(
|
||||
self.theProject.projTree[trashHandle]
|
||||
)
|
||||
trItem.setExpanded(True)
|
||||
self._setTreeChanged(True)
|
||||
if trItem is not None:
|
||||
trItem.setExpanded(True)
|
||||
self._setTreeChanged(True)
|
||||
|
||||
return trItem
|
||||
|
||||
def _addOrphanedRoot(self):
|
||||
"""Add the special Orphaned Files root item to hold non-root
|
||||
items with no parent set.
|
||||
"""
|
||||
if self.orphRoot is None:
|
||||
newItem = QTreeWidgetItem([""]*4)
|
||||
newItem.setText(self.C_NAME, "Orphaned Files")
|
||||
newItem.setText(self.C_COUNT, "")
|
||||
newItem.setText(self.C_EXPORT, "")
|
||||
newItem.setText(self.C_FLAGS, "")
|
||||
self.addTopLevelItem(newItem)
|
||||
self.orphRoot = newItem
|
||||
newItem.setExpanded(True)
|
||||
newItem.setData(self.C_NAME, Qt.UserRole, "")
|
||||
newItem.setData(self.C_COUNT, Qt.UserRole, 0)
|
||||
newItem.setIcon(self.C_NAME, self.theTheme.getIcon("proj_orphan"))
|
||||
|
||||
return
|
||||
|
||||
def _cleanOrphanedRoot(self):
|
||||
"""Remove the special Orphaned Files root folder if it is empty.
|
||||
"""
|
||||
if self.orphRoot is not None:
|
||||
if self.orphRoot.childCount() == 0:
|
||||
self.takeTopLevelItem(self.indexOfTopLevelItem(self.orphRoot))
|
||||
self.orphRoot = None
|
||||
return
|
||||
|
||||
def _updateItemParent(self, tHandle):
|
||||
"""Update the parent handle of an item so that the information
|
||||
in the project is consistent with the treeView.
|
||||
@@ -951,27 +916,6 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
return True
|
||||
|
||||
def _moveOrphanedItem(self, tHandle, dHandle):
|
||||
"""Move an Orphaned Item to a new dHandle parent item. This
|
||||
function will set all the missing meta data based on the meta
|
||||
data of the destination item.
|
||||
"""
|
||||
trItemS = self._getTreeItem(tHandle)
|
||||
nwItemS = self.theProject.projTree[tHandle]
|
||||
nwItemD = self.theProject.projTree[dHandle]
|
||||
trItemP = trItemS.parent()
|
||||
nwItemS.setClass(nwItemD.itemClass)
|
||||
if trItemP is None:
|
||||
logger.error("Failed to find new parent item of %s" % tHandle)
|
||||
return False
|
||||
|
||||
pHandle = trItemP.data(self.C_NAME, Qt.UserRole)
|
||||
nwItemS.setParent(pHandle)
|
||||
self.setTreeItemValues(tHandle)
|
||||
self._setTreeChanged(True)
|
||||
|
||||
return True
|
||||
|
||||
def _setTreeChanged(self, theState):
|
||||
"""Set the tree change flag, and propagate to the project.
|
||||
"""
|
||||
@@ -1047,12 +991,10 @@ class GuiProjectTreeMenu(QMenu):
|
||||
inTrash = theItem.itemParent == trashHandle and trashHandle is not None
|
||||
isTrash = theItem.itemHandle == trashHandle and trashHandle is not None
|
||||
isFile = theItem.itemType == nwItemType.FILE
|
||||
isOrph = isFile and theItem.itemParent is None
|
||||
|
||||
allowEdit = not (isTrash or isOrph)
|
||||
allowNew = not (isTrash or inTrash or isOrph)
|
||||
allowNew = not (isTrash or inTrash)
|
||||
|
||||
self.editItem.setVisible(allowEdit)
|
||||
self.editItem.setVisible(not isTrash)
|
||||
self.openItem.setVisible(isFile)
|
||||
self.viewItem.setVisible(isFile)
|
||||
self.toggleExp.setVisible(isFile)
|
||||
|
||||
@@ -524,7 +524,6 @@ class GuiIcons:
|
||||
"cls_trash" : (QStyle.SP_DriveHDIcon, "drive-harddisk"),
|
||||
"proj_document" : (QStyle.SP_FileIcon, "x-office-document"),
|
||||
"proj_folder" : (QStyle.SP_DirIcon, "folder"),
|
||||
"proj_orphan" : (QStyle.SP_MessageBoxWarning, "dialog-warning"),
|
||||
"proj_nwx" : (None, None),
|
||||
"status_lang" : (None, None),
|
||||
"status_time" : (None, None),
|
||||
|
||||
+18
-12
@@ -47,7 +47,7 @@ from nw.gui import (
|
||||
GuiTheme, GuiWritingStats
|
||||
)
|
||||
from nw.core import NWProject, NWDoc, NWIndex
|
||||
from nw.constants import nwItemType, nwItemClass, nwAlert
|
||||
from nw.constants import nwItemType, nwItemClass, nwAlert, nwConst
|
||||
from nw.common import getGuiItem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -722,6 +722,12 @@ class GuiMain(QMainWindow):
|
||||
logger.warning("No item selected")
|
||||
return
|
||||
|
||||
tItem = self.theProject.projTree[tHandle]
|
||||
if tItem is None:
|
||||
return
|
||||
if tItem.itemType not in nwConst.REG_TYPES:
|
||||
return
|
||||
|
||||
logger.verbose("Requesting change to item %s" % tHandle)
|
||||
dlgProj = GuiItemEditor(self, self.theProject, tHandle)
|
||||
dlgProj.exec_()
|
||||
@@ -965,17 +971,16 @@ class GuiMain(QMainWindow):
|
||||
logger.error(msgLine)
|
||||
|
||||
# Popup
|
||||
if self.mainConf.showGUI:
|
||||
msgBox = QMessageBox()
|
||||
if theLevel == nwAlert.INFO:
|
||||
msgBox.information(self, "Information", popMsg)
|
||||
elif theLevel == nwAlert.WARN:
|
||||
msgBox.warning(self, "Warning", popMsg)
|
||||
elif theLevel == nwAlert.ERROR:
|
||||
msgBox.critical(self, "Error", popMsg)
|
||||
elif theLevel == nwAlert.BUG:
|
||||
popMsg += "<br>This is a bug!"
|
||||
msgBox.critical(self, "Internal Error", popMsg)
|
||||
msgBox = QMessageBox()
|
||||
if theLevel == nwAlert.INFO:
|
||||
msgBox.information(self, "Information", popMsg)
|
||||
elif theLevel == nwAlert.WARN:
|
||||
msgBox.warning(self, "Warning", popMsg)
|
||||
elif theLevel == nwAlert.ERROR:
|
||||
msgBox.critical(self, "Error", popMsg)
|
||||
elif theLevel == nwAlert.BUG:
|
||||
popMsg += "<br>This is a bug!"
|
||||
msgBox.critical(self, "Internal Error", popMsg)
|
||||
|
||||
return
|
||||
|
||||
@@ -1320,6 +1325,7 @@ class GuiMain(QMainWindow):
|
||||
self.openDocument(tHandle, changeFocus=False, doScroll=False)
|
||||
else:
|
||||
logger.verbose("Requested item %s is a folder" % tHandle)
|
||||
|
||||
return
|
||||
|
||||
def _treeKeyPressReturn(self):
|
||||
|
||||
Reference in New Issue
Block a user