mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-09-28 15:31:38 +12:00
ff2cbca028
Some snippets have yet to be converted due to the more complex nature of those snippets, and to keep things neat a separate commit makes more sense for those.
295 lines
9.4 KiB
Python
295 lines
9.4 KiB
Python
#!/usr/bin/env python
|
|
# --!-- coding: utf8 --!--
|
|
|
|
# Version 0 of file saving format.
|
|
# Was used at the beginning and up until version XXX when
|
|
# it was superseded by Version 1, which is more open and flexible
|
|
import os
|
|
import zipfile
|
|
|
|
from PyQt5.QtCore import QModelIndex, Qt
|
|
from PyQt5.QtGui import QColor, QStandardItem
|
|
from PyQt5.QtWidgets import qApp
|
|
from lxml import etree as ET
|
|
|
|
from manuskript import settings
|
|
from manuskript.functions import iconColor, iconFromColorString, mainWindow
|
|
from manuskript.models.characterModel import Character, CharacterInfo
|
|
|
|
import logging
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
try:
|
|
import zlib # Used with zipfile for compression
|
|
|
|
compression = zipfile.ZIP_DEFLATED
|
|
except:
|
|
compression = zipfile.ZIP_STORED
|
|
|
|
###########################################################################################
|
|
# SAVE
|
|
###########################################################################################
|
|
|
|
def saveProject():
|
|
"""
|
|
Saves the whole project. Call this function to save the project in Version 0 format.
|
|
"""
|
|
|
|
files = []
|
|
mw = mainWindow()
|
|
|
|
files.append((saveStandardItemModelXML(mw.mdlFlatData),
|
|
"flatModel.xml"))
|
|
LOGGER.error("File format 0 does not save characters!")
|
|
# files.append((saveStandardItemModelXML(mw.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"))
|
|
|
|
saveFilesToZip(files, mw.currentProject)
|
|
|
|
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 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()
|
|
|
|
# Header
|
|
header = ET.SubElement(root, "header")
|
|
vHeader = ET.SubElement(header, "vertical")
|
|
for x in range(mdl.rowCount()):
|
|
vH = ET.SubElement(vHeader, "label")
|
|
vH.attrib["row"] = str(x)
|
|
vH.attrib["text"] = str(mdl.headerData(x, Qt.Vertical))
|
|
|
|
hHeader = ET.SubElement(header, "horizontal")
|
|
for y in range(mdl.columnCount()):
|
|
hH = ET.SubElement(hHeader, "label")
|
|
hH.attrib["row"] = str(y)
|
|
hH.attrib["text"] = str(mdl.headerData(y, Qt.Horizontal))
|
|
|
|
# Data
|
|
data = ET.SubElement(root, "data")
|
|
saveItem(data, mdl)
|
|
|
|
# LOGGER.info("Saving to {}.".format(xml))
|
|
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 saveItem(root, mdl, parent=QModelIndex()):
|
|
for x in range(mdl.rowCount(parent)):
|
|
row = ET.SubElement(root, "row")
|
|
row.attrib["row"] = str(x)
|
|
|
|
for y in range(mdl.columnCount(parent)):
|
|
col = ET.SubElement(row, "col")
|
|
col.attrib["col"] = str(y)
|
|
if mdl.data(mdl.index(x, y, parent), Qt.DecorationRole) != None:
|
|
color = iconColor(mdl.data(mdl.index(x, y, parent), Qt.DecorationRole)).name(QColor.HexArgb)
|
|
col.attrib["color"] = color if color != "#ff000000" else "#00000000"
|
|
if mdl.data(mdl.index(x, y, parent)) != "":
|
|
col.text = mdl.data(mdl.index(x, y, parent))
|
|
if mdl.hasChildren(mdl.index(x, y, parent)):
|
|
saveItem(col, mdl, mdl.index(x, y, parent))
|
|
|
|
###########################################################################################
|
|
# LOAD
|
|
###########################################################################################
|
|
|
|
def loadProject(project):
|
|
|
|
files = loadFilesFromZip(project)
|
|
mw = mainWindow()
|
|
|
|
errors = []
|
|
|
|
if "flatModel.xml" in files:
|
|
loadStandardItemModelXML(mw.mdlFlatData,
|
|
files["flatModel.xml"], fromString=True)
|
|
else:
|
|
errors.append("flatModel.xml")
|
|
|
|
if "perso.xml" in files:
|
|
loadStandardItemModelXMLForCharacters(mw.mdlCharacter, files["perso.xml"])
|
|
else:
|
|
errors.append("perso.xml")
|
|
|
|
if "world.xml" in files:
|
|
loadStandardItemModelXML(mw.mdlWorld,
|
|
files["world.xml"], fromString=True)
|
|
else:
|
|
errors.append("world.xml")
|
|
|
|
if "labels.xml" in files:
|
|
loadStandardItemModelXML(mw.mdlLabels,
|
|
files["labels.xml"], fromString=True)
|
|
else:
|
|
errors.append("labels.xml")
|
|
|
|
if "status.xml" in files:
|
|
loadStandardItemModelXML(mw.mdlStatus,
|
|
files["status.xml"], fromString=True)
|
|
else:
|
|
errors.append("status.xml")
|
|
|
|
if "plots.xml" in files:
|
|
loadStandardItemModelXML(mw.mdlPlots,
|
|
files["plots.xml"], fromString=True)
|
|
else:
|
|
errors.append("plots.xml")
|
|
|
|
if "outline.xml" in files:
|
|
mw.mdlOutline.loadFromXML(files["outline.xml"], fromString=True)
|
|
else:
|
|
errors.append("outline.xml")
|
|
|
|
if "settings.pickle" in files:
|
|
settings.load(files["settings.pickle"], fromString=True)
|
|
else:
|
|
errors.append("settings.pickle")
|
|
|
|
return errors
|
|
|
|
|
|
def loadFilesFromZip(zipname):
|
|
"""Returns the content of zipfile as a dict of filename:content."""
|
|
zf = zipfile.ZipFile(zipname)
|
|
files = {}
|
|
for f in zf.namelist():
|
|
# Some archiving programs (e.g. 7-Zip) also store entries for the directories when
|
|
# creating an archive. We have no use for these entries; skip them entirely.
|
|
if f[-1:] != '/':
|
|
files[os.path.normpath(f)] = zf.read(f)
|
|
return files
|
|
|
|
|
|
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 containing the data."""
|
|
|
|
# LOGGER.info("Loading {}...".format(xml))
|
|
|
|
if not fromString:
|
|
try:
|
|
tree = ET.parse(xml)
|
|
except:
|
|
LOGGER.error("Failed to load XML for QStandardItemModel (%s).", xml)
|
|
return
|
|
else:
|
|
root = ET.fromstring(xml)
|
|
|
|
# root = tree.getroot()
|
|
|
|
# Header
|
|
hLabels = []
|
|
vLabels = []
|
|
for l in root.find("header").find("horizontal").findall("label"):
|
|
hLabels.append(l.attrib["text"])
|
|
for l in root.find("header").find("vertical").findall("label"):
|
|
vLabels.append(l.attrib["text"])
|
|
|
|
# LOGGER.debug(root.find("header").find("vertical").text)
|
|
|
|
# mdl.setVerticalHeaderLabels(vLabels)
|
|
# mdl.setHorizontalHeaderLabels(hLabels)
|
|
|
|
# Populates with empty items
|
|
for i in enumerate(vLabels):
|
|
row = []
|
|
for r in enumerate(hLabels):
|
|
row.append(QStandardItem())
|
|
mdl.appendRow(row)
|
|
|
|
# Data
|
|
data = root.find("data")
|
|
loadItem(data, mdl)
|
|
|
|
return True
|
|
|
|
|
|
def loadItem(root, mdl, parent=QModelIndex()):
|
|
for row in root:
|
|
r = int(row.attrib["row"])
|
|
for col in row:
|
|
c = int(col.attrib["col"])
|
|
item = mdl.itemFromIndex(mdl.index(r, c, parent))
|
|
if not item:
|
|
item = QStandardItem()
|
|
mdl.itemFromIndex(parent).setChild(r, c, item)
|
|
|
|
if col.text:
|
|
# mdl.setData(mdl.index(r, c, parent), col.text)
|
|
item.setText(col.text)
|
|
|
|
if "color" in col.attrib:
|
|
# mdl.itemFromIndex(mdl.index(r, c, parent)).setIcon(iconFromColorString(col.attrib["color"]))
|
|
item.setIcon(iconFromColorString(col.attrib["color"]))
|
|
|
|
if len(col) != 0:
|
|
# loadItem(col, mdl, mdl.index(r, c, parent))
|
|
loadItem(col, mdl, mdl.indexFromItem(item))
|
|
|
|
|
|
def loadStandardItemModelXMLForCharacters(mdl, xml):
|
|
"""
|
|
Loads a standardItemModel saved to XML by version 0, but for the new characterModel.
|
|
@param mdl: characterModel
|
|
@param xml: the content of the xml
|
|
@return: nothing
|
|
"""
|
|
mdl = mainWindow().mdlCharacter
|
|
root = ET.fromstring(xml)
|
|
data = root.find("data")
|
|
|
|
for row in data:
|
|
char = Character(mdl)
|
|
|
|
for col in row:
|
|
c = int(col.attrib["col"])
|
|
|
|
# Value
|
|
if col.text:
|
|
char._data[c] = col.text
|
|
|
|
# Color
|
|
if "color" in col.attrib:
|
|
char.setColor(QColor(col.attrib["color"]))
|
|
|
|
# Infos
|
|
if len(col) != 0:
|
|
for rrow in col:
|
|
info = CharacterInfo(char)
|
|
for ccol in rrow:
|
|
cc = int(ccol.attrib["col"])
|
|
if cc == 11 and ccol.text:
|
|
info.description = ccol.text
|
|
if cc == 12 and ccol.text:
|
|
info.value = ccol.text
|
|
char.infos.append(info)
|
|
|
|
mdl.characters.append(char)
|