From 75adcdf6791f7548d7273a2893d9f0f4c26371ee Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sat, 9 May 2020 13:59:57 +0200 Subject: [PATCH] Can now restore document label for orphaned files --- nw/common.py | 17 ++++++++++++ nw/core/document.py | 63 +++++++++++++++++++++++++++++++++++++-------- nw/core/project.py | 14 ++++++++-- nw/guimain.py | 2 +- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/nw/common.py b/nw/common.py index 727f74c0..9f4b8011 100644 --- a/nw/common.py +++ b/nw/common.py @@ -77,6 +77,20 @@ def checkBool(checkValue, defaultValue, allowNone=False): return defaultValue return defaultValue +def isHandle(theString): + """Check if a string is a valid novelWriter handle. + Note: This is case sensitive. Must be lower case! + """ + if not isinstance(theString, str): + return False + if len(theString) != 13: + return False + invalidChar = False + for c in theString: + if c not in "0123456789abcdef": + invalidChar = True + return not invalidChar + def colRange(rgbStart, rgbEnd, nStep): if len(rgbStart) != 3 and len(rgbEnd) != 3 and nStep < 1: @@ -127,6 +141,9 @@ def formatInt(theInt): return "%d" % theInt def formatTimeStamp(theTime, fileSafe=False): + """Take a number (on the format returned by time.time()) and convert + it to a timestamp string. + """ if fileSafe: return datetime.fromtimestamp(theTime).strftime(nwConst.fStampFmt) else: diff --git a/nw/core/document.py b/nw/core/document.py index 17b3203f..aaef4e9e 100644 --- a/nw/core/document.py +++ b/nw/core/document.py @@ -31,6 +31,7 @@ import nw from os import path, mkdir, rename, unlink from nw.constants import nwAlert +from nw.common import isHandle logger = logging.getLogger(__name__) @@ -68,25 +69,29 @@ class NWDoc(): self.docMeta = "" return - def openDocument(self, tHandle, showStatus=True): + def openDocument(self, tHandle, showStatus=True, isOrphan=False): """Open a document from handle, capturing potential file system errors and parse meta data. """ self.docHandle = tHandle - self.theItem = self.theProject.projTree[tHandle] + if not isOrphan: + self.theItem = self.theProject.projTree[tHandle] + else: + self.theItem = None - if self.theItem is None: + if self.theItem is None and not isOrphan: self.clearDocument() return None # By default, the document is editable. # Except for files in the trash folder. self.docEditable = True - if self.theItem.parHandle == self.theProject.projTree.trashRoot(): - self.docEditable = False + if self.theItem is not None: + if self.theItem.parHandle == self.theProject.projTree.trashRoot(): + self.docEditable = False - docDir, docFile = self.assemblePath(self.docHandle, self.FILE_MN) + docDir, docFile = self._assemblePath(self.docHandle, self.FILE_MN) self.fileLoc = path.join(docDir,docFile) logger.debug("Opening document %s" % self.fileLoc) dataDir = path.join(self.theProject.projPath, docDir) @@ -100,7 +105,7 @@ class NWDoc(): fstLine = inFile.readline() if fstLine.startswith("%%~ "): # This is the meta line - self.docMeta = fstLine.strip() + self.docMeta = fstLine[4:].strip() else: theText = fstLine theText += inFile.read() @@ -120,7 +125,7 @@ class NWDoc(): logger.verbose("DocMeta: '%s'" % self.docMeta) - if showStatus: + if showStatus and not isOrphan: self.theParent.statusBar.setStatus("Opened Document: %s" % self.theItem.itemName) return theText @@ -133,7 +138,7 @@ class NWDoc(): if self.docHandle is None or not self.docEditable: return False - docDir, docFile = self.assemblePath(self.docHandle, self.FILE_MN) + docDir, docFile = self._assemblePath(self.docHandle, self.FILE_MN) logger.debug("Saving document %s" % path.join(docDir,docFile)) dataPath = path.join(self.theProject.projPath, docDir) docPath = path.join(dataPath, docFile) @@ -171,7 +176,7 @@ class NWDoc(): """Permanently delete a document source file and its backups from the project data folder. """ - docDir, docFile = self.assemblePath(tHandle, self.FILE_MN) + docDir, docFile = self._assemblePath(tHandle, self.FILE_MN) dataPath = path.join(self.theProject.projPath, docDir) chkList = [] chkList.append(path.join(dataPath, docFile)) @@ -187,8 +192,44 @@ class NWDoc(): return False return True + ## + # Getters + ## + + def getMeta(self): + """Parses the document meta tag and returns the path and name as + a list and a string. + """ + + if len(self.docMeta) < 14: + # Not enough information + return "", [] + + theMeta = self.docMeta + + # Scan for handles + thePath = [] + for n in range(200): + if len(theMeta) < 14: + break + if theMeta[13] == ":": + theHandle = theMeta[:13] + if isHandle(theHandle): + thePath.append(theHandle) + theMeta = theMeta[14:] + else: + break + else: + break + + return theMeta, thePath + + ## + # Internal Functions + ## + @staticmethod - def assemblePath(tHandle, docExt): + def _assemblePath(tHandle, docExt): if tHandle is None: return None, None docDir = "data_"+tHandle[0] diff --git a/nw/core/project.py b/nw/core/project.py index c2c24a9d..b3cad92f 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -41,6 +41,7 @@ from shutil import make_archive from nw.gui.tools import OptionState from nw.core.tools import projectMaintenance +from nw.core.document import NWDoc from nw.common import checkString, checkBool, checkInt, formatTimeStamp from nw.constants import ( nwFiles, nwConst, nwItemType, nwItemClass, nwItemLayout, nwAlert @@ -913,11 +914,20 @@ class NWProject(): return # Handle orphans + aDoc = NWDoc(self, self.theParent) nOrph = 0 for oHandle in orphanFiles: - nOrph += 1 + + # Look for meta data + if aDoc.openDocument(oHandle, showStatus=False, isOrphan=True): + oName, oPath = aDoc.getMeta() + aDoc.clearDocument() + else: + nOrph += 1 + oName = "Orphaned File %d" % nOrph + orphItem = NWItem(self) - orphItem.setName("Orphaned File %d" % nOrph) + orphItem.setName(oName) orphItem.setType(nwItemType.FILE) orphItem.setClass(nwItemClass.NO_CLASS) orphItem.setLayout(nwItemLayout.NO_LAYOUT) diff --git a/nw/guimain.py b/nw/guimain.py index b3356301..2f1380bd 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -404,7 +404,7 @@ class GuiMain(QMainWindow): else: return False - # project is loaded + # Project is loaded self.hasProject = True # Load the tag index