Plain text file format in progress

This commit is contained in:
Olivier Keshavjee 2016-03-05 00:35:14 +01:00
parent 240700ca17
commit af089e8a6a
3 changed files with 162 additions and 34 deletions

View file

@ -8,8 +8,11 @@
import os import os
import zipfile import zipfile
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor
from manuskript import settings from manuskript import settings
from manuskript.functions import mainWindow from manuskript.functions import mainWindow, iconColor
try: try:
import zlib # Used with zipfile for compression import zlib # Used with zipfile for compression
@ -19,6 +22,8 @@ except:
compression = zipfile.ZIP_STORED compression = zipfile.ZIP_STORED
cache = {}
def saveProject(zip=None): def saveProject(zip=None):
""" """
Saves the project. If zip is False, the project is saved as a multitude of plain-text files for the most parts Saves the project. If zip is False, the project is saved as a multitude of plain-text files for the most parts
@ -30,46 +35,153 @@ def saveProject(zip=None):
@return: Nothing @return: Nothing
""" """
if zip is None: if zip is None:
zip = False zip = True
# Fixme # Fixme
files = [] files = []
mw = mainWindow() mw = mainWindow()
# files.append((saveStandardItemModelXML(mw.mdlFlatData), # General infos (book and author)
# "flatModel.xml")) # Saved in plain text, in infos.txt
# # files.append((saveStandardItemModelXML(self.mdlCharacter),
# # "perso.xml"))
# files.append((saveStandardItemModelXML(mw.mdlWorld),
# "world.xml"))
# files.append((saveStandardItemModelXML(mw.mdlLabels),
# "labels.xml"))
# files.append((saveStandardItemModelXML(mw.mdlStatus),
# "status.xml"))
# files.append((saveStandardItemModelXML(mw.mdlPlots),
# "plots.xml"))
# files.append((mw.mdlOutline.saveToXML(),
# "outline.xml"))
# files.append((settings.save(),
# "settings.pickle"))
files.append(("blabla", "test/machin.txt")) path = "infos.txt"
files.append(("youpi", "encore/truc.txt")) content = ""
for name, col in [
("Title", 0),
("Subtitle", 1),
("Serie", 2),
("Volume", 3),
("Genre", 4),
("License", 5),
("Author", 6),
("Email", 7),
]:
val = mw.mdlFlatData.item(0, col).text().strip()
if val:
content += "{name}:{spaces}{value}\n".format(
name=name,
spaces=" " * (15 - len(name)),
value=val
)
files.append((path, content))
# Summary
# In plain text, in summary.txt
path = "summary.txt"
content = ""
for name, col in [
("Situation", 0),
("Sentence", 1),
("Paragraph", 2),
("Page", 3),
("Full", 4),
]:
val = mw.mdlFlatData.item(1, col).text().strip()
val = "\n".join([" " * 13 + l for l in val.split("\n")])[13:]
if val:
content += "{name}:{spaces}{value}\n".format(
name=name,
spaces=" " * (12 - len(name)),
value=val
)
files.append((path, content))
# Label & Status
# In plain text
for mdl, path in [
(mw.mdlStatus, "status.txt"),
(mw.mdlLabels, "labels.txt")
]:
content = ""
# We skip the first row, which is empty and transparent
for i in range(1, mdl.rowCount()):
color = ""
if mdl.data(mdl.index(i, 0), Qt.DecorationRole) is not None:
color = iconColor(mdl.data(mdl.index(i, 0), Qt.DecorationRole)).name(QColor.HexRgb)
color = color if color != "#ff000000" else "#00000000"
text = mdl.data(mdl.index(i, 0))
if text:
content += "{name}{color}\n".format(
name=text,
color= "" if color == "" else ":" + " " * (20 - len(text)) + color
)
files.append((path, content))
# Characters (self.mdlCharacter)
# In a character folder
# TODO
# Texts
# In an outline folder
# TODO
# World (mw.mdlWorld)
# Either in an XML file, or in lots of plain texts?
# More probably text, since there might be writing done in third-party.
# TODO
# Plots (mw.mdlPlots)
# Either in XML or lots of plain texts?
# More probably XML since there is not really a lot if writing to do (third-party)
# TODO
# Settings
# Saved in readable text (json) for easier versionning. But they mustn't be shared, it seems.
# Maybe include them only if zipped?
# Well, for now, we keep them here...
files.append(("settings.txt", settings.save(protocol=0)))
project = mw.currentProject project = mw.currentProject
project = os.path.join( # Save to zip
os.path.dirname(project), if zip:
"_" + os.path.basename(project) project = os.path.join(
) os.path.dirname(project),
"_" + os.path.basename(project)
)
zf = zipfile.ZipFile(project, mode="w") zf = zipfile.ZipFile(project, mode="w")
for content, filename in files: for filename, content in files:
zf.writestr(filename, content, compress_type=compression) zf.writestr(filename, content, compress_type=compression)
zf.close() zf.close()
# Save to plain text
else:
dir = os.path.dirname(project)
folder = os.path.splitext(os.path.basename(project))[0]
print("Saving to folder", folder)
for path, content in files:
filename = os.path.join(dir, folder, path)
os.makedirs(os.path.dirname(filename), exist_ok=True)
print("* Saving file", filename)
# TODO: the first time it saves, it will overwrite everything, since it's not yet in cache.
# Or we have to cache while loading.
if not path in cache or cache[path] != content:
print(" Not in cache or changed: we write")
mode = "w"+ ("b" if type(content) == bytes else "")
with open(filename, mode) as f:
f.write(content)
cache[path] = content
else:
print(" In cache, and identical. Do nothing.")
def loadProject(project): def loadProject(project):
@ -78,4 +190,8 @@ def loadProject(project):
@param project: the filename of the project to open. @param project: the filename of the project to open.
@return: an array of errors, empty if None. @return: an array of errors, empty if None.
""" """
# Don't forget to cache everything that is loaded
# In order to save only what has changed.
pass pass

View file

@ -460,7 +460,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.currentProject = projectName self.currentProject = projectName
QSettings().setValue("lastProject", projectName) QSettings().setValue("lastProject", projectName)
saveProject(version=0) saveProject() # version=0
# Giving some feedback # Giving some feedback
print(self.tr("Project {} saved.").format(self.currentProject)) print(self.tr("Project {} saved.").format(self.currentProject))

View file

@ -1,12 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import collections import collections
import json
import pickle import pickle
from PyQt5.QtWidgets import qApp from PyQt5.QtWidgets import qApp
from manuskript.enums import Outline from manuskript.enums import Outline
# TODO: move some/all of those settings to application settings and not project settings
# in order to allow a shared project between several writers
viewSettings = { viewSettings = {
"Tree": { "Tree": {
"Icon": "Nothing", "Icon": "Nothing",
@ -28,7 +32,8 @@ viewSettings = {
"Background": "Nothing", "Background": "Nothing",
}, },
} }
# Application
spellcheck = False spellcheck = False
dict = None dict = None
corkSizeFactor = 100 corkSizeFactor = 100
@ -81,7 +86,7 @@ frequencyAnalyzer = {
"phraseMax": 5 "phraseMax": 5
} }
def save(filename=None): def save(filename=None, protocol=None):
global spellcheck, dict, corkSliderFactor, viewSettings, corkSizeFactor, folderView, lastTab, openIndexes, \ global spellcheck, dict, corkSliderFactor, viewSettings, corkSizeFactor, folderView, lastTab, openIndexes, \
autoSave, autoSaveDelay, saveOnQuit, autoSaveNoChanges, autoSaveNoChangesDelay, outlineViewColumns, \ autoSave, autoSaveDelay, saveOnQuit, autoSaveNoChanges, autoSaveNoChangesDelay, outlineViewColumns, \
@ -107,7 +112,7 @@ def save(filename=None):
"textEditor":textEditor, "textEditor":textEditor,
"revisions":revisions, "revisions":revisions,
"frequencyAnalyzer": frequencyAnalyzer "frequencyAnalyzer": frequencyAnalyzer
} }
#pp=pprint.PrettyPrinter(indent=4, compact=False) #pp=pprint.PrettyPrinter(indent=4, compact=False)
#print("Saving:") #print("Saving:")
@ -117,8 +122,15 @@ def save(filename=None):
f = open(filename, "wb") f = open(filename, "wb")
pickle.dump(allSettings, f) pickle.dump(allSettings, f)
else: else:
return pickle.dumps(allSettings) if protocol == 0:
# This looks stupid
# But a simple json.dumps with sort_keys will throw a TypeError
# because of unorderable types.
return json.dumps(json.loads(json.dumps(allSettings)), indent=4, sort_keys=True)
else:
return pickle.dumps(allSettings)
def load(string, fromString=False): def load(string, fromString=False):
"""Load settings from 'string'. 'string' is the filename of the pickle dump. """Load settings from 'string'. 'string' is the filename of the pickle dump.
If fromString=True, string is the data of the pickle dumps.""" If fromString=True, string is the data of the pickle dumps."""