From b26de717a9f1022b5aac9da4b1d82e5750a5bc4b Mon Sep 17 00:00:00 2001 From: Olivier Keshavjee Date: Thu, 10 Mar 2016 13:10:31 +0100 Subject: [PATCH] Seems that loading works --- manuskript/load_save/version_1.py | 163 +++++++++++++++++++++++++----- manuskript/models/outlineModel.py | 9 +- 2 files changed, 144 insertions(+), 28 deletions(-) diff --git a/manuskript/load_save/version_1.py b/manuskript/load_save/version_1.py index e38af59..6aecb19 100644 --- a/manuskript/load_save/version_1.py +++ b/manuskript/load_save/version_1.py @@ -23,6 +23,7 @@ from lxml import etree as ET from manuskript.load_save.version_0 import loadFilesFromZip from manuskript.models.characterModel import CharacterInfo +from manuskript.models.outlineModel import outlineItem try: import zlib # Used with zipfile for compression @@ -573,15 +574,6 @@ def outlineToMMD(item): content += "\n\n" content += item.data(Outline.text.value) - # Saving revisions - # TODO: saving revisions? - # rev = item.revisions() - # for r in rev: - # revItem = ET.Element("revision") - # revItem.set("timestamp", str(r[0])) - # revItem.set("text", r[1]) - # item.append(revItem) - return content ######################################################################################################################## @@ -596,9 +588,6 @@ def loadProject(project, zip=None): @return: an array of errors, empty if None. """ - # FIXME: Don't forget to cache everything that is loaded - # In order to save only what has changed. - mw = mainWindow() errors = [] @@ -632,6 +621,12 @@ def loadProject(project, zip=None): with open(os.path.join(dirpath, f), mode) as fo: files[os.path.join(p, f)] = fo.read() + # Sort files by keys + files = OrderedDict(sorted(files.items())) + + # Saves to cache + cache = files + #################################################################################################################### # Settings @@ -792,21 +787,138 @@ def loadProject(project, zip=None): log("* Adds {} ({})".format(c.name(), c.ID())) + #################################################################################################################### + # Texts + # We read outline form the outline folder. If revisions are saved, then there's also a revisions.xml which contains + # everything, but the outline folder takes precedence (in cases it's been edited outside of manuksript. + + mdl = mw.mdlOutline + log("\nReading outline:") + paths = [f for f in files if "outline" in f] + outline = OrderedDict() + + # We create a structure of imbricated OrderedDict to store the whole tree. + for f in paths: + split = f.split(os.path.sep)[1:] + # log("* ", split) + + last = "" + parent = outline + for i in split: + if last: + parent = parent[last] + last = i + + if not i in parent: + # If not last item, then it is folder + if i != split[-1]: + parent[i] = OrderedDict() + + # If file, we store it + else: + parent[i] = files[f] + + # We now just have to recursively add items. + addTextItems(mdl, outline) + + # Adds revisions + if "revisions.xml" in files: + root = ET.fromstring(files["revisions.xml"]) + appendRevisions(mdl, root) + + # Check IDS + mdl.rootItem.checkIDs() + + return errors + + +def addTextItems(mdl, odict, parent=None): + """ + Adds a text / outline items from an OrderedDict. + @param mdl: model to add to + @param odict: OrderedDict + @return: nothing + """ + if parent is None: + parent = mdl.rootItem + + for k in odict: + + # In case k is a folder: + if type(odict[k]) == OrderedDict and "folder.txt" in odict[k]: + + # Adds folder + log("{}* Adds {} to {} (folder)".format(" " * parent.level(), k, parent.title())) + item = outlineFromMMD(odict[k]["folder.txt"], parent=parent) + + # Read content + addTextItems(mdl, odict[k], parent=item) + + # In case it is not + elif k != "folder.txt": + log("{}* Adds {} to {} (file)".format(" " * parent.level(), k, parent.title())) + item = outlineFromMMD(odict[k], parent=parent) + + +def outlineFromMMD(text, parent): + """ + Creates outlineItem from multimarkdown file. + @param text: content of the file + @param parent: appends item to parent (outlineItem) + @return: outlineItem + """ + + item = outlineItem(parent=parent) + md, body = parseMMDFile(text, asDict=True) + + # Store metadata + for k in md: + if k in Outline.__members__: + item.setData(Outline.__members__[k].value, str(md[k])) + + # Store body + item.setData(Outline.text.value, str(body)) + + # FIXME: add lastpath + + return item + + +def appendRevisions(mdl, root): + """ + Parse etree item to find outlineItem's with revisions, and adds them to model `mdl`. + @param mdl: outlineModel + @param root: etree + @return: nothing + """ + for child in root: + # Recursively go through items + if child.tag == "outlineItem": + appendRevisions(mdl, child) + + # Revision found. + elif child.tag == "revision": + # Get root's ID + ID = root.attrib["ID"] + if not ID: + log("* Serious problem: no ID!") + return + + # Find outline item in model + item = mdl.getItemByID(ID) + + # Store revision + log("* Appends revision ({}) to {}".format(child.attrib["timestamp"], item.title())) + item.appendRevision(child.attrib["timestamp"], child.attrib["text"]) - # if "perso.xml" in files: - # loadStandardItemModelXMLForCharacters(mw.mdlCharacter, files["perso.xml"]) - # else: - # errors.append("perso.xml") - # - # - # if "outline.xml" in files: - # mw.mdlOutline.loadFromXML(files["outline.xml"], fromString=True) - # else: - # errors.append("outline.xml") - # - # return errors def getOutlineItem(item, enum): + """ + Reads outline items from an opml file. Returns a row of QStandardItem, easy to add to a QStandardItemModel. + @param item: etree item + @param enum: enum to read keys from + @return: [QStandardItem] + """ row = getStandardItemRowFromXMLEnum(item, enum) log("* Add worldItem:", row[0].text()) for child in item: @@ -815,6 +927,7 @@ def getOutlineItem(item, enum): return row + def getStandardItemRowFromXMLEnum(item, enum): """ Reads and etree item and creates a row of QStandardItems by cross-referencing an enum. @@ -880,7 +993,7 @@ def parseMMDFile(text, asDict=False): mdd[descr] = val else: - body.append[s] + body.append(s) # We remove the second empty line (since we save with two empty lines) if body and body[0] == "": diff --git a/manuskript/models/outlineModel.py b/manuskript/models/outlineModel.py index 55d676c..564c818 100644 --- a/manuskript/models/outlineModel.py +++ b/manuskript/models/outlineModel.py @@ -77,9 +77,7 @@ class outlineModel(QAbstractItemModel): in columns ``columns`` (being a list of int).""" return self.rootItem.findItemsContaining(text, columns, mainWindow(), caseSensitive) - def getIndexByID(self, ID): - "Returns the index of item whose ID is ``ID``. If none, returns QModelIndex()." - + def getItemByID(self, ID): def search(item): if item.ID() == ID: return item @@ -89,6 +87,11 @@ class outlineModel(QAbstractItemModel): return r item = search(self.rootItem) + return item + + def getIndexByID(self, ID): + "Returns the index of item whose ID is ``ID``. If none, returns QModelIndex()." + item = self.getItemByID(ID) if not item: return QModelIndex() else: