Merge: adds new file format

This commit is contained in:
Olivier Keshavjee 2016-03-10 14:15:42 +01:00
commit 468e2e0dd7
38 changed files with 2076 additions and 710 deletions

3
.gitignore vendored
View file

@ -10,4 +10,5 @@ ExportTest
icons/Numix
.idea
dist
build
build
test-projects

View file

@ -1669,7 +1669,7 @@ des lignes:</translation>
</message>
</context>
<context>
<name>outlinePersoDelegate</name>
<name>outlineCharacterDelegate</name>
<message>
<location filename="../manuskript/ui/views/outlineDelegates.py" line="126"/>
<source>None</source>

View file

@ -10,7 +10,7 @@ run: $(UIs)
bin/manuskript
debug: $(UIs)
gdb --args python3 manuskript/main.py
gdb --args python3 bin/manuskript
lineprof:
kernprof -l -v manuskript/main.py

View file

@ -9,7 +9,7 @@ from enum import Enum
#def enum(**enums):
#return type(str('Enum'), (), enums)
class Perso(Enum):
class Character(Enum):
name = 0
ID = 1
importance = 2
@ -21,20 +21,18 @@ class Perso(Enum):
summaryPara = 8
summaryFull = 9
notes = 10
infoName = 11
infoData = 12
class Plot(Enum):
name = 0
ID = 1
importance = 2
persos = 3
characters = 3
description = 4
result = 5
subplots = 6
steps = 6
summary = 7
class Subplot(Enum):
class PlotStep(Enum):
name = 0
ID = 1
meta = 2
@ -66,4 +64,3 @@ class Outline(Enum):
# (sum of all sub-items' goals)
textFormat = 15
revisions = 16

View file

@ -121,9 +121,9 @@ def outlineItemColors(item):
# POV
colors["POV"] = QColor(Qt.transparent)
POV = item.data(Outline.POV.value)
for i in range(mw.mdlPersos.rowCount()):
if mw.mdlPersos.ID(i) == POV:
colors["POV"] = iconColor(mw.mdlPersos.icon(i))
for i in range(mw.mdlCharacter.rowCount()):
if mw.mdlCharacter.ID(i) == POV:
colors["POV"] = iconColor(mw.mdlCharacter.icon(i))
# Label
lbl = item.data(Outline.label.value)
@ -179,6 +179,10 @@ def allPaths(suffix=None):
return paths
def lightBlue():
"""
A light blue used in several places in manuskript.
@return: QColor
"""
return QColor(Qt.blue).lighter(190)
def totalObjects():

View file

@ -1,149 +1,58 @@
#!/usr/bin/env python
#--!-- coding: utf8 --!--
# --!-- coding: utf8 --!--
# The loadSave file calls the propper functions to load and save file
# trying to detect the proper file format if it comes from an older version
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
import manuskript.load_save.version_0 as v0
import manuskript.load_save.version_1 as v1
from manuskript.functions import iconColor, iconFromColorString
try:
import zlib # Used with zipfile for compression
compression = zipfile.ZIP_DEFLATED
except:
compression = zipfile.ZIP_STORED
def saveProject(version=None):
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."""
print(zipname)
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()
# 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)
#print(qApp.tr("Saving to {}.").format(xml))
if xml:
ET.ElementTree(root).write(xml, encoding="UTF-8", xml_declaration=True, pretty_print=True)
# While debugging, we don't save the project
# return
if version == 0:
v0.saveProject()
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))
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="")
if not fromString:
try:
tree = ET.parse(xml)
except:
print("Failed.")
return
v1.saveProject()
# FIXME: add settings to chose between saving as zip or not.
def loadProject(project):
# Detect version
isZip = False
version = 0
# Is it a zip?
try:
zf = zipfile.ZipFile(project)
isZip = True
except zipfile.BadZipFile:
isZip = False
# Does it have a VERSION in zip root?
if isZip and "VERSION" in zf.namelist():
version = int(zf.read("VERSION"))
# Zip but no VERSION: oldest file format
elif isZip:
version = 0
# Not a zip
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"])
#print(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))
with open(project, "r") as f:
version = int(f.read())
print("Loading:", project)
print("Detected file format version: {}. Zip: {}.".format(version, isZip))
if version == 0:
v0.loadProject(project)
else:
v1.loadProject(project, zip=isZip)

View file

View file

@ -0,0 +1,289 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
# Version 0 of file saving format.
# Was used at the begining and up util version XXX when
# it was superseded by Version 1, which is more open and flexible
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
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"))
print("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)
# print(qApp.tr("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():
files[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 containg the data."""
# print(qApp.tr("Loading {}... ").format(xml), end="")
if not fromString:
try:
tree = ET.parse(xml)
except:
print("Failed.")
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"])
# print(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)

File diff suppressed because it is too large Load diff

View file

@ -9,13 +9,11 @@ from PyQt5.QtWidgets import QMainWindow, QHeaderView, qApp, QMenu, QActionGroup,
QLabel
from manuskript import settings
from manuskript.enums import Perso, Subplot, Plot, World
from manuskript.enums import Character, PlotStep, Plot, World
from manuskript.functions import AUC, wordCount, appPath
from manuskript.loadSave import loadStandardItemModelXML, loadFilesFromZip
from manuskript.loadSave import saveFilesToZip
from manuskript.loadSave import saveStandardItemModelXML
from manuskript.loadSave import saveProject, loadProject
from manuskript.models.characterModel import characterModel
from manuskript.models.outlineModel import outlineModel
from manuskript.models.persosModel import persosModel
from manuskript.models.plotModel import plotModel
from manuskript.models.worldModel import worldModel
from manuskript.settingsWindow import settingsWindow
@ -24,7 +22,7 @@ from manuskript.ui.compileDialog import compileDialog
from manuskript.ui.helpLabel import helpLabel
from manuskript.ui.mainWindow import Ui_MainWindow
from manuskript.ui.tools.frequencyAnalyzer import frequencyAnalyzer
from manuskript.ui.views.outlineDelegates import outlinePersoDelegate
from manuskript.ui.views.outlineDelegates import outlineCharacterDelegate
from manuskript.ui.views.plotDelegate import plotDelegate
# Spellcheck support
@ -144,15 +142,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# PERSOS
###############################################################################
def changeCurrentPerso(self, trash=None):
def changeCurrentCharacter(self, trash=None):
"""
index = self.lstPersos.currentPersoIndex()
if not index.isValid():
@return:
"""
c = self.lstCharacters.currentCharacter()
if not c:
self.tabPlot.setEnabled(False)
return
self.tabPersos.setEnabled(True)
index = c.index()
for w in [
self.txtPersoName,
@ -169,27 +170,24 @@ class MainWindow(QMainWindow, Ui_MainWindow):
w.setCurrentModelIndex(index)
# Button color
self.mdlPersos.updatePersoColor(index)
self.updateCharacterColor(c.ID())
# Perso Infos
# Character Infos
self.tblPersoInfos.setRootIndex(index)
if self.mdlPersos.rowCount(index):
if self.mdlCharacter.rowCount(index):
self.updatePersoInfoView()
def updatePersoInfoView(self):
# Hide columns
for i in range(self.mdlPersos.columnCount()):
self.tblPersoInfos.hideColumn(i)
self.tblPersoInfos.showColumn(Perso.infoName.value)
self.tblPersoInfos.showColumn(Perso.infoData.value)
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(
Perso.infoName.value, QHeaderView.ResizeToContents)
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(
Perso.infoData.value, QHeaderView.Stretch)
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
self.tblPersoInfos.verticalHeader().hide()
def updateCharacterColor(self, ID):
c = self.mdlCharacter.getCharacterByID(ID)
color = c.color().name()
self.btnPersoColor.setStyleSheet("background:{};".format(color))
###############################################################################
# PLOTS
###############################################################################
@ -207,8 +205,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.txtPlotResult.setCurrentModelIndex(index)
self.sldPlotImportance.setCurrentModelIndex(index)
self.lstPlotPerso.setRootIndex(index.sibling(index.row(),
Plot.persos.value))
subplotindex = index.sibling(index.row(), Plot.subplots.value)
Plot.characters.value))
subplotindex = index.sibling(index.row(), Plot.steps.value)
self.lstSubPlots.setRootIndex(subplotindex)
if self.mdlPlots.rowCount(subplotindex):
self.updateSubPlotView()
@ -224,18 +222,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Hide columns
for i in range(self.mdlPlots.columnCount()):
self.lstSubPlots.hideColumn(i)
self.lstSubPlots.showColumn(Subplot.name.value)
self.lstSubPlots.showColumn(Subplot.meta.value)
self.lstSubPlots.showColumn(PlotStep.name.value)
self.lstSubPlots.showColumn(PlotStep.meta.value)
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
Subplot.name.value, QHeaderView.Stretch)
PlotStep.name.value, QHeaderView.Stretch)
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
Subplot.meta.value, QHeaderView.ResizeToContents)
PlotStep.meta.value, QHeaderView.ResizeToContents)
self.lstSubPlots.verticalHeader().hide()
def changeCurrentSubPlot(self, index):
# Got segfaults when using textEditView model system, so ad hoc stuff.
index = index.sibling(index.row(), Subplot.summary.value)
index = index.sibling(index.row(), PlotStep.summary.value)
item = self.mdlPlots.itemFromIndex(index)
if not item:
self.txtSubPlotSummary.setEnabled(False)
@ -253,7 +251,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
index = self.lstSubPlots.currentIndex()
if not index.isValid():
return
index = index.sibling(index.row(), Subplot.summary.value)
index = index.sibling(index.row(), PlotStep.summary.value)
item = self.mdlPlots.itemFromIndex(index)
self._updatingSubPlot = True
@ -310,7 +308,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Load settings
for i in settings.openIndexes:
idx = self.mdlOutline.indexFromPath(i)
idx = self.mdlOutline.getIndexByID(i)
self.mainEditor.setCurrentModelIndex(idx, newTab=True)
self.generateViewMenu()
self.mainEditor.sldCorkSizeFactor.setValue(settings.corkSizeFactor)
@ -340,7 +338,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.saveTimerNoChanges.setSingleShot(True)
self.mdlFlatData.dataChanged.connect(self.startTimerNoChanges)
self.mdlOutline.dataChanged.connect(self.startTimerNoChanges)
self.mdlPersos.dataChanged.connect(self.startTimerNoChanges)
self.mdlCharacter.dataChanged.connect(self.startTimerNoChanges)
self.mdlPlots.dataChanged.connect(self.startTimerNoChanges)
self.mdlWorld.dataChanged.connect(self.startTimerNoChanges)
# self.mdlPersosInfos.dataChanged.connect(self.startTimerNoChanges)
@ -434,10 +432,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
settings.lastTab = self.tabMain.currentIndex()
if self.currentProject:
# Remembering the current items
# Remembering the current items (stores outlineItem's ID)
sel = []
for i in range(self.mainEditor.tab.count()):
sel.append(self.mdlOutline.pathToIndex(self.mainEditor.tab.widget(i).currentIndex))
sel.append(self.mdlOutline.ID(self.mainEditor.tab.widget(i).currentIndex))
settings.openIndexes = sel
# Save data from models
@ -462,27 +460,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.currentProject = projectName
QSettings().setValue("lastProject", projectName)
# Saving
files = []
files.append((saveStandardItemModelXML(self.mdlFlatData),
"flatModel.xml"))
files.append((saveStandardItemModelXML(self.mdlPersos),
"perso.xml"))
files.append((saveStandardItemModelXML(self.mdlWorld),
"world.xml"))
files.append((saveStandardItemModelXML(self.mdlLabels),
"labels.xml"))
files.append((saveStandardItemModelXML(self.mdlStatus),
"status.xml"))
files.append((saveStandardItemModelXML(self.mdlPlots),
"plots.xml"))
files.append((self.mdlOutline.saveToXML(),
"outline.xml"))
files.append((settings.save(),
"settings.pickle"))
saveFilesToZip(files, self.currentProject)
saveProject() # version=0
self.saveTimerNoChanges.stop()
# Giving some feedback
print(self.tr("Project {} saved.").format(self.currentProject))
@ -491,7 +470,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def loadEmptyDatas(self):
self.mdlFlatData = QStandardItemModel(self)
self.mdlPersos = persosModel(self)
self.mdlCharacter = characterModel(self)
# self.mdlPersosProxy = persosProxyModel(self)
# self.mdlPersosInfos = QStandardItemModel(self)
self.mdlLabels = QStandardItemModel(self)
@ -501,56 +480,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.mdlWorld = worldModel(self)
def loadDatas(self, project):
# Loading
files = loadFilesFromZip(project)
errors = []
if "flatModel.xml" in files:
loadStandardItemModelXML(self.mdlFlatData,
files["flatModel.xml"], fromString=True)
else:
errors.append("flatModel.xml")
if "perso.xml" in files:
loadStandardItemModelXML(self.mdlPersos,
files["perso.xml"], fromString=True)
else:
errors.append("perso.xml")
if "world.xml" in files:
loadStandardItemModelXML(self.mdlWorld,
files["world.xml"], fromString=True)
else:
errors.append("world.xml")
if "labels.xml" in files:
loadStandardItemModelXML(self.mdlLabels,
files["labels.xml"], fromString=True)
else:
errors.append("perso.xml")
if "status.xml" in files:
loadStandardItemModelXML(self.mdlStatus,
files["status.xml"], fromString=True)
else:
errors.append("perso.xml")
if "plots.xml" in files:
loadStandardItemModelXML(self.mdlPlots,
files["plots.xml"], fromString=True)
else:
errors.append("perso.xml")
if "outline.xml" in files:
self.mdlOutline.loadFromXML(files["outline.xml"], fromString=True)
else:
errors.append("perso.xml")
if "settings.pickle" in files:
settings.load(files["settings.pickle"], fromString=True)
else:
errors.append("perso.xml")
errors = loadProject(project)
# Giving some feedback
if not errors:
@ -570,7 +501,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def makeUIConnections(self):
"Connections that have to be made once only, event when new project is loaded."
self.lstPersos.currentItemChanged.connect(self.changeCurrentPerso, AUC)
self.lstCharacters.currentItemChanged.connect(self.changeCurrentCharacter, AUC)
self.txtPlotFilter.textChanged.connect(self.lstPlots.setFilter, AUC)
self.lstPlots.currentItemChanged.connect(self.changeCurrentPlot, AUC)
@ -622,29 +553,32 @@ class MainWindow(QMainWindow, Ui_MainWindow):
widget.setCurrentModelIndex(self.mdlFlatData.index(0, col))
# Persos
self.lstPersos.setPersosModel(self.mdlPersos)
self.tblPersoInfos.setModel(self.mdlPersos)
self.lstCharacters.setCharactersModel(self.mdlCharacter)
self.tblPersoInfos.setModel(self.mdlCharacter)
self.btnAddPerso.clicked.connect(self.mdlPersos.addPerso, AUC)
self.btnRmPerso.clicked.connect(self.mdlPersos.removePerso, AUC)
self.btnPersoColor.clicked.connect(self.mdlPersos.chosePersoColor, AUC)
self.btnPersoAddInfo.clicked.connect(self.mdlPersos.addPersoInfo, AUC)
self.btnPersoRmInfo.clicked.connect(self.mdlPersos.removePersoInfo, AUC)
self.btnAddPerso.clicked.connect(self.mdlCharacter.addCharacter, AUC)
try:
self.btnRmPerso.clicked.connect(self.lstCharacters.removeCharacter, AUC)
self.btnPersoColor.clicked.connect(self.lstCharacters.choseCharacterColor, AUC)
self.btnPersoAddInfo.clicked.connect(self.lstCharacters.addCharacterInfo, AUC)
self.btnPersoRmInfo.clicked.connect(self.lstCharacters.removeCharacterInfo, AUC)
except TypeError:
# Connection has already been made
pass
for w, c in [
(self.txtPersoName, Perso.name.value),
(self.sldPersoImportance, Perso.importance.value),
(self.txtPersoMotivation, Perso.motivation.value),
(self.txtPersoGoal, Perso.goal.value),
(self.txtPersoConflict, Perso.conflict.value),
(self.txtPersoEpiphany, Perso.epiphany.value),
(self.txtPersoSummarySentence, Perso.summarySentence.value),
(self.txtPersoSummaryPara, Perso.summaryPara.value),
(self.txtPersoSummaryFull, Perso.summaryFull.value),
(self.txtPersoNotes, Perso.notes.value)
(self.txtPersoName, Character.name.value),
(self.sldPersoImportance, Character.importance.value),
(self.txtPersoMotivation, Character.motivation.value),
(self.txtPersoGoal, Character.goal.value),
(self.txtPersoConflict, Character.conflict.value),
(self.txtPersoEpiphany, Character.epiphany.value),
(self.txtPersoSummarySentence, Character.summarySentence.value),
(self.txtPersoSummaryPara, Character.summaryPara.value),
(self.txtPersoSummaryFull, Character.summaryFull.value),
(self.txtPersoNotes, Character.notes.value)
]:
w.setModel(self.mdlPersos)
w.setModel(self.mdlCharacter)
w.setColumn(c)
self.tabPersos.setEnabled(False)
@ -672,13 +606,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.tabPlot.setEnabled(False)
self.mdlPlots.updatePlotPersoButton()
self.mdlPersos.dataChanged.connect(self.mdlPlots.updatePlotPersoButton)
self.mdlCharacter.dataChanged.connect(self.mdlPlots.updatePlotPersoButton)
self.lstOutlinePlots.setPlotModel(self.mdlPlots)
self.lstOutlinePlots.setShowSubPlot(True)
self.plotPersoDelegate = outlinePersoDelegate(self.mdlPersos, self)
self.lstPlotPerso.setItemDelegate(self.plotPersoDelegate)
self.plotCharacterDelegate = outlineCharacterDelegate(self.mdlCharacter, self)
self.lstPlotPerso.setItemDelegate(self.plotCharacterDelegate)
self.plotDelegate = plotDelegate(self)
self.lstSubPlots.setItemDelegateForColumn(Subplot.meta.value, self.plotDelegate)
self.lstSubPlots.setItemDelegateForColumn(PlotStep.meta.value, self.plotDelegate)
# World
self.treeWorld.setModel(self.mdlWorld)
@ -702,18 +636,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Outline
self.treeRedacOutline.setModel(self.mdlOutline)
self.treeOutlineOutline.setModelPersos(self.mdlPersos)
self.treeOutlineOutline.setModelCharacters(self.mdlCharacter)
self.treeOutlineOutline.setModelLabels(self.mdlLabels)
self.treeOutlineOutline.setModelStatus(self.mdlStatus)
self.redacMetadata.setModels(self.mdlOutline, self.mdlPersos,
self.redacMetadata.setModels(self.mdlOutline, self.mdlCharacter,
self.mdlLabels, self.mdlStatus)
self.outlineItemEditor.setModels(self.mdlOutline, self.mdlPersos,
self.outlineItemEditor.setModels(self.mdlOutline, self.mdlCharacter,
self.mdlLabels, self.mdlStatus)
self.treeOutlineOutline.setModel(self.mdlOutline)
# self.redacEditor.setModel(self.mdlOutline)
self.storylineView.setModels(self.mdlOutline, self.mdlPersos, self.mdlPlots)
self.storylineView.setModels(self.mdlOutline, self.mdlCharacter, self.mdlPlots)
self.treeOutlineOutline.selectionModel().selectionChanged.connect(lambda:
self.outlineItemEditor.selectionChanged(
@ -735,12 +669,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Debug
self.mdlFlatData.setVerticalHeaderLabels(["Infos générales", "Summary"])
self.tblDebugFlatData.setModel(self.mdlFlatData)
self.tblDebugPersos.setModel(self.mdlPersos)
self.tblDebugPersosInfos.setModel(self.mdlPersos)
self.tblDebugPersos.setModel(self.mdlCharacter)
self.tblDebugPersosInfos.setModel(self.mdlCharacter)
self.tblDebugPersos.selectionModel().currentChanged.connect(
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlPersos.index(
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlCharacter.index(
self.tblDebugPersos.selectionModel().currentIndex().row(),
Perso.name.value)), AUC)
Character.name.value)), AUC)
self.tblDebugPlots.setModel(self.mdlPlots)
self.tblDebugPlotsPersos.setModel(self.mdlPlots)
@ -748,11 +682,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.tblDebugPlots.selectionModel().currentChanged.connect(
lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index(
self.tblDebugPlots.selectionModel().currentIndex().row(),
Plot.persos.value)), AUC)
Plot.characters.value)), AUC)
self.tblDebugPlots.selectionModel().currentChanged.connect(
lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index(
self.tblDebugPlots.selectionModel().currentIndex().row(),
Plot.subplots.value)), AUC)
Plot.steps.value)), AUC)
self.treeDebugWorld.setModel(self.mdlWorld)
self.treeDebugOutline.setModel(self.mdlOutline)
self.lstDebugLabels.setModel(self.mdlLabels)

View file

@ -0,0 +1,293 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
from PyQt5.QtCore import QModelIndex, Qt, QAbstractItemModel, QVariant
from PyQt5.QtGui import QIcon, QPixmap, QColor
from manuskript.functions import randomColor, iconColor, mainWindow
from manuskript.enums import Character as C
class characterModel(QAbstractItemModel):
def __init__(self, parent):
QAbstractItemModel.__init__(self, parent)
# CharacterItems are stored in this list
self.characters = []
###############################################################################
# QAbstractItemModel subclassed
###############################################################################
def rowCount(self, parent=QModelIndex()):
if parent.isValid():
c = parent.internalPointer()
return len(c.infos)
else:
return len(self.characters)
def columnCount(self, parent=QModelIndex()):
if parent.isValid():
# Returns characters infos
return 2
else:
return len(C)
def data(self, index, role=Qt.DisplayRole):
c = index.internalPointer()
if type(c) == Character:
if role == Qt.DisplayRole:
if index.column() in c._data:
return c._data[index.column()]
else:
return ""
elif type(c) == CharacterInfo:
if role == Qt.DisplayRole or role == Qt.EditRole:
if index.column() == 0:
return c.description
elif index.column() == 1:
return c.value
def setData(self, index, value, role=Qt.EditRole):
c = index.internalPointer()
if type(c) == Character:
if role == Qt.EditRole:
# We update only if data is different
if index.column() not in c._data or c._data[index.column()] != value:
c._data[index.column()] = value
self.dataChanged.emit(index, index)
return True
elif type(c) == CharacterInfo:
if role == Qt.EditRole:
if index.column() == 0:
c.description = value
elif index.column() == 1:
c.value = value
self.dataChanged.emit(index, index)
return True
return False
def index(self, row, column, parent=QModelIndex()):
if not parent.isValid():
return self.createIndex(row, column, self.characters[row])
else:
c = parent.internalPointer()
if row < len(c.infos):
return self.createIndex(row, column, c.infos[row])
else:
return QModelIndex()
def indexFromItem(self, item, column=0):
if not item:
return QModelIndex()
row = self.characters.index(item)
col = column
return self.createIndex(row, col, item)
def parent(self, index):
if not index.isValid():
return QModelIndex()
child = index.internalPointer()
if type(child) == Character:
return QModelIndex()
elif type(child) == CharacterInfo:
return child.character.index()
def flags(self, index):
if index.parent().isValid():
return QAbstractItemModel.flags(self, index) | Qt.ItemIsEditable
else:
return QAbstractItemModel.flags(self, index)
###############################################################################
# CHARACTER QUERRIES
###############################################################################
def character(self, row):
return self.characters[row]
def name(self, row):
return self.character(row).name()
def icon(self, row):
return self.character(row).icon
def ID(self, row):
return self.character(row).ID()
def importance(self, row):
return self.character(row).importance()
###############################################################################
# MODEL QUERRIES
###############################################################################
def getCharactersByImportance(self):
"""
Lists characters by importance.
@return: array of array of ´character´, by importance.
"""
r = [[], [], []]
for c in self.characters:
r[2-int(c.importance())].append(c)
return r
def getCharacterByID(self, ID):
if ID is not None:
ID = str(ID)
for c in self.characters:
if c.ID() == ID:
return c
return None
###############################################################################
# ADDING / REMOVING
###############################################################################
def addCharacter(self):
"""
Creates a new character
@return: the character
"""
c = Character(model=self, name=self.tr("New character"))
self.beginInsertRows(QModelIndex(), len(self.characters), len(self.characters))
self.characters.append(c)
self.endInsertRows()
return c
def removeCharacter(self, ID):
"""
Removes character whose ID is ID...
@param ID: the ID of the character to remove
@return: nothing
"""
c = self.getCharacterByID(ID)
self.beginRemoveRows(QModelIndex(), self.characters.index(c), self.characters.index(c))
self.characters.remove(c)
self.endRemoveRows()
###############################################################################
# CHARACTER INFOS
###############################################################################
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.DisplayRole and orientation == Qt.Horizontal:
if section == 0:
return self.tr("Name")
elif section == 1:
return self.tr("Value")
else:
return C(section).name
def addCharacterInfo(self, ID):
c = self.getCharacterByID(ID)
self.beginInsertRows(c.index(), len(c.infos), len(c.infos))
c.infos.append(CharacterInfo(c, description="Description", value="Value"))
self.endInsertRows()
mainWindow().updatePersoInfoView()
def removeCharacterInfo(self, ID):
c = self.getCharacterByID(ID)
rm = []
for idx in mainWindow().tblPersoInfos.selectedIndexes():
if not idx.row() in rm:
rm.append(idx.row())
rm.sort()
rm.reverse()
for r in rm:
self.beginRemoveRows(c.index(), r, r)
c.infos.pop(r)
self.endRemoveRows()
###############################################################################
# CHARACTER
###############################################################################
class Character():
def __init__(self, model, name="No name"):
self._model = model
self.lastPath = ""
self._data = {}
self._data[C.name.value] = name
self.assignUniqueID()
self.assignRandomColor()
self._data[C.importance.value] = "0"
self.infos = []
def name(self):
return self._data[C.name.value]
def importance(self):
return self._data[C.importance.value]
def ID(self):
return self._data[C.ID.value]
def index(self, column=0):
return self._model.indexFromItem(self, column)
def assignRandomColor(self):
"""
Assigns a random color the the character.
"""
color = randomColor(QColor(Qt.white))
self.setColor(color)
def setColor(self, color):
"""
Sets the character's color
@param color: QColor.
"""
px = QPixmap(32, 32)
px.fill(color)
self.icon = QIcon(px)
try:
self._model.dataChanged.emit(self.index(), self.index())
except:
# If it is the initialisation, won't be able to emit
pass
def color(self):
"""
Returns character's color in QColor
@return: QColor
"""
return iconColor(self.icon)
def assignUniqueID(self, parent=QModelIndex()):
"""Assigns an unused character ID."""
vals = []
for c in self._model.characters:
vals.append(int(c.ID()))
k = 0
while k in vals:
k += 1
self._data[C.ID.value] = str(k)
def listInfos(self):
r = []
for i in self.infos:
r.append((i.description, i.value))
return r
class CharacterInfo():
def __init__(self, character, description="", value=""):
self.description = description
self.value = value
self.character = character

View file

@ -18,7 +18,7 @@ from manuskript.enums import Outline
from manuskript.functions import mainWindow, toInt, wordCount
locale.setlocale(locale.LC_ALL, '')
import time
import time, os
class outlineModel(QAbstractItemModel):
@ -27,6 +27,9 @@ class outlineModel(QAbstractItemModel):
self.rootItem = outlineItem(self, title="root", ID="0")
# Stores removed item, in order to remove them on disk when saving, depending on the file format.
self.removed = []
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
@ -74,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
@ -86,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:
@ -363,7 +369,8 @@ class outlineModel(QAbstractItemModel):
self.beginRemoveRows(parent, row, row + count - 1)
for i in range(count):
parentItem.removeChild(row)
item = parentItem.removeChild(row)
self.removed.append(item)
self.endRemoveRows()
return True
@ -400,19 +407,6 @@ class outlineModel(QAbstractItemModel):
self.rootItem = outlineItem(model=self, xml=ET.tostring(root), ID="0")
self.rootItem.checkIDs()
def pathToIndex(self, index, path=""):
# FIXME: Use item's ID instead of rows
if not index.isValid():
return ""
if index.parent().isValid():
path = self.pathToIndex(index.parent())
if path:
path = "{},{}".format(path, str(index.row()))
else:
path = str(index.row())
return path
def indexFromPath(self, path):
path = path.split(",")
item = self.rootItem
@ -431,6 +425,8 @@ class outlineItem():
self._model = model
self.defaultTextType = None
self.IDs = [] # used by root item to store unique IDs
self._lastPath = "" # used by loadSave version_1 to remember which files the items comes from,
# in case it is renamed / removed
if title:
self._data[Outline.title] = title
@ -603,7 +599,7 @@ class outlineItem():
self.parent().updateWordCount(emit)
def row(self):
if self.parent:
if self.parent():
return self.parent().childItems.index(self)
def appendChild(self, child):
@ -645,9 +641,15 @@ class outlineItem():
c.emitDataChanged(cols, recursive=True)
def removeChild(self, row):
self.childItems.pop(row)
"""
Removes child at position `row` and returns it.
@param row: index (int) of the child to remove.
@return: the removed outlineItem
"""
r = self.childItems.pop(row)
# Might be causing segfault when updateWordCount emits dataChanged
self.updateWordCount(emit=False)
return r
def parent(self):
return self._parent
@ -758,6 +760,9 @@ class outlineItem():
revItem.set("text", r[1])
item.append(revItem)
# Saving lastPath
item.set("lastPath", self._lastPath)
for i in self.childItems:
item.append(ET.XML(i.toXML()))
@ -773,6 +778,9 @@ class outlineItem():
# else:
self.setData(Outline.__members__[k].value, str(root.attrib[k]))
if "lastPath" in root.attrib:
self._lastPath = root.attrib["lastPath"]
for child in root:
if child.tag == "outlineItem":
item = outlineItem(self._model, xml=ET.tostring(child), parent=self)
@ -854,8 +862,13 @@ class outlineItem():
text = text.lower() if not caseSensitive else text
for c in columns:
if c == Outline.POV.value:
searchIn = mainWindow.mdlPersos.getPersoNameByID(self.POV())
if c == Outline.POV.value and self.POV():
c = mainWindow.mdlCharacter.getCharacterByID(self.POV())
if c:
searchIn = c.name()
else:
searchIn = ""
print("Character POV not found:", self.POV())
elif c == Outline.status.value:
searchIn = mainWindow.mdlStatus.item(toInt(self.status()), 0).text()

View file

@ -1,183 +0,0 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
from PyQt5.QtCore import QModelIndex, Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QColor, QPixmap, QIcon
from PyQt5.QtWidgets import QColorDialog
from manuskript.enums import Perso
from manuskript.enums import Plot
from manuskript.functions import iconColor
from manuskript.functions import mainWindow
from manuskript.functions import randomColor
from manuskript.functions import toInt
class persosModel(QStandardItemModel):
def __init__(self, parent):
QStandardItemModel.__init__(self, 0, 3, parent)
self.setHorizontalHeaderLabels([i.name for i in Perso])
self.mw = mainWindow()
# self._proxy = plotsProxyModel()
# self._proxy.setSourceModel(self)
###############################################################################
# PERSOS QUERRIES
###############################################################################
def name(self, row):
return self.item(row, Perso.name.value).text()
def icon(self, row):
return self.item(row, Perso.name.value).icon()
def ID(self, row):
return self.item(row, Perso.ID.value).text()
def importance(self, row):
return self.item(row, Perso.importance.value).text()
###############################################################################
# MODEL QUERRIES
###############################################################################
def getPersosByImportance(self):
persos = [[], [], []]
for i in range(self.rowCount()):
importance = self.item(i, Perso.importance.value).text()
ID = self.item(i, Perso.ID.value).text()
persos[2-toInt(importance)].append(ID)
return persos
def getPersoNameByID(self, ID):
index = self.getIndexFromID(ID)
if index.isValid():
return self.name(index.row())
return ""
def getIndexFromID(self, ID):
for i in range(self.rowCount()):
_ID = self.item(i, Perso.ID.value).text()
if _ID == ID or toInt(_ID) == ID:
return self.index(i, 0)
return QModelIndex()
def getPersoColorByID(self, ID):
idx = self.getIndexFromID(ID)
return self.getPersoColorName(idx)
def getPersoColorName(self, index):
icon = self.item(index.row()).icon()
return iconColor(icon).name() if icon else ""
def currentListIndex(self):
i = self.mw.lstPersos.currentIndex()
if i .isValid():
return i
else:
return None
def currentPersoIndex(self):
return self.mw.lstPersos.currentPersoIndex()
###############################################################################
# ADDING / REMOVING
###############################################################################
def addPerso(self):
"""Creates a perso by adding a row in mdlPersos
and a column in mdlPersosInfos with same ID"""
p = QStandardItem(self.tr("New character"))
self.setPersoColor(p, randomColor(QColor(Qt.white)))
pid = self.getUniqueID()
self.appendRow([p, QStandardItem(pid), QStandardItem("0")])
def getUniqueID(self, parent=QModelIndex()):
"""Returns an unused perso ID (row 1)."""
vals = []
for i in range(self.rowCount(parent)):
index = self.index(i, Perso.ID.value, parent)
if index.isValid() and index.data():
vals.append(int(index.data()))
k = 0
while k in vals:
k += 1
return str(k)
def removePerso(self):
index = self.currentPersoIndex()
self.takeRow(index.row())
def setPersoColor(self, item, color):
px = QPixmap(32, 32)
px.fill(color)
item.setIcon(QIcon(px))
def chosePersoColor(self):
idx = self.currentPersoIndex()
item = self.item(idx.row(), Perso.name.value)
if item:
color = iconColor(item.icon())
else:
color = Qt.white
self.colorDialog = QColorDialog(color, self.mw)
color = self.colorDialog.getColor(color)
if color.isValid():
self.setPersoColor(item, color)
self.updatePersoColor(idx)
###############################################################################
# UI
###############################################################################
def updatePersoColor(self, idx):
# idx = self.currentPersoIndex()
color = self.getPersoColorName(idx)
self.mw.btnPersoColor.setStyleSheet("background:{};".format(color))
###############################################################################
# PERSO INFOS
###############################################################################
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.DisplayRole and orientation == Qt.Horizontal:
if section == Perso.infoName.value:
return self.tr("Name")
elif section == Perso.infoData.value:
return self.tr("Value")
else:
return Perso(section).name
else:
return QStandardItemModel.headerData(self, section, orientation, role)
def addPersoInfo(self):
perso = self.itemFromIndex(self.currentPersoIndex())
row = perso.rowCount()
perso.setChild(row, Perso.infoName.value, QStandardItem(""))
perso.setChild(row, Perso.infoData.value, QStandardItem(""))
self.mw.updatePersoInfoView()
def removePersoInfo(self):
perso = self.itemFromIndex(self.currentPersoIndex())
rm = []
for idx in self.mw.tblPersoInfos.selectedIndexes():
if not idx.row() in rm:
rm.append(idx.row())
rm.sort()
rm.reverse()
for r in rm:
perso.takeRow(r)
def listPersoInfos(self, index):
infos = []
for i in range(self.rowCount(index)):
name = self.data(index.child(i, Perso.infoName.value))
val = self.data(index.child(i, Perso.infoData.value))
infos.append((name, val))
return infos

View file

@ -9,7 +9,7 @@ from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QAction, QMenu
from manuskript.enums import Plot
from manuskript.enums import Subplot
from manuskript.enums import PlotStep
from manuskript.functions import toInt, mainWindow
@ -37,7 +37,7 @@ class plotModel(QStandardItemModel):
index = self.getIndexFromID(ID)
if not index.isValid():
return
index = index.sibling(index.row(), Plot.subplots.value)
index = index.sibling(index.row(), Plot.steps.value)
item = self.itemFromIndex(index)
lst = []
for i in range(item.rowCount()):
@ -86,8 +86,8 @@ class plotModel(QStandardItemModel):
p = QStandardItem(self.tr("New plot"))
_id = QStandardItem(self.getUniqueID())
importance = QStandardItem(str(0))
self.appendRow([p, _id, importance, QStandardItem("Persos"),
QStandardItem(), QStandardItem(), QStandardItem("Subplots")])
self.appendRow([p, _id, importance, QStandardItem("Characters"),
QStandardItem(), QStandardItem(), QStandardItem("Resolution steps")])
def getUniqueID(self, parent=QModelIndex()):
"""Returns an unused ID"""
@ -114,9 +114,9 @@ class plotModel(QStandardItemModel):
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
if section == Subplot.name.value:
if section == PlotStep.name.value:
return self.tr("Name")
elif section == Subplot.meta.value:
elif section == PlotStep.meta.value:
return self.tr("Meta")
else:
return ""
@ -127,8 +127,8 @@ class plotModel(QStandardItemModel):
def data(self, index, role=Qt.DisplayRole):
if index.parent().isValid() and \
index.parent().column() == Plot.subplots.value and \
index.column() == Subplot.meta.value:
index.parent().column() == Plot.steps.value and \
index.column() == PlotStep.meta.value:
if role == Qt.TextAlignmentRole:
return Qt.AlignRight | Qt.AlignVCenter
elif role == Qt.ForegroundRole:
@ -144,13 +144,13 @@ class plotModel(QStandardItemModel):
if not index.isValid():
return
parent = index.sibling(index.row(), Plot.subplots.value)
parentItem = self.item(index.row(), Plot.subplots.value)
parent = index.sibling(index.row(), Plot.steps.value)
parentItem = self.item(index.row(), Plot.steps.value)
if not parentItem:
return
p = QStandardItem(self.tr("New subplot"))
p = QStandardItem(self.tr("New step"))
_id = QStandardItem(self.getUniqueID(parent))
summary = QStandardItem()
@ -182,10 +182,10 @@ class plotModel(QStandardItemModel):
def addPlotPerso(self, v):
index = self.mw.lstPlots.currentPlotIndex()
if index.isValid():
if not self.item(index.row(), Plot.persos.value):
self.setItem(index.row(), Plot.persos.value, QStandardItem())
if not self.item(index.row(), Plot.characters.value):
self.setItem(index.row(), Plot.characters.value, QStandardItem())
item = self.item(index.row(), Plot.persos.value)
item = self.item(index.row(), Plot.characters.value)
# We check that the PersoID is not in the list yet
for i in range(item.rowCount()):
@ -212,13 +212,13 @@ class plotModel(QStandardItemModel):
menu.addMenu(m)
mpr = QSignalMapper(menu)
for i in range(self.mw.mdlPersos.rowCount()):
a = QAction(self.mw.mdlPersos.name(i), menu)
a.setIcon(self.mw.mdlPersos.icon(i))
for i in range(self.mw.mdlCharacter.rowCount()):
a = QAction(self.mw.mdlCharacter.name(i), menu)
a.setIcon(self.mw.mdlCharacter.icon(i))
a.triggered.connect(mpr.map)
mpr.setMapping(a, int(self.mw.mdlPersos.ID(i)))
mpr.setMapping(a, int(self.mw.mdlCharacter.ID(i)))
imp = toInt(self.mw.mdlPersos.importance(i))
imp = toInt(self.mw.mdlCharacter.importance(i))
menus[2 - imp].addAction(a)

View file

@ -11,9 +11,9 @@ import re
from PyQt5.QtWidgets import qApp
from manuskript.enums import Outline
from manuskript.enums import Perso
from manuskript.enums import Character
from manuskript.enums import Plot
from manuskript.enums import Subplot
from manuskript.enums import PlotStep
from manuskript.functions import mainWindow
RegEx = r"{(\w):(\d+):?.*?}"
@ -22,7 +22,7 @@ RegExNonCapturing = r"{\w:\d+:?.*?}"
# The basic format of the references
EmptyRef = "{{{}:{}:{}}}"
EmptyRefSearchable = "{{{}:{}:"
PersoLetter = "C"
CharacterLetter = "C"
TextLetter = "T"
PlotLetter = "P"
WorldLetter = "W"
@ -37,13 +37,13 @@ def plotReference(ID, searchable=False):
return EmptyRefSearchable.format(PlotLetter, ID, "")
def persoReference(ID, searchable=False):
def characterReference(ID, searchable=False):
"""Takes the ID of a character and returns a reference for that character.
@searchable: returns a stripped version that allows simple text search."""
if not searchable:
return EmptyRef.format(PersoLetter, ID, "")
return EmptyRef.format(CharacterLetter, ID, "")
else:
return EmptyRefSearchable.format(PersoLetter, ID, "")
return EmptyRefSearchable.format(CharacterLetter, ID, "")
def textReference(ID, searchable=False):
@ -103,8 +103,8 @@ def infos(ref):
POV = ""
if item.POV():
POV = "<a href='{ref}'>{text}</a>".format(
ref=persoReference(item.POV()),
text=mainWindow().mdlPersos.getPersoNameByID(item.POV()))
ref=characterReference(item.POV()),
text=mainWindow().mdlCharacter.getCharacterByID(item.POV()).name())
# The status of the scene
status = item.status()
@ -174,10 +174,12 @@ def infos(ref):
return text
# A character
elif _type == PersoLetter:
m = mainWindow().mdlPersos
index = m.getIndexFromID(_ref)
name = m.name(index.row())
elif _type == CharacterLetter:
m = mainWindow().mdlCharacter
c = m.getCharacterByID(int(_ref))
index = c.index()
name = c.name()
# Titles
basicTitle = qApp.translate("references", "Basic infos")
@ -191,14 +193,16 @@ def infos(ref):
# basic infos
basic = []
for i in [
(Perso.motivation, qApp.translate("references", "Motivation"), False),
(Perso.goal, qApp.translate("references", "Goal"), False),
(Perso.conflict, qApp.translate("references", "Conflict"), False),
(Perso.epiphany, qApp.translate("references", "Epiphany"), False),
(Perso.summarySentence, qApp.translate("references", "Short summary"), True),
(Perso.summaryPara, qApp.translate("references", "Longer summary"), True),
(Character.motivation, qApp.translate("references", "Motivation"), False),
(Character.goal, qApp.translate("references", "Goal"), False),
(Character.conflict, qApp.translate("references", "Conflict"), False),
(Character.epiphany, qApp.translate("references", "Epiphany"), False),
(Character.summarySentence, qApp.translate("references", "Short summary"), True),
(Character.summaryPara, qApp.translate("references", "Longer summary"), True),
]:
val = m.data(index.sibling(index.row(), i[0].value))
if val:
basic.append("<b>{title}:</b>{n}{val}".format(
title=i[1],
@ -208,7 +212,7 @@ def infos(ref):
# detailed infos
detailed = []
for _name, _val in m.listPersoInfos(index):
for _name, _val in c.listInfos():
detailed.append("<b>{}:</b> {}".format(
_name,
_val))
@ -272,24 +276,24 @@ def infos(ref):
Plot.result.value))
# Characters
pM = mainWindow().mdlPersos
item = m.item(index.row(), Plot.persos.value)
pM = mainWindow().mdlCharacter
item = m.item(index.row(), Plot.characters.value)
characters = ""
if item:
for r in range(item.rowCount()):
ID = item.child(r, 0).text()
characters += "<li><a href='{link}'>{text}</a>".format(
link=persoReference(ID),
link=characterReference(ID),
text=pM.getPersoNameByID(ID))
# Resolution steps
steps = ""
item = m.item(index.row(), Plot.subplots.value)
item = m.item(index.row(), Plot.steps.value)
if item:
for r in range(item.rowCount()):
title = item.child(r, Subplot.name.value).text()
summary = item.child(r, Subplot.summary.value).text()
meta = item.child(r, Subplot.meta.value).text()
title = item.child(r, PlotStep.name.value).text()
summary = item.child(r, PlotStep.summary.value).text()
meta = item.child(r, PlotStep.meta.value).text()
if meta:
meta = " <span style='color:gray;'>({})</span>".format(meta)
steps += "<li><b>{title}</b>{summary}{meta}</li>".format(
@ -408,15 +412,16 @@ def shortInfos(ref):
infos["path"] = item.path()
return infos
elif _type == PersoLetter:
elif _type == CharacterLetter:
infos["type"] = PersoLetter
infos["type"] = CharacterLetter
m = mainWindow().mdlPersos
item = m.item(int(_ref), Perso.name.value)
if item:
infos["title"] = item.text()
infos["name"] = item.text()
m = mainWindow().mdlCharacter
c = m.getCharacterByID(_ref)
if c:
infos["title"] = c.name()
infos["name"] = c.name()
return infos
elif _type == PlotLetter:
@ -482,7 +487,7 @@ def tooltip(ref):
tt += "<br><i>{}</i>".format(infos["path"])
return tt
elif infos["type"] == PersoLetter:
elif infos["type"] == CharacterLetter:
return qApp.translate("references", "Character: <b>{}</b>").format(infos["title"])
elif infos["type"] == PlotLetter:
@ -515,9 +520,9 @@ def refToLink(ref):
item = idx.internalPointer()
text = item.title()
elif _type == PersoLetter:
m = mainWindow().mdlPersos
text = m.item(int(_ref), Perso.name.value).text()
elif _type == CharacterLetter:
m = mainWindow().mdlCharacter
text = m.getCharacterByID(int(_ref)).name()
elif _type == PlotLetter:
m = mainWindow().mdlPlots
@ -618,16 +623,16 @@ def open(ref):
_type = match.group(1)
_ref = match.group(2)
if _type == PersoLetter:
if _type == CharacterLetter:
mw = mainWindow()
item = mw.lstPersos.getItemByID(_ref)
item = mw.lstCharacters.getItemByID(int(_ref))
if item:
mw.tabMain.setCurrentIndex(mw.TabPersos)
mw.lstPersos.setCurrentItem(item)
mw.lstCharacters.setCurrentItem(item)
return True
print("Ref not found")
print("Error: Ref {} not found".format(ref))
return False
elif _type == TextLetter:

View file

@ -1,12 +1,16 @@
# -*- coding: utf-8 -*-
import collections
import json
import pickle
from PyQt5.QtWidgets import qApp
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 = {
"Tree": {
"Icon": "Nothing",
@ -28,7 +32,8 @@ viewSettings = {
"Background": "Nothing",
},
}
# Application
spellcheck = False
dict = None
corkSizeFactor = 100
@ -81,7 +86,7 @@ frequencyAnalyzer = {
"phraseMax": 5
}
def save(filename=None):
def save(filename=None, protocol=None):
global spellcheck, dict, corkSliderFactor, viewSettings, corkSizeFactor, folderView, lastTab, openIndexes, \
autoSave, autoSaveDelay, saveOnQuit, autoSaveNoChanges, autoSaveNoChangesDelay, outlineViewColumns, \
@ -107,7 +112,7 @@ def save(filename=None):
"textEditor":textEditor,
"revisions":revisions,
"frequencyAnalyzer": frequencyAnalyzer
}
}
#pp=pprint.PrettyPrinter(indent=4, compact=False)
#print("Saving:")
@ -117,9 +122,16 @@ def save(filename=None):
f = open(filename, "wb")
pickle.dump(allSettings, f)
else:
return pickle.dumps(allSettings)
def load(string, fromString=False):
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, protocol=None):
"""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
@ -133,8 +145,11 @@ def load(string, fromString=False):
print("{} doesn't exist, cannot load settings.".format(string))
return
else:
allSettings = pickle.loads(string)
if protocol == 0:
allSettings = json.loads(string)
else:
allSettings = pickle.loads(string)
#pp=pprint.PrettyPrinter(indent=4, compact=False)
#print("Loading:")
#pp.pprint(allSettings)
@ -211,6 +226,17 @@ def load(string, fromString=False):
global revisions
revisions = allSettings["revisions"]
# With JSON we had to convert int keys to str, and None to "null", so we roll back.
r = {}
for i in revisions["rules"]:
if i == "null":
r[None] = revisions["rules"]["null"]
continue
elif i == None:
continue
r[int(i)] = revisions["rules"][i]
revisions["rules"] = r
if "frequencyAnalyzer" in allSettings:
global frequencyAnalyzer
frequencyAnalyzer = allSettings["frequencyAnalyzer"]

View file

@ -4,7 +4,7 @@ from PyQt5.QtCore import pyqtSignal, Qt, QTimer, QRect
from PyQt5.QtGui import QBrush, QCursor, QPalette, QFontMetrics
from PyQt5.QtWidgets import QWidget, QListWidgetItem, QToolTip, QStyledItemDelegate, QStyle
from manuskript.enums import Perso
from manuskript.enums import Character
from manuskript.enums import Plot
from manuskript.functions import lightBlue
from manuskript.functions import mainWindow
@ -36,7 +36,7 @@ class cheatSheet(QWidget, Ui_cheatSheet):
self.line.hide()
self.outlineModel = None
self.persoModel = None
self.characterModel = None
self.plotModel = None
self.worldModel = None
@ -53,12 +53,14 @@ class cheatSheet(QWidget, Ui_cheatSheet):
def setModels(self):
mw = mainWindow()
self.outlineModel = mw.mdlOutline
self.persoModel = mw.mdlPersos
self.characterModel = mw.mdlCharacter
self.plotModel = mw.mdlPlots
self.worldModel = mw.mdlWorld
self.outlineModel.dataChanged.connect(self.populateTimer.start)
self.persoModel.dataChanged.connect(self.populateTimer.start)
self.characterModel.dataChanged.connect(self.populateTimer.start)
self.characterModel.rowsInserted.connect(self.populateTimer.start)
self.characterModel.rowsRemoved.connect(self.populateTimer.start)
self.plotModel.dataChanged.connect(self.populateTimer.start)
self.worldModel.dataChanged.connect(self.populateTimer.start)
@ -75,17 +77,14 @@ class cheatSheet(QWidget, Ui_cheatSheet):
self.list.hide()
def populate(self):
if self.persoModel:
if self.characterModel:
d = []
for r in range(self.persoModel.rowCount()):
name = self.persoModel.item(r, Perso.name.value).text()
ID = self.persoModel.item(r, Perso.ID.value).text()
imp = self.persoModel.item(r, Perso.importance.value).text()
imp = [self.tr("Minor"), self.tr("Secondary"), self.tr("Main")][int(imp)]
d.append((name, ID, imp))
for c in self.characterModel.characters:
imp = [self.tr("Minor"), self.tr("Secondary"), self.tr("Main")][int(c.importance())]
d.append((c.name(), c.ID(), imp))
self.data[(self.tr("Characters"), Ref.PersoLetter)] = d
self.data[(self.tr("Characters"), Ref.CharacterLetter)] = d
if self.outlineModel:
d = []

View file

@ -61,7 +61,7 @@ class basicHighlighter(QSyntaxHighlighter):
fmt.setFontWeight(QFont.DemiBold)
if txt.group(1) == Ref.TextLetter:
fmt.setBackground(QBrush(QColor(Qt.blue).lighter(190)))
elif txt.group(1) == Ref.PersoLetter:
elif txt.group(1) == Ref.CharacterLetter:
fmt.setBackground(QBrush(QColor(Qt.yellow).lighter(170)))
elif txt.group(1) == Ref.PlotLetter:
fmt.setBackground(QBrush(QColor(Qt.red).lighter(170)))

View file

@ -173,7 +173,7 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
elif item and item.isFolder() and self.folderView == "outline":
self.stack.setCurrentIndex(3)
self.outlineView.setModelPersos(mainWindow().mdlPersos)
self.outlineView.setModelCharacters(mainWindow().mdlCharacter)
self.outlineView.setModelLabels(mainWindow().mdlLabels)
self.outlineView.setModelStatus(mainWindow().mdlStatus)
self.outlineView.setModel(self.mw.mdlOutline)

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/mainWindow.ui'
#
# Created: Wed Mar 2 00:30:17 2016
# Created: Thu Mar 3 18:52:22 2016
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
@ -337,12 +337,12 @@ class Ui_MainWindow(object):
self.groupBox.setObjectName("groupBox")
self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.groupBox)
self.verticalLayout_8.setObjectName("verticalLayout_8")
self.lstPersos = persoTreeView(self.groupBox)
self.lstPersos.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.lstPersos.setDragEnabled(True)
self.lstPersos.setObjectName("lstPersos")
self.lstPersos.headerItem().setText(0, "1")
self.verticalLayout_8.addWidget(self.lstPersos)
self.lstCharacters = characterTreeView(self.groupBox)
self.lstCharacters.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.lstCharacters.setDragEnabled(True)
self.lstCharacters.setObjectName("lstCharacters")
self.lstCharacters.headerItem().setText(0, "1")
self.verticalLayout_8.addWidget(self.lstCharacters)
self.horizontalLayout_14 = QtWidgets.QHBoxLayout()
self.horizontalLayout_14.setObjectName("horizontalLayout_14")
self.btnAddPerso = QtWidgets.QPushButton(self.groupBox)
@ -1166,7 +1166,7 @@ class Ui_MainWindow(object):
self.retranslateUi(MainWindow)
self.stack.setCurrentIndex(1)
self.tabMain.setCurrentIndex(6)
self.tabMain.setCurrentIndex(2)
self.tabSummary.setCurrentIndex(0)
self.tabPersos.setCurrentIndex(0)
self.tabPlot.setCurrentIndex(0)
@ -1303,18 +1303,18 @@ class Ui_MainWindow(object):
self.actCompile.setShortcut(_translate("MainWindow", "F6"))
self.actToolFrequency.setText(_translate("MainWindow", "&Frequency Analyzer"))
from manuskript.ui.views.storylineView import storylineView
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.views.treeView import treeView
from manuskript.ui.editors.mainEditor import mainEditor
from manuskript.ui.views.basicItemView import basicItemView
from manuskript.ui.views.persoTreeView import persoTreeView
from manuskript.ui.views.plotTreeView import plotTreeView
from manuskript.ui.views.outlineView import outlineView
from manuskript.ui.views.metadataView import metadataView
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.basicItemView import basicItemView
from manuskript.ui.views.plotTreeView import plotTreeView
from manuskript.ui.cheatSheet import cheatSheet
from manuskript.ui.views.textEditCompleter import textEditCompleter
from manuskript.ui.sldImportance import sldImportance
from manuskript.ui.welcome import welcome
from manuskript.ui.views.sldImportance import sldImportance
from manuskript.ui.views.metadataView import metadataView
from manuskript.ui.views.characterTreeView import characterTreeView
from manuskript.ui.editors.mainEditor import mainEditor
from manuskript.ui.search import search
from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.welcome import welcome
from manuskript.ui.views.treeView import treeView
from manuskript.ui.views.textEditCompleter import textEditCompleter
from manuskript.ui.views.storylineView import storylineView

View file

@ -124,7 +124,7 @@
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>6</number>
<number>2</number>
</property>
<property name="documentMode">
<bool>true</bool>
@ -714,7 +714,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="persoTreeView" name="lstPersos">
<widget class="characterTreeView" name="lstCharacters">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
@ -2358,7 +2358,7 @@ QListView::item:hover {
<customwidget>
<class>sldImportance</class>
<extends>QWidget</extends>
<header>manuskript.ui.sldImportance.h</header>
<header>manuskript.ui.views.sldImportance.h</header>
<container>1</container>
</customwidget>
<customwidget>
@ -2396,9 +2396,9 @@ QListView::item:hover {
<container>1</container>
</customwidget>
<customwidget>
<class>persoTreeView</class>
<class>characterTreeView</class>
<extends>QTreeWidget</extends>
<header>manuskript.ui.views.persoTreeView.h</header>
<header>manuskript.ui.views.characterTreeView.h</header>
</customwidget>
<customwidget>
<class>cheatSheet</class>

View file

@ -14,8 +14,8 @@ class basicItemView(QWidget, Ui_basicItemView):
self.txtSummaryFull.setColumn(Outline.summaryFull.value)
self.txtGoal.setColumn(Outline.setGoal.value)
def setModels(self, mdlOutline, mdlPersos, mdlLabels, mdlStatus):
self.cmbPOV.setModels(mdlPersos, mdlOutline)
def setModels(self, mdlOutline, mdlCharacter, mdlLabels, mdlStatus):
self.cmbPOV.setModels(mdlCharacter, mdlOutline)
self.txtSummarySentence.setModel(mdlOutline)
self.txtSummaryFull.setModel(mdlOutline)
self.txtGoal.setModel(mdlOutline)

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/views/basicItemView_ui.ui'
#
# Created: Wed Mar 2 00:33:34 2016
# Created: Thu Mar 3 17:26:11 2016
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
@ -24,7 +24,7 @@ class Ui_basicItemView(object):
self.lblPlanPOV.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.lblPlanPOV.setObjectName("lblPlanPOV")
self.horizontalLayout_11.addWidget(self.lblPlanPOV)
self.cmbPOV = cmbOutlinePersoChoser(basicItemView)
self.cmbPOV = cmbOutlineCharacterChoser(basicItemView)
self.cmbPOV.setFrame(False)
self.cmbPOV.setObjectName("cmbPOV")
self.horizontalLayout_11.addWidget(self.cmbPOV)
@ -67,6 +67,6 @@ class Ui_basicItemView(object):
self.txtSummarySentence.setPlaceholderText(_translate("basicItemView", "One line summary"))
self.label_9.setText(_translate("basicItemView", "Few sentences summary:"))
from manuskript.ui.views.cmbOutlinePersoChoser import cmbOutlinePersoChoser
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.cmbOutlineCharacterChoser import cmbOutlineCharacterChoser
from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.views.textEditView import textEditView

View file

@ -43,7 +43,7 @@
</widget>
</item>
<item>
<widget class="cmbOutlinePersoChoser" name="cmbPOV">
<widget class="cmbOutlineCharacterChoser" name="cmbPOV">
<property name="frame">
<bool>false</bool>
</property>
@ -112,9 +112,9 @@
<header>manuskript.ui.views.textEditView.h</header>
</customwidget>
<customwidget>
<class>cmbOutlinePersoChoser</class>
<class>cmbOutlineCharacterChoser</class>
<extends>QComboBox</extends>
<header>manuskript.ui.views.cmbOutlinePersoChoser.h</header>
<header>manuskript.ui.views.cmbOutlineCharacterChoser.h</header>
</customwidget>
<customwidget>
<class>lineEditView</class>

View file

@ -2,12 +2,16 @@
# --!-- coding: utf8 --!--
from PyQt5.QtCore import QSize, QModelIndex, Qt
from PyQt5.QtGui import QPixmap, QColor, QIcon, QBrush
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QColorDialog
from manuskript.enums import Perso
from manuskript.enums import Character
from manuskript.functions import iconColor, mainWindow
class persoTreeView(QTreeWidget):
class characterTreeView(QTreeWidget):
"""
A QTreeWidget that displays characters from a characterModel in respect of their importance.
"""
def __init__(self, parent=None):
QTreeWidget.__init__(self, parent)
self._model = None
@ -24,7 +28,7 @@ class persoTreeView(QTreeWidget):
self._rootItem = QTreeWidgetItem()
self.insertTopLevelItem(0, self._rootItem)
def setPersosModel(self, model):
def setCharactersModel(self, model):
self._model = model
self._model.dataChanged.connect(self.updateMaybe)
self._model.rowsInserted.connect(self.updateMaybe2)
@ -39,11 +43,11 @@ class persoTreeView(QTreeWidget):
if topLeft.parent() != QModelIndex():
return
if topLeft.column() <= Perso.name.value <= bottomRight.column():
if topLeft.column() <= Character.name.value <= bottomRight.column():
# Update name
self.updateNames()
elif topLeft.column() <= Perso.importance.value <= bottomRight.column():
elif topLeft.column() <= Character.importance.value <= bottomRight.column():
# Importance changed
self.updateItems()
@ -56,16 +60,17 @@ class persoTreeView(QTreeWidget):
for i in range(self.topLevelItemCount()):
item = self.topLevelItem(i)
for c in range(item.childCount()):
sub = item.child(c)
for child in range(item.childCount()):
sub = item.child(child)
ID = sub.data(0, Qt.UserRole)
if ID:
if ID is not None:
# Update name
name = self._model.getPersoNameByID(ID)
c = self._model.getCharacterByID(ID)
name = c.name()
sub.setText(0, name)
# Update icon
px = QPixmap(32, 32)
color = QColor(self._model.getPersoColorByID(ID))
color = c.color()
px.fill(color)
sub.setIcon(0, QIcon(px))
@ -78,10 +83,12 @@ class persoTreeView(QTreeWidget):
self._updating = True
self.clear()
persos = self._model.getPersosByImportance()
characters = self._model.getCharactersByImportance()
h = [self.tr("Main"), self.tr("Secondary"), self.tr("Minor")]
for i in range(3):
# Create category item
cat = QTreeWidgetItem(self, [h[i]])
cat.setBackground(0, QBrush(QColor(Qt.blue).lighter(190)))
cat.setForeground(0, QBrush(Qt.darkBlue))
@ -92,23 +99,68 @@ class persoTreeView(QTreeWidget):
self.addTopLevelItem(cat)
# cat.setChildIndicatorPolicy(cat.DontShowIndicator)
for ID in persos[i]:
name = self._model.getPersoNameByID(ID)
for c in characters[i]:
name = c.name()
# Check if name passes filter
if not self._filter.lower() in name.lower():
continue
item = QTreeWidgetItem(cat, [name])
item.setData(0, Qt.UserRole, ID)
item.setData(0, Qt.UserRole, c.ID())
px = QPixmap(32, 32)
color = QColor(self._model.getPersoColorByID(ID))
color = QColor(c.color())
px.fill(color)
item.setIcon(0, QIcon(px))
if ID == self._lastID:
if c.ID() == self._lastID:
self.setCurrentItem(item)
self.expandAll()
self._updating = False
def removeCharacter(self):
"""
Removes selected character.
"""
ID = self.currentCharacterID()
if ID:
self._model.removeCharacter(ID)
def choseCharacterColor(self):
ID = self.currentCharacterID()
c = self._model.getCharacterByID(ID)
if c:
color = iconColor(c.icon)
else:
color = Qt.white
self.colorDialog = QColorDialog(color, mainWindow())
color = self.colorDialog.getColor(color)
if color.isValid():
c.setColor(color)
mainWindow().updateCharacterColor(ID)
def addCharacterInfo(self):
self._model.addCharacterInfo(self.currentCharacterID())
def removeCharacterInfo(self):
self._model.removeCharacterInfo(self.currentCharacterID(),
)
def currentCharacterID(self):
ID = None
if self.currentItem():
ID = self.currentItem().data(0, Qt.UserRole)
return ID
def currentCharacter(self):
"""
Returns the selected character
@return: Character
"""
ID = self.currentCharacterID()
return self._model.getCharacterByID(ID)
def getItemByID(self, ID):
for t in range(self.topLevelItemCount()):
for i in range(self.topLevelItem(t).childCount()):
@ -116,13 +168,6 @@ class persoTreeView(QTreeWidget):
if item.data(0, Qt.UserRole) == ID:
return item
def currentPersoIndex(self):
ID = None
if self.currentItem():
ID = self.currentItem().data(0, Qt.UserRole)
return self._model.getIndexFromID(ID)
def mouseDoubleClickEvent(self, event):
item = self.currentItem()
# Catching double clicks to forbid collapsing of toplevel items

View file

@ -8,7 +8,7 @@ from manuskript.enums import Outline
from manuskript.functions import toInt
class cmbOutlinePersoChoser(QComboBox):
class cmbOutlineCharacterChoser(QComboBox):
def __init__(self, parent=None):
QComboBox.__init__(self, parent)
self.activated[int].connect(self.submit)
@ -18,9 +18,12 @@ class cmbOutlinePersoChoser(QComboBox):
self._updating = False
self._various = False
def setModels(self, mdlPersos, mdlOutline):
self.mdlPersos = mdlPersos
self.mdlPersos.dataChanged.connect(self.updateItems)
def setModels(self, mdlCharacter, mdlOutline):
self.mdlCharacters = mdlCharacter
self.mdlCharacters.dataChanged.connect(self.updateItems)
self.mdlCharacters.rowsInserted.connect(self.updateItems)
self.mdlCharacters.rowsRemoved.connect(self.updateItems)
self.mdlOutline = mdlOutline
self.mdlOutline.dataChanged.connect(self.update)
self.updateItems()
@ -37,14 +40,14 @@ class cmbOutlinePersoChoser(QComboBox):
self.setItemData(self.count() - 1, QBrush(QColor(Qt.blue).lighter(190)), Qt.BackgroundRole)
item = self.model().item(self.count() - 1)
item.setFlags(Qt.ItemIsEnabled)
for i in range(self.mdlPersos.rowCount()):
imp = toInt(self.mdlPersos.importance(i))
for i in range(self.mdlCharacters.rowCount()):
imp = toInt(self.mdlCharacters.importance(i))
if not 2 - imp == importance:
continue
self.addItem(self.mdlPersos.icon(i), self.mdlPersos.name(i), self.mdlPersos.ID(i))
self.setItemData(self.count() - 1, self.mdlPersos.name(i), Qt.ToolTipRole)
self.addItem(self.mdlCharacters.icon(i), self.mdlCharacters.name(i), self.mdlCharacters.ID(i))
self.setItemData(self.count() - 1, self.mdlCharacters.name(i), Qt.ToolTipRole)
self._various = False

View file

@ -16,8 +16,8 @@ class metadataView(QWidget, Ui_metadataView):
self.txtNotes.setColumn(Outline.notes.value)
self.revisions.setEnabled(False)
def setModels(self, mdlOutline, mdlPersos, mdlLabels, mdlStatus):
self.properties.setModels(mdlOutline, mdlPersos, mdlLabels, mdlStatus)
def setModels(self, mdlOutline, mdlCharacter, mdlLabels, mdlStatus):
self.properties.setModels(mdlOutline, mdlCharacter, mdlLabels, mdlStatus)
self.txtSummarySentence.setModel(mdlOutline)
self.txtSummaryFull.setModel(mdlOutline)
self.txtNotes.setModel(mdlOutline)

View file

@ -83,12 +83,12 @@ class outlineBasics(QAbstractItemView):
self.menuPOV.addMenu(m)
mpr = QSignalMapper(self.menuPOV)
for i in range(mw.mdlPersos.rowCount()):
a = QAction(mw.mdlPersos.icon(i), mw.mdlPersos.name(i), self.menuPOV)
for i in range(mw.mdlCharacter.rowCount()):
a = QAction(mw.mdlCharacter.icon(i), mw.mdlCharacter.name(i), self.menuPOV)
a.triggered.connect(mpr.map)
mpr.setMapping(a, int(mw.mdlPersos.ID(i)))
mpr.setMapping(a, int(mw.mdlCharacter.ID(i)))
imp = toInt(mw.mdlPersos.importance(i))
imp = toInt(mw.mdlCharacter.importance(i))
menus[2 - imp].addAction(a)

View file

@ -6,7 +6,7 @@ from PyQt5.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem, QStyle, Q
from PyQt5.QtWidgets import qApp
from manuskript import settings
from manuskript.enums import Perso, Outline
from manuskript.enums import Character, Outline
from manuskript.functions import outlineItemColors, mixColors, colorifyPixmap, toInt, toFloat, drawProgress
@ -92,18 +92,18 @@ class outlineTitleDelegate(QStyledItemDelegate):
# QStyledItemDelegate.paint(self, painter, option, index)
class outlinePersoDelegate(QStyledItemDelegate):
def __init__(self, mdlPersos, parent=None):
class outlineCharacterDelegate(QStyledItemDelegate):
def __init__(self, mdlCharacter, parent=None):
QStyledItemDelegate.__init__(self, parent)
self.mdlPersos = mdlPersos
self.mdlCharacter = mdlCharacter
def sizeHint(self, option, index):
# s = QStyledItemDelegate.sizeHint(self, option, index)
item = QModelIndex()
for i in range(self.mdlPersos.rowCount()):
if self.mdlPersos.ID(i) == index.data():
item = self.mdlPersos.index(i, Perso.name.value)
character = self.mdlCharacter.getCharacterByID(index.data())
if character:
item = character.index(Character.name.value)
opt = QStyleOptionViewItem(option)
self.initStyleOption(opt, item)
@ -136,13 +136,13 @@ class outlinePersoDelegate(QStyledItemDelegate):
editor.setItemData(editor.count() - 1, QBrush(QColor(Qt.blue).lighter(190)), Qt.BackgroundRole)
item = editor.model().item(editor.count() - 1)
item.setFlags(Qt.ItemIsEnabled)
for i in range(self.mdlPersos.rowCount()):
imp = toInt(self.mdlPersos.importance(i))
for i in range(self.mdlCharacter.rowCount()):
imp = toInt(self.mdlCharacter.importance(i))
if not 2 - imp == importance: continue
# try:
editor.addItem(self.mdlPersos.icon(i), self.mdlPersos.name(i), self.mdlPersos.ID(i))
editor.setItemData(editor.count() - 1, self.mdlPersos.name(i), Qt.ToolTipRole)
editor.addItem(self.mdlCharacter.icon(i), self.mdlCharacter.name(i), self.mdlCharacter.ID(i))
editor.setItemData(editor.count() - 1, self.mdlCharacter.name(i), Qt.ToolTipRole)
# except:
# pass
@ -158,18 +158,21 @@ class outlinePersoDelegate(QStyledItemDelegate):
# QStyledItemDelegate.paint(self, painter, option, index)
##option.rect.setWidth(option.rect.width() + 18)
item = QModelIndex()
for i in range(self.mdlPersos.rowCount()):
if self.mdlPersos.ID(i) == index.data():
item = self.mdlPersos.index(i, Perso.name.value)
itemIndex = QModelIndex()
character = self.mdlCharacter.getCharacterByID(index.data())
if character:
itemIndex = character.index(Character.name.value)
else:
# Character ID not found in character model.
return
opt = QStyleOptionViewItem(option)
self.initStyleOption(opt, item)
self.initStyleOption(opt, itemIndex)
qApp.style().drawControl(QStyle.CE_ItemViewItem, opt, painter)
# if index.isValid() and index.internalPointer().data(Outline.POV.value) not in ["", None]:
if index.isValid() and self.mdlPersos.data(index) not in ["", None]:
if itemIndex.isValid() and self.mdlCharacter.data(itemIndex) not in ["", None]:
opt = QStyleOptionComboBox()
opt.rect = option.rect
r = qApp.style().subControlRect(QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxArrow)

View file

@ -6,25 +6,25 @@ from manuskript import settings
from manuskript.enums import Outline
from manuskript.ui.views.dndView import dndView
from manuskript.ui.views.outlineBasics import outlineBasics
from manuskript.ui.views.outlineDelegates import outlineTitleDelegate, outlinePersoDelegate, outlineCompileDelegate, \
from manuskript.ui.views.outlineDelegates import outlineTitleDelegate, outlineCharacterDelegate, outlineCompileDelegate, \
outlineStatusDelegate, outlineGoalPercentageDelegate, outlineLabelDelegate
class outlineView(QTreeView, dndView, outlineBasics):
def __init__(self, parent=None, modelPersos=None, modelLabels=None, modelStatus=None):
def __init__(self, parent=None, modelCharacters=None, modelLabels=None, modelStatus=None):
QTreeView.__init__(self, parent)
dndView.__init__(self)
outlineBasics.__init__(self, parent)
self.modelPersos = modelPersos
self.modelCharacters = modelCharacters
self.modelLabels = modelLabels
self.modelStatus = modelStatus
self.header().setStretchLastSection(False)
def setModelPersos(self, model):
# This is used by outlinePersoDelegate to select character
self.modelPersos = model
def setModelCharacters(self, model):
# This is used by outlineCharacterDelegate to select character
self.modelCharacters = model
def setModelLabels(self, model):
# This is used by outlineLabelDelegate to display labels
@ -41,8 +41,8 @@ class outlineView(QTreeView, dndView, outlineBasics):
self.outlineTitleDelegate = outlineTitleDelegate(self)
# self.outlineTitleDelegate.setView(self)
self.setItemDelegateForColumn(Outline.title.value, self.outlineTitleDelegate)
self.outlinePersoDelegate = outlinePersoDelegate(self.modelPersos)
self.setItemDelegateForColumn(Outline.POV.value, self.outlinePersoDelegate)
self.outlineCharacterDelegate = outlineCharacterDelegate(self.modelCharacters)
self.setItemDelegateForColumn(Outline.POV.value, self.outlineCharacterDelegate)
self.outlineCompileDelegate = outlineCompileDelegate()
self.setItemDelegateForColumn(Outline.compile.value, self.outlineCompileDelegate)
self.outlineStatusDelegate = outlineStatusDelegate(self.modelStatus)

View file

@ -12,8 +12,8 @@ class propertiesView(QWidget, Ui_propertiesView):
self.setupUi(self)
self.txtGoal.setColumn(Outline.setGoal.value)
def setModels(self, mdlOutline, mdlPersos, mdlLabels, mdlStatus):
self.cmbPOV.setModels(mdlPersos, mdlOutline)
def setModels(self, mdlOutline, mdlCharacter, mdlLabels, mdlStatus):
self.cmbPOV.setModels(mdlCharacter, mdlOutline)
self.cmbLabel.setModels(mdlLabels, mdlOutline)
self.cmbStatus.setModels(mdlStatus, mdlOutline)
self.cmbType.setModel(mdlOutline)

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/views/propertiesView_ui.ui'
#
# Created: Wed Mar 2 00:30:18 2016
# Created: Thu Mar 3 17:26:11 2016
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
@ -37,7 +37,7 @@ class Ui_propertiesView(object):
self.lblPOV = QtWidgets.QLabel(self.page)
self.lblPOV.setObjectName("lblPOV")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lblPOV)
self.cmbPOV = cmbOutlinePersoChoser(self.page)
self.cmbPOV = cmbOutlineCharacterChoser(self.page)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@ -116,7 +116,7 @@ class Ui_propertiesView(object):
self.lblPOV_2 = QtWidgets.QLabel(self.page_2)
self.lblPOV_2.setObjectName("lblPOV_2")
self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lblPOV_2)
self.cmbPOVMulti = cmbOutlinePersoChoser(self.page_2)
self.cmbPOVMulti = cmbOutlineCharacterChoser(self.page_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@ -195,9 +195,9 @@ class Ui_propertiesView(object):
self.label_36.setText(_translate("propertiesView", "Goal"))
self.txtGoalMulti.setPlaceholderText(_translate("propertiesView", "Word count"))
from manuskript.ui.views.cmbOutlineStatusChoser import cmbOutlineStatusChoser
from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.views.chkOutlineCompile import chkOutlineCompile
from manuskript.ui.views.cmbOutlineLabelChoser import cmbOutlineLabelChoser
from manuskript.ui.views.cmbOutlineCharacterChoser import cmbOutlineCharacterChoser
from manuskript.ui.views.cmbOutlineTypeChoser import cmbOutlineTypeChoser
from manuskript.ui.views.cmbOutlinePersoChoser import cmbOutlinePersoChoser
from manuskript.ui.views.chkOutlineCompile import chkOutlineCompile
from manuskript.ui.views.cmbOutlineStatusChoser import cmbOutlineStatusChoser
from manuskript.ui.views.cmbOutlineLabelChoser import cmbOutlineLabelChoser

View file

@ -53,7 +53,7 @@
</widget>
</item>
<item row="0" column="1">
<widget class="cmbOutlinePersoChoser" name="cmbPOV">
<widget class="cmbOutlineCharacterChoser" name="cmbPOV">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -190,7 +190,7 @@
</widget>
</item>
<item row="0" column="1">
<widget class="cmbOutlinePersoChoser" name="cmbPOVMulti">
<widget class="cmbOutlineCharacterChoser" name="cmbPOVMulti">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -300,9 +300,9 @@
<header>manuskript.ui.views.lineEditView.h</header>
</customwidget>
<customwidget>
<class>cmbOutlinePersoChoser</class>
<class>cmbOutlineCharacterChoser</class>
<extends>QComboBox</extends>
<header>manuskript.ui.views.cmbOutlinePersoChoser.h</header>
<header>manuskript.ui.views.cmbOutlineCharacterChoser.h</header>
</customwidget>
<customwidget>
<class>cmbOutlineStatusChoser</class>

View file

@ -2,9 +2,9 @@
# --!-- coding: utf8 --!--
from PyQt5.QtCore import pyqtSignal, pyqtProperty
from PyQt5.QtWidgets import QWidget
from manuskript.ui.views.sldImportance_ui import Ui_sldImportance
from manuskript.functions import toInt
from manuskript.ui.sldImportance_ui import Ui_sldImportance
class sldImportance(QWidget, Ui_sldImportance):

View file

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'manuskript/ui/sldImportance_ui.ui'
# Form implementation generated from reading ui file 'manuskript/ui/views/sldImportance_ui.ui'
#
# Created by: PyQt5 UI code generator 5.4.1
# Created: Thu Mar 3 18:52:22 2016
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtWidgets
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_sldImportance(object):
def setupUi(self, sldImportance):

View file

@ -46,7 +46,7 @@ class storylineView(QWidget, Ui_storylineView):
self.btnSettings.setMenu(m)
def setModels(self, mdlOutline, mdlPersos, mdlPlots):
def setModels(self, mdlOutline, mdlCharacter, mdlPlots):
self._mdlPlots = mdlPlots
# self._mdlPlots.dataChanged.connect(self.refresh)
# self._mdlPlots.rowsInserted.connect(self.refresh)
@ -54,8 +54,8 @@ class storylineView(QWidget, Ui_storylineView):
self._mdlOutline = mdlOutline
self._mdlOutline.dataChanged.connect(self.reloadTimer.start)
self._mdlPersos = mdlPersos
self._mdlPersos.dataChanged.connect(self.reloadTimer.start)
self._mdlCharacter = mdlCharacter
self._mdlCharacter.dataChanged.connect(self.reloadTimer.start)
def plotReferences(self):
"Returns a list of plot references"
@ -71,22 +71,22 @@ class storylineView(QWidget, Ui_storylineView):
return r
def persosReferences(self):
def charactersReferences(self):
"Returns a list of character references"
if not self._mdlPersos:
if not self._mdlCharacter:
pass
IDs = self._mdlPersos.getPersosByImportance()
chars = self._mdlCharacter.getCharactersByImportance()
r = []
for importance in IDs:
for ID in importance:
ref = references.persoReference(ID)
for importance in chars:
for c in importance:
ref = references.characterReference(c.ID())
r.append(ref)
return r
def refresh(self):
if not self._mdlPlots or not self._mdlOutline or not self._mdlPersos:
if not self._mdlPlots or not self._mdlOutline or not self._mdlCharacter:
pass
LINE_HEIGHT = 18
@ -118,7 +118,7 @@ class storylineView(QWidget, Ui_storylineView):
trackedItems += self.plotReferences()
if self.actCharacters.isChecked():
trackedItems += self.persosReferences()
trackedItems += self.charactersReferences()
ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING )
@ -185,7 +185,7 @@ class storylineView(QWidget, Ui_storylineView):
# Tests if POV
scenePOV = False # Will hold true of character is POV of the current text, not containing folder
if references.type(ref) == references.PersoLetter:
if references.type(ref) == references.CharacterLetter:
ID = references.ID(ref)
c = child
while c:
@ -221,8 +221,8 @@ class storylineView(QWidget, Ui_storylineView):
itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING)
for ref in trackedItems:
if references.type(ref) == references.PersoLetter:
color = QColor(self._mdlPersos.getPersoColorByID(references.ID(ref)))
if references.type(ref) == references.CharacterLetter:
color = self._mdlCharacter.getCharacterByID(references.ID(ref)).color()
else:
color = randomColor()

View file

@ -12,9 +12,9 @@ from PyQt5.QtWidgets import QWidget, QAction, QFileDialog, QSpinBox, QLineEdit,
from manuskript import settings
from manuskript.enums import Outline
from manuskript.functions import mainWindow, iconFromColor, appPath
from manuskript.models.characterModel import characterModel
from manuskript.models.outlineModel import outlineItem
from manuskript.models.outlineModel import outlineModel
from manuskript.models.persosModel import persosModel
from manuskript.models.plotModel import plotModel
from manuskript.models.worldModel import worldModel
from manuskript.ui.welcome_ui import Ui_welcome
@ -345,7 +345,7 @@ class welcome(QWidget, Ui_welcome):
# Persos
# self.mw.mdlPersos = QStandardItemModel(0, 0, self.mw)
self.mw.mdlPersos = persosModel(self.mw)
self.mw.mdlCharacter = characterModel(self.mw)
# self.mdlPersosProxy = None # persosProxyModel() # None
# self.mw.mdlPersosProxy = persosProxyModel(self.mw)