diff --git a/nw/gui/docdetails.py b/nw/gui/docdetails.py index 138fdfe7..2bd9e9ef 100644 --- a/nw/gui/docdetails.py +++ b/nw/gui/docdetails.py @@ -64,17 +64,20 @@ class GuiDocDetails(QFrame): def buildViewBox(self, tHandle): - nwItem = self.theProject.getItem(tHandle) - itemStatus = nwItem.itemStatus - if itemStatus < 0 or itemStatus >= len(self.theProject.statusLabels): - itemStatus = 0 + nwItem = self.theProject.getItem(tHandle) - colTwo = [ - nwItem.itemName, - self.theProject.statusLabels[itemStatus], - nwLabels.CLASS_NAME[nwItem.itemClass], - nwLabels.LAYOUT_NAME[nwItem.itemLayout], - ] + if nwItem is None: + colTwo = [""]*4 + else: + itemStatus = nwItem.itemStatus + if itemStatus < 0 or itemStatus >= len(self.theProject.statusLabels): + itemStatus = 0 + colTwo = [ + nwItem.itemName, + self.theProject.statusLabels[itemStatus], + nwLabels.CLASS_NAME[nwItem.itemClass], + nwLabels.LAYOUT_NAME[nwItem.itemLayout], + ] for nRow in range(4): lblTwo = QLabel(colTwo[nRow]) diff --git a/nw/gui/doctree.py b/nw/gui/doctree.py index 3ee5bc95..dac47b1c 100644 --- a/nw/gui/doctree.py +++ b/nw/gui/doctree.py @@ -40,6 +40,7 @@ class GuiDocTree(QTreeWidget): self.theParent = theParent self.theProject = theProject self.theMap = {} + self.orphRoot = None self.setIconSize(QSize(13,13)) self.setExpandsOnDoubleClick(True) @@ -152,6 +153,8 @@ class GuiDocTree(QTreeWidget): def saveTreeOrder(self): theList = [] for i in range(self.topLevelItemCount()): + if self.topLevelItem(i) == self.orphRoot: + continue theList = self._scanChildren(theList, self.topLevelItem(i), i) self.theProject.setTreeOrder(theList) return True @@ -200,7 +203,12 @@ class GuiDocTree(QTreeWidget): self.theMap[tHandle] = newItem if pHandle is None: - self.addTopLevelItem(newItem) + if nwItem.itemType == nwItemType.ROOT: + self.addTopLevelItem(newItem) + self.theParent.mainMenu.setAvailableRoot() + else: + self._addOrphanedRoot() + self.orphRoot.addChild(newItem) else: self.theMap[pHandle].addChild(newItem) self.propagateCount(tHandle, nwItem.wordCount) @@ -210,7 +218,6 @@ class GuiDocTree(QTreeWidget): if nwItem.itemType == nwItemType.ROOT: newItem.setIcon(self.C_NAME, QIcon.fromTheme("drive-harddisk")) - self.theParent.mainMenu.setAvailableRoot() elif nwItem.itemType == nwItemType.FOLDER: newItem.setIcon(self.C_NAME, QIcon.fromTheme("folder")) elif nwItem.itemType == nwItemType.FILE: @@ -218,6 +225,18 @@ class GuiDocTree(QTreeWidget): return newItem + def _addOrphanedRoot(self): + if self.orphRoot is None: + newItem = QTreeWidgetItem([""]*4) + newItem.setText(self.C_NAME, "Orphaned Files") + newItem.setText(self.C_COUNT, "") + newItem.setText(self.C_FLAGS, "") + newItem.setText(self.C_HANDLE, "") + self.addTopLevelItem(newItem) + self.orphRoot = newItem + newItem.setExpanded(True) + return + def setTreeItemValues(self, tHandle): trItem = self.theMap[tHandle] @@ -248,7 +267,7 @@ class GuiDocTree(QTreeWidget): for i in range(pItem.childCount()): pCount += int(pItem.child(i).text(self.C_COUNT)) pHandle = pItem.text(self.C_HANDLE) - if not nDepth > NWItem.MAX_DEPTH: + if not nDepth > NWItem.MAX_DEPTH and pHandle != "": self.propagateCount(pHandle, pCount, nDepth+1) return @@ -298,14 +317,15 @@ class GuiDocTree(QTreeWidget): snItem = self.theProject.getItem(sHandle) dnItem = self.theProject.getItem(dHandle) isSame = snItem.itemClass == dnItem.itemClass and dnItem.itemType + isNone = snItem.itemClass == nwItemClass.NO_CLASS isFile = dnItem.itemType == nwItemType.FILE isRoot = snItem.itemType == nwItemType.ROOT isOnTop = self.dropIndicatorPosition() == QAbstractItemView.OnItem - if isSame and not (isFile and isOnTop) and not isRoot: - logger.verbose("Drag'n'drop on item %s allowed" % sHandle) + if (isSame or isNone) and not (isFile and isOnTop) and not isRoot: + logger.verbose("Drag'n'drop of item %s accepted" % sHandle) QTreeWidget.dropEvent(self, theEvent) else: - logger.verbose("Drag'n'drop on item %s not allowed" % sHandle) + logger.verbose("Drag'n'drop of item %s not accepted" % sHandle) return diff --git a/nw/project/project.py b/nw/project/project.py index 2ed388ce..acd29b3e 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -13,7 +13,7 @@ import logging import nw -from os import path, mkdir +from os import path, mkdir, listdir from lxml import etree from hashlib import sha256 from datetime import datetime @@ -167,6 +167,8 @@ class NWProject(): self._makeStatusIcons() self.mainConf.setRecent(self.projPath) + self._scanProjectFolder() + return True def saveProject(self): @@ -287,6 +289,56 @@ class NWProject(): # Internal Functions ## + def _scanProjectFolder(self): + + if self.projPath is None: + return + + # First, scan the project data folders + itemList = [] + for subItem in listdir(self.projPath): + if subItem[:5] != "data_": + continue + dataDir = path.join(self.projPath,subItem) + for subFile in listdir(dataDir): + if subFile[-4:] == ".nwd": + newItem = path.join(subItem,subFile) + itemList.append(newItem) + + # Then check the valid files + orphanFiles = [] + for fileItem in itemList: + if len(fileItem) != 28: + # Just to be safe, shouldn't happen + logger.warning("Skipping file %s" % fileItem) + continue + fHandle = fileItem[5]+fileItem[7:19] + if fHandle in self.treeOrder: + logger.verbose("Checking file %s, handle %s: OK" % (fileItem,fHandle)) + else: + logger.verbose("Checking file %s, handle %s: Orphaned" % (fileItem,fHandle)) + orphanFiles.append(fHandle) + + # Report status + if len(orphanFiles) > 0: + logger.warning("Found %d orphaned file(s) in project folder!" % len(orphanFiles)) + else: + logger.verbose("File check OK") + return + + # Handle orphans + nOrph = 0 + for oHandle in orphanFiles: + nOrph += 1 + orItem = NWItem() + orItem.setName("Orphaned File %d" % nOrph) + orItem.setType(nwItemType.FILE) + orItem.setClass(nwItemClass.NO_CLASS) + orItem.setLayout(nwItemLayout.NO_LAYOUT) + self._appendItem(oHandle,None,orItem) + + return + def _countItemDepth(self, tHandle): theDepth = 0 nwItem = self.getItem(tHandle) diff --git a/sample/sampleNovel/data_1/4298de4d9524_main.nwd b/sample/sampleNovel/data_1/4298de4d9524_main.nwd index 3665ee3c..11127dab 100644 --- a/sample/sampleNovel/data_1/4298de4d9524_main.nwd +++ b/sample/sampleNovel/data_1/4298de4d9524_main.nwd @@ -1,3 +1,3 @@ # John Smith -He’s pretty cool. Nor Brad Pitt though. \ No newline at end of file +He’s pretty cool. Not Brad Pitt though. \ No newline at end of file diff --git a/sample/sampleNovel/data_5/3b69b83cdafc_main.nwd b/sample/sampleNovel/data_5/3b69b83cdafc_main.nwd new file mode 100644 index 00000000..9a7abf96 --- /dev/null +++ b/sample/sampleNovel/data_5/3b69b83cdafc_main.nwd @@ -0,0 +1,4 @@ +# My Novel + +**By Jane Doh** + diff --git a/sample/sampleNovel/data_b/3e74dbc1f584_main.nwd b/sample/sampleNovel/data_b/3e74dbc1f584_main.nwd index 9ae46188..bcdf600f 100644 --- a/sample/sampleNovel/data_b/3e74dbc1f584_main.nwd +++ b/sample/sampleNovel/data_b/3e74dbc1f584_main.nwd @@ -1,3 +1,3 @@ # Earth -Third planet from the sun, fairly dense and with lots of people on it. \ No newline at end of file +Third planet from the sun, fairly dense, and with lots of people on it. \ No newline at end of file diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx index 97b33dbc..6cae852c 100644 --- a/sample/sampleNovel/nwProject.nwx +++ b/sample/sampleNovel/nwProject.nwx @@ -1,12 +1,12 @@ - + Sample Project Sample Project Jane Smith Jay Doh - + Novel ROOT