mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-05-15 02:12:29 +12:00
Restore revisions, and better html output
This commit is contained in:
parent
3f175f2d4b
commit
92b270c651
Binary file not shown.
|
@ -214,7 +214,7 @@
|
|||
<translation>Contexte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1022"/>
|
||||
<location filename="../src/mainWindow.py" line="1042"/>
|
||||
<source>Outline</source>
|
||||
<translation>Plan</translation>
|
||||
</message>
|
||||
|
@ -329,62 +329,62 @@
|
|||
<translation>Mode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="854"/>
|
||||
<location filename="../src/mainWindow.py" line="875"/>
|
||||
<source> (~{} pages)</source>
|
||||
<translation> (~{} pages)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="881"/>
|
||||
<location filename="../src/mainWindow.py" line="901"/>
|
||||
<source>Enter infos about your book, and yourself.</source>
|
||||
<translation>Entrez toutes les informations relatives au livre, ainsi qu'à vous.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="887"/>
|
||||
<location filename="../src/mainWindow.py" line="907"/>
|
||||
<source>Take time to think about a one sentance (~50 words) summary of your book. Then expand it to a paragraph, then to a page, then to a full summary.</source>
|
||||
<translation>Prenez le temps de réfléchir à un résumé de votre livre, en une phrase (~50 mots). Puis augmentez cette phrase en un paragraphe, puis en une page, puis en un résumé complet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="890"/>
|
||||
<location filename="../src/mainWindow.py" line="910"/>
|
||||
<source>Create your characters.</source>
|
||||
<translation>Créez ici vos personnage.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="893"/>
|
||||
<location filename="../src/mainWindow.py" line="913"/>
|
||||
<source>Develop plots.</source>
|
||||
<translation>Développez vos intrigues.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="896"/>
|
||||
<location filename="../src/mainWindow.py" line="916"/>
|
||||
<source>Create the outline of your masterpiece.</source>
|
||||
<translation>Créez le plan de votre chef-d'œuvre.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="899"/>
|
||||
<location filename="../src/mainWindow.py" line="919"/>
|
||||
<source>Write.</source>
|
||||
<translation>Écrivez.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="902"/>
|
||||
<location filename="../src/mainWindow.py" line="922"/>
|
||||
<source>Debug infos. Sometimes useful.</source>
|
||||
<translation>Des infos pour débugger des fois pendant qu'on code c'est utile.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="916"/>
|
||||
<location filename="../src/mainWindow.py" line="936"/>
|
||||
<source>Dictionary</source>
|
||||
<translation>Dictionnaire</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="929"/>
|
||||
<location filename="../src/mainWindow.py" line="949"/>
|
||||
<source>Install PyEnchant to use spellcheck</source>
|
||||
<translation>Installez PyEnchant pour profiter du correcteur orthographique</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="858"/>
|
||||
<location filename="../src/mainWindow.py" line="879"/>
|
||||
<source>Words: {}{}</source>
|
||||
<translation>Mots: {}{}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1033"/>
|
||||
<location filename="../src/mainWindow.py" line="1053"/>
|
||||
<source>Text</source>
|
||||
<translation>Texte</translation>
|
||||
</message>
|
||||
|
@ -424,7 +424,7 @@
|
|||
<translation>Et si...?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1021"/>
|
||||
<location filename="../src/mainWindow.py" line="1041"/>
|
||||
<source>Index cards</source>
|
||||
<translation>Cartes</translation>
|
||||
</message>
|
||||
|
@ -444,7 +444,7 @@
|
|||
<translation>F9</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1020"/>
|
||||
<location filename="../src/mainWindow.py" line="1040"/>
|
||||
<source>Tree</source>
|
||||
<translation>Arbre</translation>
|
||||
</message>
|
||||
|
@ -469,77 +469,77 @@
|
|||
<translation>Réglages</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="512"/>
|
||||
<location filename="../src/mainWindow.py" line="533"/>
|
||||
<source>Project {} saved.</source>
|
||||
<translation>Le projet {} a été enregistré.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="583"/>
|
||||
<location filename="../src/mainWindow.py" line="604"/>
|
||||
<source>Project {} loaded.</source>
|
||||
<translation>Le projet {} a été chargé.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="884"/>
|
||||
<location filename="../src/mainWindow.py" line="904"/>
|
||||
<source>The basic situation, in the form of a 'What if...?' question. Ex: 'What if the most dangerous evil wizard could wasn't abled to kill a baby?' (Harry Potter)</source>
|
||||
<translation>La situation de base, sous la forme d'une question: "Et si...?" Par exemple: "Et si le plus dangereux magiciens mauvais n'était pas capable de tuer un bébé?" (Harry Potter)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1012"/>
|
||||
<location filename="../src/mainWindow.py" line="1032"/>
|
||||
<source>Nothing</source>
|
||||
<translation>Rien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1013"/>
|
||||
<location filename="../src/mainWindow.py" line="1033"/>
|
||||
<source>POV</source>
|
||||
<translation>POV</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1014"/>
|
||||
<location filename="../src/mainWindow.py" line="1034"/>
|
||||
<source>Label</source>
|
||||
<translation>Label</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1015"/>
|
||||
<location filename="../src/mainWindow.py" line="1035"/>
|
||||
<source>Progress</source>
|
||||
<translation>Progrès</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1016"/>
|
||||
<location filename="../src/mainWindow.py" line="1036"/>
|
||||
<source>Compile</source>
|
||||
<translation>Compilation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1039"/>
|
||||
<location filename="../src/mainWindow.py" line="1059"/>
|
||||
<source>Icon color</source>
|
||||
<translation>Couleur de l'icone</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1040"/>
|
||||
<location filename="../src/mainWindow.py" line="1060"/>
|
||||
<source>Text color</source>
|
||||
<translation>Couleur du texte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1041"/>
|
||||
<location filename="../src/mainWindow.py" line="1061"/>
|
||||
<source>Background color</source>
|
||||
<translation>Couleur de l'arrière-plan</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1032"/>
|
||||
<location filename="../src/mainWindow.py" line="1052"/>
|
||||
<source>Icon</source>
|
||||
<translation>Icone</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1034"/>
|
||||
<location filename="../src/mainWindow.py" line="1054"/>
|
||||
<source>Background</source>
|
||||
<translation>Arrière-plan</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1035"/>
|
||||
<location filename="../src/mainWindow.py" line="1055"/>
|
||||
<source>Border</source>
|
||||
<translation>Bordure</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="1036"/>
|
||||
<location filename="../src/mainWindow.py" line="1056"/>
|
||||
<source>Corner</source>
|
||||
<translation>Coin</translation>
|
||||
</message>
|
||||
|
@ -554,17 +554,17 @@
|
|||
<translation>Le fichier {} n'existe pas. Essayez encore.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="586"/>
|
||||
<location filename="../src/mainWindow.py" line="607"/>
|
||||
<source>Project {} loaded with some errors:</source>
|
||||
<translation>Le projet {} a été chargé, avec des erreurs:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="588"/>
|
||||
<location filename="../src/mainWindow.py" line="609"/>
|
||||
<source> * {} wasn't found in project file.</source>
|
||||
<translation>* {} n'a pas été trouvé dans le fichier du projet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainWindow.py" line="589"/>
|
||||
<location filename="../src/mainWindow.py" line="610"/>
|
||||
<source>Project {} loaded with some errors.</source>
|
||||
<translation>Le projet {} a été chargé avec des erreurs.</translation>
|
||||
</message>
|
||||
|
@ -1826,27 +1826,27 @@ des lignes:</translation>
|
|||
<translation>Supprimer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="93"/>
|
||||
<location filename="../src/ui/revisions.py" line="98"/>
|
||||
<source>1 day ago</source>
|
||||
<translation>Il y a un jour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="95"/>
|
||||
<location filename="../src/ui/revisions.py" line="100"/>
|
||||
<source>{} days ago</source>
|
||||
<translation>Il y a {} jours</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="97"/>
|
||||
<location filename="../src/ui/revisions.py" line="102"/>
|
||||
<source>{} hours ago</source>
|
||||
<translation>Il y a {} heures</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="99"/>
|
||||
<location filename="../src/ui/revisions.py" line="104"/>
|
||||
<source>{} minutes ago</source>
|
||||
<translation>Il y a {} minutes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="101"/>
|
||||
<location filename="../src/ui/revisions.py" line="106"/>
|
||||
<source>{} seconds ago</source>
|
||||
<translation>Il y a {} secondes</translation>
|
||||
</message>
|
||||
|
@ -1856,25 +1856,30 @@ des lignes:</translation>
|
|||
<translation>Options</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="29"/>
|
||||
<location filename="../src/ui/revisions.py" line="34"/>
|
||||
<source>Show modifications</source>
|
||||
<translation>Montrer les modifications</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="36"/>
|
||||
<location filename="../src/ui/revisions.py" line="41"/>
|
||||
<source>Show ancient version</source>
|
||||
<translation>Montrer la version ancienne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="44"/>
|
||||
<location filename="../src/ui/revisions.py" line="49"/>
|
||||
<source>Show spaces</source>
|
||||
<translation>Montrer les espaces</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="50"/>
|
||||
<location filename="../src/ui/revisions.py" line="55"/>
|
||||
<source>Show modifications only</source>
|
||||
<translation>Montrer les modifications seulement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/ui/revisions.py" line="171"/>
|
||||
<source>Line {}:</source>
|
||||
<translation>Ligne {}:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>settingsWindow</name>
|
||||
|
|
|
@ -457,6 +457,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
if sttgns.contains("searchState"):
|
||||
state = False if sttgns.value("searchState") == "false" else True
|
||||
self.grpSearch.restoreState(state)
|
||||
if sttgns.contains("revisionsState"):
|
||||
state = [False if v == "false" else True for v in sttgns.value("revisionsState")]
|
||||
self.redacMetadata.revisions.restoreState(state)
|
||||
|
||||
|
||||
def closeEvent(self, event):
|
||||
|
@ -469,6 +472,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
sttgns.setValue("redacInfosState", self.tabRedacInfos.currentIndex())
|
||||
sttgns.setValue("cheatSheetState", self.grpCheatSheet.saveState())
|
||||
sttgns.setValue("searchState", self.grpSearch.saveState())
|
||||
sttgns.setValue("revisionsState", self.redacMetadata.revisions.saveState())
|
||||
|
||||
# Specific settings to save before quitting
|
||||
settings.lastTab = self.tabMain.currentIndex()
|
||||
|
|
|
@ -9,6 +9,7 @@ from functions import *
|
|||
import models.references as Ref
|
||||
import datetime
|
||||
import difflib
|
||||
import re
|
||||
|
||||
class revisions(QWidget, Ui_revisions):
|
||||
|
||||
|
@ -21,6 +22,10 @@ class revisions(QWidget, Ui_revisions):
|
|||
self.listDelegate = listCompleterDelegate(self)
|
||||
self.list.setItemDelegate(self.listDelegate)
|
||||
self.list.itemActivated.connect(self.showDiff)
|
||||
self.btnDelete.setEnabled(False)
|
||||
self.btnRestore.clicked.connect(self.restore)
|
||||
self.btnRestore.setEnabled(False)
|
||||
|
||||
#self.list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
|
||||
self.menu = QMenu(self)
|
||||
|
@ -101,12 +106,21 @@ class revisions(QWidget, Ui_revisions):
|
|||
return self.tr("{} seconds ago").format(str(delta.seconds))
|
||||
|
||||
def showDiff(self):
|
||||
#FIXME: doesn't work for HTML formatting.
|
||||
# UI stuff
|
||||
self.actShowSpaces.setEnabled(self.actShowDiff.isChecked())
|
||||
self.actDiffOnly.setEnabled(self.actShowDiff.isChecked())
|
||||
|
||||
#FIXME: Errors in line number
|
||||
i = self.list.currentItem()
|
||||
|
||||
if not i:
|
||||
self.btnDelete.setEnabled(False)
|
||||
self.btnRestore.setEnabled(False)
|
||||
return
|
||||
|
||||
self.btnDelete.setEnabled(True)
|
||||
self.btnRestore.setEnabled(True)
|
||||
|
||||
ts = i.data(Qt.UserRole)
|
||||
item = self._index.internalPointer()
|
||||
|
||||
|
@ -145,25 +159,40 @@ class revisions(QWidget, Ui_revisions):
|
|||
skip = False
|
||||
continue
|
||||
|
||||
# Same line
|
||||
if op == " " and not self.actDiffOnly.isChecked():
|
||||
if item.type() == "t2t":
|
||||
txt = Ref.basicT2TFormat(txt)
|
||||
mydiff += "{}{}".format(txt, extra)
|
||||
|
||||
elif op == "- " and op2 == "+ ":
|
||||
if self.actDiffOnly.isChecked():
|
||||
mydiff += "<br>{}:<br>".format(str(n))
|
||||
mydiff += "<br><span style='color: blue;'>{}</span><br>".format(
|
||||
self.tr("Line {}:").format(str(n)))
|
||||
s = difflib.SequenceMatcher(None, txt, txt2, autojunk=False)
|
||||
newline = ""
|
||||
for tag, i1, i2, j1, j2 in s.get_opcodes():
|
||||
if tag == "equal":
|
||||
mydiff += txt[i1:i2]
|
||||
newline += txt[i1:i2]
|
||||
elif tag == "delete":
|
||||
mydiff += "<span style='color:red;'>{}</span>".format(_format(txt[i1:i2]))
|
||||
newline += "<span style='color:red;'>{}</span>".format(_format(txt[i1:i2]))
|
||||
elif tag == "insert":
|
||||
mydiff += "<span style='color:green;'>{}</span>".format(_format(txt2[j1:j2]))
|
||||
newline += "<span style='color:green;'>{}</span>".format(_format(txt2[j1:j2]))
|
||||
elif tag == "replace":
|
||||
mydiff += "<span style='color:red;'>{}</span>".format(_format(txt[i1:i2]))
|
||||
mydiff += "<span style='color:green;'>{}</span>".format(_format(txt2[j1:j2]))
|
||||
mydiff += extra
|
||||
newline += "<span style='color:red;'>{}</span>".format(_format(txt[i1:i2]))
|
||||
newline += "<span style='color:green;'>{}</span>".format(_format(txt2[j1:j2]))
|
||||
|
||||
# Few ugly tweaks for html diffs
|
||||
newline = re.sub(r"(<span style='color.*?><span.*?>)</span>(.*)<span style='color:.*?>(</span></span>)",
|
||||
"\\1\\2\\3", newline)
|
||||
newline = re.sub(r"<p align=\"<span style='color:red;'>cen</span><span style='color:green;'>righ</span>t<span style='color:red;'>er</span>\" style=\" -qt-block-indent:0; -qt-user-state:0; \">(.*?)</p>",
|
||||
"<p align=\"right\"><span style='color:green;'>\\1</span></p>", newline)
|
||||
newline = re.sub(r"<p align=\"<span style='color:green;'>cente</span>r<span style='color:red;'>ight</span>\" style=\" -qt-block-indent:0; -qt-user-state:0; \">(.*)</p>",
|
||||
"<p align=\"center\"><span style='color:green;'>\\1</span></p>", newline)
|
||||
newline = re.sub(r"<p(<span.*?>)(.*?)(</span>)(.*?)>(.*?)</p>",
|
||||
"<p\\2\\4>\\1\\5\\3</p>", newline)
|
||||
|
||||
mydiff += newline + extra
|
||||
skip = True
|
||||
elif op == "- ":
|
||||
if self.actDiffOnly.isChecked():
|
||||
|
@ -176,6 +205,34 @@ class revisions(QWidget, Ui_revisions):
|
|||
|
||||
self.view.setText(mydiff)
|
||||
|
||||
def restore(self):
|
||||
i = self.list.currentItem()
|
||||
if not i:
|
||||
return
|
||||
ts = i.data(Qt.UserRole)
|
||||
item = self._index.internalPointer()
|
||||
textBefore = [r[1] for r in item.revisions() if r[0] == ts][0]
|
||||
index = self._index.sibling(self._index.row(), Outline.text.value)
|
||||
self._index.model().setData(index, textBefore)
|
||||
#item.setData(Outline.text.value, textBefore)
|
||||
|
||||
|
||||
def saveState(self):
|
||||
return [
|
||||
self.actShowDiff.isChecked(),
|
||||
self.actShowVersion.isChecked(),
|
||||
self.actShowSpaces.isChecked(),
|
||||
self.actDiffOnly.isChecked(),
|
||||
]
|
||||
|
||||
def restoreState(self, state):
|
||||
self.actShowDiff.setChecked(state[0])
|
||||
self.actShowVersion.setChecked(state[1])
|
||||
self.actShowSpaces.setChecked(state[2])
|
||||
self.actDiffOnly.setChecked(state[3])
|
||||
self.actShowSpaces.setEnabled(self.actShowDiff.isChecked())
|
||||
self.actDiffOnly.setEnabled(self.actShowDiff.isChecked())
|
||||
|
||||
|
||||
class listCompleterDelegate(QStyledItemDelegate):
|
||||
def __init__(self, parent=None):
|
||||
|
|
|
@ -57,11 +57,9 @@ class Ui_revisions(object):
|
|||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.btnRestore = QtWidgets.QPushButton(self.layoutWidget)
|
||||
self.btnRestore.setEnabled(False)
|
||||
self.btnRestore.setObjectName("btnRestore")
|
||||
self.horizontalLayout_2.addWidget(self.btnRestore)
|
||||
self.btnDelete = QtWidgets.QPushButton(self.layoutWidget)
|
||||
self.btnDelete.setEnabled(False)
|
||||
self.btnDelete.setObjectName("btnDelete")
|
||||
self.horizontalLayout_2.addWidget(self.btnDelete)
|
||||
self.verticalLayout_2.addWidget(self.splitter)
|
||||
|
|
|
@ -93,9 +93,6 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRestore">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Restore</string>
|
||||
</property>
|
||||
|
@ -103,9 +100,6 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnDelete">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
|
|
|
@ -79,11 +79,11 @@ class metadataView(QWidget, Ui_metadataView):
|
|||
self.grpSummary.saveState(),
|
||||
self.grpNotes.saveState(),
|
||||
self.grpRevisions.saveState(),
|
||||
self.revisions.saveState()
|
||||
]
|
||||
|
||||
def restoreState(self, state):
|
||||
self.grpProperties.restoreState(state[0]),
|
||||
self.grpSummary.restoreState(state[1]),
|
||||
self.grpNotes.restoreState(state[2]),
|
||||
self.grpRevisions.restoreState(state[3]),
|
||||
|
||||
self.grpProperties.restoreState(state[0])
|
||||
self.grpSummary.restoreState(state[1])
|
||||
self.grpNotes.restoreState(state[2])
|
||||
self.grpRevisions.restoreState(state[3])
|
Loading…
Reference in a new issue