def loadProject(project, zip=None): """ Loads a project. @param project: the filename of the project to open. @param zip: whether the project is a zipped or not. @return: an array of errors, empty if None. """ mw = mainWindow() errors = [] #################################################################################################################### # Read and store everything in a dict log("\nLoading {} ({})".format(project, "ZIP" if zip else "not zip")) if zip: files = loadFilesFromZip(project) # Decode files for f in files: if f[-4:] not in [".xml", "opml"]: files[f] = files[f].decode("utf-8") else: # Project path dir = os.path.dirname(project) # Folder containing file: name of the project file (without .msk extension) folder = os.path.splitext(os.path.basename(project))[0] # The full path towards the folder containing files path = os.path.join(dir, folder, "") files = {} for dirpath, dirnames, filenames in os.walk(path): p = dirpath.replace(path, "") for f in filenames: # mode = "r" + ("b" if f[-4:] in [".xml", "opml"] else "") if f[-4:] in [".xml", "opml"]: with open(os.path.join(dirpath, f), "rb") as fo: files[os.path.join(p, f)] = fo.read() else: with open(os.path.join(dirpath, f), "r", encoding="utf8") as fo: files[os.path.join(p, f)] = fo.read() # Saves to cache (only if we loaded from disk and not zip) global cache cache = files # FIXME: watch directory for changes # Sort files by keys files = OrderedDict(sorted(files.items())) #################################################################################################################### # Settings if "settings.txt" in files: settings.load(files["settings.txt"], fromString=True, protocol=0) else: errors.append("settings.txt") # Just to be sure settings.saveToZip = zip settings.defaultTextType = "md" #################################################################################################################### # Labels mdl = mw.mdlLabels mdl.appendRow(QStandardItem("")) # Empty = No labels if "labels.txt" in files: log("\nReading labels:") for s in files["labels.txt"].split("\n"): if not s: continue m = re.search(r"^(.*?):\s*(.*)$", s) txt = m.group(1) col = m.group(2) log("* Add status: {} ({})".format(txt, col)) icon = iconFromColorString(col) mdl.appendRow(QStandardItem(icon, txt)) else: errors.append("labels.txt") #################################################################################################################### # Status mdl = mw.mdlStatus mdl.appendRow(QStandardItem("")) # Empty = No status if "status.txt" in files: log("\nReading Status:") for s in files["status.txt"].split("\n"): if not s: continue log("* Add status:", s) mdl.appendRow(QStandardItem(s)) else: errors.append("status.txt") #################################################################################################################### # Infos mdl = mw.mdlFlatData if "infos.txt" in files: md, body = parseMMDFile(files["infos.txt"], asDict=True) row = [] for name in ["Title", "Subtitle", "Serie", "Volume", "Genre", "License", "Author", "Email"]: row.append(QStandardItem(md.get(name, ""))) mdl.appendRow(row) else: errors.append("infos.txt") #################################################################################################################### # Summary mdl = mw.mdlFlatData if "summary.txt" in files: md, body = parseMMDFile(files["summary.txt"], asDict=True) row = [] for name in ["Situation", "Sentence", "Paragraph", "Page", "Full"]: row.append(QStandardItem(md.get(name, ""))) mdl.appendRow(row) else: errors.append("summary.txt") #################################################################################################################### # Plots mdl = mw.mdlPlots if "plots.xml" in files: log("\nReading plots:") # xml = bytearray(files["plots.xml"], "utf-8") root = ET.fromstring(files["plots.xml"]) for plot in root: # Create row row = getStandardItemRowFromXMLEnum(plot, Plot) # Log log("* Add plot: ", row[0].text()) # Characters if row[Plot.characters.value].text(): IDs = row[Plot.characters.value].text().split(",") item = QStandardItem() for ID in IDs: item.appendRow(QStandardItem(ID.strip())) row[Plot.characters.value] = item # Subplots for step in plot: row[Plot.steps.value].appendRow( getStandardItemRowFromXMLEnum(step, PlotStep) ) # Add row to the model mdl.appendRow(row) else: errors.append("plots.xml") #################################################################################################################### # World mdl = mw.mdlWorld if "world.opml" in files: log("\nReading World:") # xml = bytearray(files["plots.xml"], "utf-8") root = ET.fromstring(files["world.opml"]) body = root.find("body") for outline in body: row = getOutlineItem(outline, World) mdl.appendRow(row) else: errors.append("world.opml") #################################################################################################################### # Characters mdl = mw.mdlCharacter log("\nReading Characters:") for f in [f for f in files if "characters" in f]: md, body = parseMMDFile(files[f]) c = mdl.addCharacter() c.lastPath = f color = False for desc, val in md: # Base infos if desc in characterMap.values(): key = [key for key, value in characterMap.items() if value == desc][0] index = c.index(key.value) mdl.setData(index, val) # Character color elif desc == "Color" and not color: c.setColor(QColor(val)) # We remember the first time we found "Color": it is the icon color. # If "Color" comes a second time, it is a Character's info. color = True # Character's infos else: c.infos.append(CharacterInfo(c, desc, val)) 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 parentLastPath = "outline" for i in split: if last: parent = parent[last] parentLastPath = os.path.join(parentLastPath, last) last = i if not i in parent: # If not last item, then it is a folder if i != split[-1]: parent[i] = OrderedDict() # If file, we store it else: parent[i] = files[f] # We store f to add it later as lastPath parent[i + ":lastPath"] = os.path.join(parentLastPath, i) # 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 loadProject(project, zip=None): """ Loads a project. @param project: the filename of the project to open. @param zip: whether the project is a zipped or not. @return: an array of errors, empty if None. """ mw = mainWindow() errors = [] #################################################################################################################### # Read and store everything in a dict log("\nLoading {} ({})".format(project, "ZIP" if zip else "not zip")) if zip: files = loadFilesFromZip(project) # Decode files for f in files: if f[-4:] not in [".xml", "opml"]: files[f] = files[f].decode("utf-8") else: # Project path dir = os.path.dirname(project) # Folder containing file: name of the project file (without .msk extension) folder = os.path.splitext(os.path.basename(project))[0] # The full path towards the folder containing files path = os.path.join(dir, folder, "") files = {} for dirpath, dirnames, filenames in os.walk(path): p = dirpath.replace(path, "") for f in filenames: # mode = "r" + ("b" if f[-4:] in [".xml", "opml"] else "") if f[-4:] in [".xml", "opml"]: with open(os.path.join(dirpath, f), "rb") as fo: files[os.path.join(p, f)] = fo.read() else: with open(os.path.join(dirpath, f), "r", encoding="utf8") as fo: files[os.path.join(p, f)] = fo.read() # Saves to cache (only if we loaded from disk and not zip) global cache cache = files # FIXME: watch directory for changes # Sort files by keys files = OrderedDict(sorted(files.items())) #################################################################################################################### # Settings if "settings.txt" in files: settings.load(files["settings.txt"], fromString=True, protocol=0) else: errors.append("settings.txt") # Just to be sure settings.saveToZip = zip #################################################################################################################### # Labels mdl = mw.mdlLabels mdl.appendRow(QStandardItem("")) # Empty = No labels if "labels.txt" in files: log("\nReading labels:") for s in files["labels.txt"].split("\n"): if not s: continue m = re.search(r"^(.*?):\s*(.*)$", s) txt = m.group(1) col = m.group(2) log("* Add status: {} ({})".format(txt, col)) icon = iconFromColorString(col) mdl.appendRow(QStandardItem(icon, txt)) else: errors.append("labels.txt") #################################################################################################################### # Status mdl = mw.mdlStatus mdl.appendRow(QStandardItem("")) # Empty = No status if "status.txt" in files: log("\nReading Status:") for s in files["status.txt"].split("\n"): if not s: continue log("* Add status:", s) mdl.appendRow(QStandardItem(s)) else: errors.append("status.txt") #################################################################################################################### # Infos mdl = mw.mdlFlatData if "infos.txt" in files: md, body = parseMMDFile(files["infos.txt"], asDict=True) row = [] for name in ["Title", "Subtitle", "Serie", "Volume", "Genre", "License", "Author", "Email"]: row.append(QStandardItem(md.get(name, ""))) mdl.appendRow(row) else: errors.append("infos.txt") #################################################################################################################### # Summary mdl = mw.mdlFlatData if "summary.txt" in files: md, body = parseMMDFile(files["summary.txt"], asDict=True) row = [] for name in ["Situation", "Sentence", "Paragraph", "Page", "Full"]: row.append(QStandardItem(md.get(name, ""))) mdl.appendRow(row) else: errors.append("summary.txt") #################################################################################################################### # Plots mdl = mw.mdlPlots if "plots.xml" in files: log("\nReading plots:") # xml = bytearray(files["plots.xml"], "utf-8") root = ET.fromstring(files["plots.xml"]) for plot in root: # Create row row = getStandardItemRowFromXMLEnum(plot, Plot) # Log log("* Add plot: ", row[0].text()) # Characters if row[Plot.characters.value].text(): IDs = row[Plot.characters.value].text().split(",") item = QStandardItem() for ID in IDs: item.appendRow(QStandardItem(ID.strip())) row[Plot.characters.value] = item # Subplots for step in plot: row[Plot.steps.value].appendRow( getStandardItemRowFromXMLEnum(step, PlotStep) ) # Add row to the model mdl.appendRow(row) else: errors.append("plots.xml") #################################################################################################################### # World mdl = mw.mdlWorld if "world.opml" in files: log("\nReading World:") # xml = bytearray(files["plots.xml"], "utf-8") root = ET.fromstring(files["world.opml"]) body = root.find("body") for outline in body: row = getOutlineItem(outline, World) mdl.appendRow(row) else: errors.append("world.opml") #################################################################################################################### # Characters mdl = mw.mdlCharacter log("\nReading Characters:") for f in [f for f in files if "characters" in f]: md, body = parseMMDFile(files[f]) c = mdl.addCharacter() c.lastPath = f color = False for desc, val in md: # Base infos if desc in characterMap.values(): key = [key for key, value in characterMap.items() if value == desc][0] index = c.index(key.value) mdl.setData(index, val) # Character color elif desc == "Color" and not color: c.setColor(QColor(val)) # We remember the first time we found "Color": it is the icon color. # If "Color" comes a second time, it is a Character's info. color = True # Character's infos else: c.infos.append(CharacterInfo(c, desc, val)) 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 parentLastPath = "outline" for i in split: if last: parent = parent[last] parentLastPath = os.path.join(parentLastPath, last) last = i if not i in parent: # If not last item, then it is a folder if i != split[-1]: parent[i] = OrderedDict() # If file, we store it else: parent[i] = files[f] # We store f to add it later as lastPath parent[i + ":lastPath"] = os.path.join(parentLastPath, i) # 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