diff --git a/.gitignore b/.gitignore index 25b1c20..fe8374b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ snowflake* *.pyc *.lprof .directory +test_project.zip +test_project_ +Notes.t2t \ No newline at end of file diff --git a/README.md b/README.md index 7dcf003..567285e 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,5 @@ Dépendances: - lxml Optional: -- pyenchant \ No newline at end of file +- pyenchant +- zlib \ No newline at end of file diff --git a/src/loadSave.py b/src/loadSave.py index 3838ba2..be0ca16 100644 --- a/src/loadSave.py +++ b/src/loadSave.py @@ -4,8 +4,35 @@ from qt import * from functions import * from lxml import etree as ET +import zipfile +try: + import zlib # Used with zipfile for compression + compression = zipfile.ZIP_DEFLATED +except: + compression = zipfile.ZIP_STORED -def saveStandardItemModelXML(mdl, xml): +def saveFilesToZip(files, zipname): + """Saves given files to zipname. + files is actually a list of (content, filename).""" + + zf = zipfile.ZipFile(zipname, mode="w") + + for content, filename in files: + zf.writestr(filename, content, compress_type=compression) + + zf.close() + +def loadFilesFromZip(zipname): + """Returns the content of zipfile as a dict of filename:content.""" + zf = zipfile.ZipFile(zipname) + files = {} + for f in zf.namelist(): + files[f] = zf.read(f) + return files + +def saveStandardItemModelXML(mdl, xml=None): + """Saves the given QStandardItemModel to XML. + If xml (filename) is given, saves to xml. Otherwise returns as string.""" root = ET.Element("model") root.attrib["version"] = qApp.applicationVersion() @@ -41,20 +68,28 @@ def saveStandardItemModelXML(mdl, xml): col.text = mdl.data(mdl.index(x, y)) #print(qApp.tr("Saving to {}.").format(xml)) - ET.ElementTree(root).write(xml, encoding="UTF-8", xml_declaration=True, pretty_print=True) + if xml: + ET.ElementTree(root).write(xml, encoding="UTF-8", xml_declaration=True, pretty_print=True) + else: + return ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True) -def loadStandardItemModelXML(mdl, xml): +def loadStandardItemModelXML(mdl, xml, fromString=False): + """Load data to a QStandardItemModel mdl from xml. + By default xml is a filename. If fromString=True, xml is a string containg the data.""" #print(qApp.tr("Loading {}... ").format(xml), end="") - try: - tree = ET.parse(xml) - except: - print("Failed.") - return + if not fromString: + try: + tree = ET.parse(xml) + except: + print("Failed.") + return + else: + root = ET.fromstring(xml) - root = tree.getroot() + #root = tree.getroot() #Header hLabels = [] diff --git a/src/mainWindow.py b/src/mainWindow.py index a0dcef6..4a997c9 100644 --- a/src/mainWindow.py +++ b/src/mainWindow.py @@ -226,7 +226,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.lstDebugLabels.setModel(self.mdlLabels) self.lstDebugStatus.setModel(self.mdlStatus) - self.loadProject("test_project") + self.loadProject("test_project.zip") #################################################################################################### # OUTLINE # @@ -375,7 +375,6 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.loadDatas() # Load settings - settings.load("{}/settings.pickle".format(project)) self.generateViewMenu() self.sldCorkSizeFactor.setValue(settings.corkSizeFactor) self.actSpellcheck.setChecked(settings.spellcheck) @@ -435,29 +434,47 @@ class MainWindow(QMainWindow, Ui_MainWindow): if settings.saveOnQuit: self.saveDatas() - # Save settings - settings.save("{}/settings.pickle".format(self.currentProject)) - # closeEvent QMainWindow.closeEvent(self, event) def saveDatas(self): - saveStandardItemModelXML(self.mdlFlatData, "{}/flatModel.xml".format(self.currentProject)) - saveStandardItemModelXML(self.mdlPersos, "{}/perso.xml".format(self.currentProject)) - saveStandardItemModelXML(self.mdlPersosInfos, "{}/persoInfos.xml".format(self.currentProject)) - saveStandardItemModelXML(self.mdlLabels, "{}/labels.xml".format(self.currentProject)) - saveStandardItemModelXML(self.mdlStatus, "{}/status.xml".format(self.currentProject)) - self.mdlOutline.saveToXML("{}/outline.xml".format(self.currentProject)) + # Saving + files = [] + + files.append((saveStandardItemModelXML(self.mdlFlatData), "flatModel.xml")) + files.append((saveStandardItemModelXML(self.mdlPersos), "perso.xml")) + files.append((saveStandardItemModelXML(self.mdlPersosInfos), "persoInfos.xml")) + files.append((saveStandardItemModelXML(self.mdlLabels), "labels.xml")) + files.append((saveStandardItemModelXML(self.mdlStatus), "status.xml")) + files.append((self.mdlOutline.saveToXML(), "outline.xml")) + files.append((settings.save(),"settings.pickle")) + + saveFilesToZip(files, self.currentProject) + + # Giving some feedback print(self.tr("Project {} saved.").format(self.currentProject)) self.statusBar().showMessage(self.tr("Project {} saved.").format(self.currentProject), 5000) def loadDatas(self): - loadStandardItemModelXML(self.mdlFlatData, "{}/flatModel.xml".format(self.currentProject)) - loadStandardItemModelXML(self.mdlPersos, "{}/perso.xml".format(self.currentProject)) - loadStandardItemModelXML(self.mdlPersosInfos, "{}/persoInfos.xml".format(self.currentProject)) - loadStandardItemModelXML(self.mdlLabels, "{}/labels.xml".format(self.currentProject)) - loadStandardItemModelXML(self.mdlStatus, "{}/status.xml".format(self.currentProject)) - self.mdlOutline.loadFromXML("{}/outline.xml".format(self.currentProject)) + # Loading + files = loadFilesFromZip(self.currentProject) + + if "flatModel.xml" in files: + loadStandardItemModelXML(self.mdlFlatData, files["flatModel.xml"], fromString=True) + if "perso.xml" in files: + loadStandardItemModelXML(self.mdlPersos, files["perso.xml"], fromString=True) + if "persoInfos.xml" in files: + loadStandardItemModelXML(self.mdlPersosInfos, files["persoInfos.xml"], fromString=True) + if "labels.xml" in files: + loadStandardItemModelXML(self.mdlLabels, files["labels.xml"], fromString=True) + if "status.xml" in files: + loadStandardItemModelXML(self.mdlStatus, files["status.xml"], fromString=True) + if "outline.xml" in files: + self.mdlOutline.loadFromXML(files["outline.xml"], fromString=True) + if "settings.pickle" in files: + settings.load(files["settings.pickle"], fromString=True) + + # Giving some feedback print(self.tr("Project {} loaded.").format(self.currentProject)) self.statusBar().showMessage(self.tr("Project {} loaded.").format(self.currentProject), 5000) diff --git a/src/models/outlineModel.py b/src/models/outlineModel.py index 37456b8..a217408 100644 --- a/src/models/outlineModel.py +++ b/src/models/outlineModel.py @@ -296,17 +296,23 @@ class outlineModel(QAbstractItemModel): ################# XML / saving / loading ################# - def saveToXML(self, xml): + def saveToXML(self, xml=None): + "If xml (filename) is given, saves the items to xml. Otherwise returns as string." root = ET.XML(self.rootItem.toXML()) - ET.ElementTree(root).write(xml, encoding="UTF-8", xml_declaration=True, pretty_print=True) + if xml: + ET.ElementTree(root).write(xml, encoding="UTF-8", xml_declaration=True, pretty_print=True) + else: + return ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True) - def loadFromXML(self, xml): - #try: + def loadFromXML(self, xml, fromString=False): + "Load from xml. Assume that xml is a filename. If fromString=True, xml is the content." + if not fromString: root = ET.parse(xml) - self.rootItem = outlineItem(self, xml=ET.tostring(root)) - #except: - #print("N'arrive pas à ouvrir {}".format(xml)) - #return + else: + root = ET.fromstring(xml) + + self.rootItem = outlineItem(self, xml=ET.tostring(root)) + def pathToIndex(self, index, path=""): if not index.isValid(): diff --git a/src/settings.py b/src/settings.py index b69ab15..5e12f11 100644 --- a/src/settings.py +++ b/src/settings.py @@ -33,7 +33,7 @@ autoSave = True autoSaveDelay = 5 saveOnQuit = True -def save(filename): +def save(filename=None): global spellcheck, dict, corkSliderFactor, viewSettings, corkSizeFactor, folderView, lastTab, lastIndex, \ autoSave, autoSaveDelay, saveOnQuit @@ -55,19 +55,27 @@ def save(filename): #print("Saving:") #pp.pprint(allSettings) - f = open(filename, "wb") - pickle.dump(allSettings, f) + if filename: + f = open(filename, "wb") + pickle.dump(allSettings, f) + else: + return pickle.dumps(allSettings) -def load(filename): - try: - global allSettings - - f = open(filename, "rb") - allSettings = pickle.load(f) - - except: - print("{} doesn't exist, cannot load settings.".format(filename)) - return +def load(string, fromString=False): + """Load settings from 'string'. 'string' is the filename of the pickle dump. + If fromString=True, string is the data of the pickle dumps.""" + global allSettings + + if not fromString: + try: + f = open(string, "rb") + allSettings = pickle.load(f) + + except: + print("{} doesn't exist, cannot load settings.".format(string)) + return + else: + allSettings = pickle.loads(string) #pp=pprint.PrettyPrinter(indent=4, compact=False) #print("Loading:") diff --git a/test_project/flatModel.xml b/test_project/flatModel.xml deleted file mode 100644 index 30041cf..0000000 --- a/test_project/flatModel.xml +++ /dev/null @@ -1,60 +0,0 @@ - - -
- - - - -
- - - Titre du livre - Sous-titre - - - Fantasy - CC-BY-SA - Auteur Cool - auteur@cool.com - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Oxygen-Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Bonjour asdasd</p></body></html> - Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - -Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir Bonsoir - - - - - - -
diff --git a/test_project/labels.xml b/test_project/labels.xml deleted file mode 100644 index 1873061..0000000 --- a/test_project/labels.xml +++ /dev/null @@ -1,36 +0,0 @@ - - -
- - - - -
- - - - - - Idée - - - Note - - - Chapitre - - - Scène - - - Nouveau label - - -
diff --git a/test_project/outline.xml b/test_project/outline.xml deleted file mode 100644 index 2047bc7..0000000 --- a/test_project/outline.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test_project/perso.xml b/test_project/perso.xml deleted file mode 100644 index a6a2287..0000000 --- a/test_project/perso.xml +++ /dev/null @@ -1,71 +0,0 @@ - - -
- - - - -
- - - Albert le vert - 0 - 2 - - - - - - - - Quelques notes - - -Pour voir. - - - - Ginette La Barbette - 1 - 1 - - - - - - - - - - - - Nouveau perso avec un nom très très long pour voir comment ça fait - 2 - 0 - - - - - - - - - - - -
diff --git a/test_project/persoInfos.xml b/test_project/persoInfos.xml deleted file mode 100644 index 3feecb7..0000000 --- a/test_project/persoInfos.xml +++ /dev/null @@ -1,36 +0,0 @@ - - -
- - - - -
- - - 1 - 2 - 4 - 5 - - - 12 - - - - - - - - - - - -
diff --git a/test_project/settings.pickle b/test_project/settings.pickle deleted file mode 100644 index 69b20be..0000000 Binary files a/test_project/settings.pickle and /dev/null differ diff --git a/test_project/status.xml b/test_project/status.xml deleted file mode 100644 index 60fb05f..0000000 --- a/test_project/status.xml +++ /dev/null @@ -1,36 +0,0 @@ - - -
- - - - -
- - - - - - TODO - - - Premier brouillon - - - Second brouillon - - - Final - - - Nouveau status - - -