mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-06-13 16:34:34 +12:00
Checkpoint: revisions
This commit is contained in:
parent
a0fac27e07
commit
584b0b04a6
|
@ -14,8 +14,7 @@ from manuskript.version import getVersion
|
||||||
|
|
||||||
faulthandler.enable()
|
faulthandler.enable()
|
||||||
|
|
||||||
|
def prepare():
|
||||||
def run():
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setOrganizationName("manuskript")
|
app.setOrganizationName("manuskript")
|
||||||
app.setOrganizationDomain("www.theologeek.ch")
|
app.setOrganizationDomain("www.theologeek.ch")
|
||||||
|
@ -57,25 +56,38 @@ def run():
|
||||||
|
|
||||||
QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")])
|
QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")])
|
||||||
QIcon.setThemeName("NumixMsk")
|
QIcon.setThemeName("NumixMsk")
|
||||||
# qApp.setWindowIcon(QIcon.fromTheme("im-aim"))
|
|
||||||
|
|
||||||
# Seperating launch to avoid segfault, so it seem.
|
# Main window
|
||||||
# Cf. http://stackoverflow.com/questions/12433491/is-this-pyqt-4-python-bug-or-wrongly-behaving-code
|
|
||||||
launch()
|
|
||||||
|
|
||||||
|
|
||||||
def launch():
|
|
||||||
from manuskript.mainWindow import MainWindow
|
from manuskript.mainWindow import MainWindow
|
||||||
|
|
||||||
main = MainWindow()
|
MW = MainWindow()
|
||||||
# We store the system default cursor flash time to be able to restore it
|
# We store the system default cursor flash time to be able to restore it
|
||||||
# later if necessary
|
# later if necessary
|
||||||
main._defaultCursorFlashTime = qApp.cursorFlashTime()
|
MW._defaultCursorFlashTime = qApp.cursorFlashTime()
|
||||||
main.show()
|
|
||||||
|
return app, MW
|
||||||
|
|
||||||
|
def launch(MW = None):
|
||||||
|
if MW is None:
|
||||||
|
from manuskript.functions import mainWindow
|
||||||
|
MW = mainWindow()
|
||||||
|
|
||||||
|
MW.show()
|
||||||
|
|
||||||
qApp.exec_()
|
qApp.exec_()
|
||||||
qApp.deleteLater()
|
qApp.deleteLater()
|
||||||
|
|
||||||
|
def run():
|
||||||
|
"""
|
||||||
|
Run separates prepare and launch for two reasons:
|
||||||
|
1. I've read somewhere it helps with potential segfault (see comment below)
|
||||||
|
2. So that prepare can be used in tests, without running the whole thing
|
||||||
|
"""
|
||||||
|
# Need to return and keep `app` otherwise it gets deleted.
|
||||||
|
app, MW = prepare()
|
||||||
|
# Seperating launch to avoid segfault, so it seem.
|
||||||
|
# Cf. http://stackoverflow.com/questions/12433491/is-this-pyqt-4-python-bug-or-wrongly-behaving-code
|
||||||
|
launch(MW)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
run()
|
||||||
|
|
|
@ -1416,4 +1416,3 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
r = self.dialog.geometry()
|
r = self.dialog.geometry()
|
||||||
r2 = self.geometry()
|
r2 = self.geometry()
|
||||||
self.dialog.move(r2.center() - r.center())
|
self.dialog.move(r2.center() - r.center())
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,10 @@ import pytest
|
||||||
|
|
||||||
# We need a qApplication to be running, or all the calls to qApp
|
# We need a qApplication to be running, or all the calls to qApp
|
||||||
# will throw a seg fault.
|
# will throw a seg fault.
|
||||||
from PyQt5.QtWidgets import QApplication
|
# from PyQt5.QtWidgets import QApplication
|
||||||
app = QApplication([])
|
# app = QApplication([])
|
||||||
|
# app.setOrganizationName("manuskript_tests")
|
||||||
|
# app.setApplicationName("manuskript_tests")
|
||||||
|
|
||||||
|
from manuskript import main
|
||||||
|
app, MW = main.prepare()
|
||||||
|
|
|
@ -5,17 +5,32 @@
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.fixture(scope='session', autouse=True)
|
# @pytest.fixture(scope='session', autouse=True)
|
||||||
def MW():
|
# def MW():
|
||||||
"""
|
# """
|
||||||
Creates a mainWindow that can be used for the tests
|
# Creates a mainWindow that can be used for the tests
|
||||||
Either with functions.mainWindow or by passing argument
|
# Either with functions.mainWindow or by passing argument
|
||||||
MW to the test
|
# MW to the test
|
||||||
"""
|
# """
|
||||||
from manuskript.mainWindow import MainWindow
|
# from manuskript.mainWindow import MainWindow
|
||||||
mw = MainWindow()
|
# mw = MainWindow()
|
||||||
|
#
|
||||||
|
# yield
|
||||||
|
#
|
||||||
|
# # Properly destructed after. Otherwise: seg fault.
|
||||||
|
# mw.deleteLater()
|
||||||
|
|
||||||
yield
|
@pytest.fixture
|
||||||
|
def MWEmptyProject():
|
||||||
|
"""
|
||||||
|
Sets the mainWindow to load an empty project.
|
||||||
|
"""
|
||||||
|
from manuskript.functions import mainWindow
|
||||||
|
MW = mainWindow()
|
||||||
|
|
||||||
# Properly destructed after. Otherwise: seg fault.
|
import tempfile
|
||||||
mw.deleteLater()
|
tf = tempfile.NamedTemporaryFile(suffix=".msk")
|
||||||
|
MW.welcome.createFile(tf.name, overwrite=True)
|
||||||
|
assert MW.currentProject is not None
|
||||||
|
|
||||||
|
return MW
|
||||||
|
|
|
@ -7,13 +7,13 @@ import pytest
|
||||||
from manuskript.models import outlineModel, outlineItem
|
from manuskript.models import outlineModel, outlineItem
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def outlineModelBasic():
|
def outlineModelBasic(MWEmptyProject):
|
||||||
"""Returns an outlineModel with a few items:
|
"""Returns an outlineModel with a few items:
|
||||||
* Folder
|
* Folder
|
||||||
* Text
|
* Text
|
||||||
* Text
|
* Text
|
||||||
"""
|
"""
|
||||||
mdl = outlineModel(parent=None)
|
mdl = MWEmptyProject.mdlOutline
|
||||||
|
|
||||||
root = mdl.rootItem
|
root = mdl.rootItem
|
||||||
f = outlineItem(title="Folder", parent=root)
|
f = outlineItem(title="Folder", parent=root)
|
||||||
|
|
|
@ -18,53 +18,79 @@ def outlineItemText():
|
||||||
return outlineItem(title="Text", _type="md")
|
return outlineItem(title="Text", _type="md")
|
||||||
|
|
||||||
def test_outlineItemsProperties(outlineItemFolder, outlineItemText):
|
def test_outlineItemsProperties(outlineItemFolder, outlineItemText):
|
||||||
|
"""
|
||||||
|
Tests with simple items, without parent or models.
|
||||||
|
"""
|
||||||
|
|
||||||
# Simplification
|
# Simplification
|
||||||
folder = outlineItemFolder
|
folder = outlineItemFolder
|
||||||
text = outlineItemText
|
text = outlineItemText
|
||||||
|
|
||||||
# Basic tests
|
# getters
|
||||||
assert folder.isFolder() == True
|
assert folder.isFolder() == True
|
||||||
assert text.isFolder() == False
|
assert text.isFolder() == False
|
||||||
assert text.isText() == True
|
assert text.isText() == True
|
||||||
assert text.isMD() == text.isMMD() == True
|
assert text.isMD() == text.isMMD() == True
|
||||||
|
|
||||||
assert text.title() == "Text"
|
assert text.title() == "Text"
|
||||||
assert text.compile() == True
|
assert text.compile() == True
|
||||||
text.setData(text.enum.compile, 0)
|
|
||||||
assert text.compile() == False
|
|
||||||
assert folder.POV() == ""
|
assert folder.POV() == ""
|
||||||
assert folder.status() == ""
|
assert folder.status() == ""
|
||||||
assert folder.POV() == ""
|
assert folder.label() == ""
|
||||||
assert folder.customIcon() == ""
|
assert folder.customIcon() == ""
|
||||||
|
|
||||||
|
# setData and other setters
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
assert text.data(text.enum.compile, role=Qt.CheckStateRole) == Qt.Checked
|
||||||
|
text.setData(text.enum.compile, 0)
|
||||||
|
assert text.compile() == False
|
||||||
|
assert text.data(text.enum.compile, role=Qt.CheckStateRole) == Qt.Unchecked
|
||||||
folder.setCustomIcon("custom")
|
folder.setCustomIcon("custom")
|
||||||
assert folder.customIcon() == "custom"
|
assert folder.customIcon() == "custom"
|
||||||
|
folder.setData(folder.enum.text, "Some text")
|
||||||
|
assert folder.text() == "" # folders have no text
|
||||||
|
|
||||||
|
# wordCount
|
||||||
text.setData(text.enum.text, "Sample **text**.")
|
text.setData(text.enum.text, "Sample **text**.")
|
||||||
assert text.wordCount() == 2
|
assert text.wordCount() == 2
|
||||||
assert text.data(text.enum.revisions) == []
|
text.setData(text.enum.goal, 4)
|
||||||
text.setData(text.enum.setGoal, 4)
|
|
||||||
assert text.data(text.enum.goalPercentage) == .5
|
assert text.data(text.enum.goalPercentage) == .5
|
||||||
|
|
||||||
|
# revisions
|
||||||
|
assert text.data(text.enum.revisions) == []
|
||||||
|
|
||||||
def test_modelStuff(outlineModelBasic):
|
def test_modelStuff(outlineModelBasic):
|
||||||
|
"""
|
||||||
|
Tests with children items.
|
||||||
|
"""
|
||||||
|
|
||||||
# Simplification
|
# Simplification
|
||||||
model = outlineModelBasic
|
model = outlineModelBasic
|
||||||
|
|
||||||
|
# Child count
|
||||||
root = model.rootItem
|
root = model.rootItem
|
||||||
assert len(root.children()) == 2
|
assert len(root.children()) == 2
|
||||||
folder = root.child(0)
|
folder = root.child(0)
|
||||||
text1 = folder.child(0)
|
text1 = folder.child(0)
|
||||||
text2 = root.child(1)
|
text2 = root.child(1)
|
||||||
|
|
||||||
|
# Compile
|
||||||
assert text1.compile() == True
|
assert text1.compile() == True
|
||||||
folder.setData(folder.enum.compile, 0)
|
folder.setData(folder.enum.compile, 0)
|
||||||
assert text1.compile() == False
|
assert text1.compile() == False
|
||||||
|
|
||||||
|
# Word count
|
||||||
text1.setData(text1.enum.text, "Sample text.")
|
text1.setData(text1.enum.text, "Sample text.")
|
||||||
assert text1.wordCount() == 2
|
assert text1.wordCount() == 2
|
||||||
assert folder.wordCount() == 2
|
assert folder.wordCount() == 2
|
||||||
assert folder.stats() != ""
|
statsWithGoal = folder.stats()
|
||||||
|
assert statsWithGoal != ""
|
||||||
|
text1.setData(text1.enum.setGoal, 4)
|
||||||
|
assert folder.data(folder.enum.goal) == 4
|
||||||
|
folder.setData(folder.enum.setGoal, 3)
|
||||||
|
assert folder.data(folder.enum.goal) == 3
|
||||||
|
assert folder.stats() != statsWithGoal
|
||||||
|
|
||||||
|
# Split and merge
|
||||||
text1.setData(text1.enum.text, "Sample\n---\ntext.")
|
text1.setData(text1.enum.text, "Sample\n---\ntext.")
|
||||||
folder.split("invalid mark")
|
folder.split("invalid mark")
|
||||||
assert folder.childCount() == 1
|
assert folder.childCount() == 1
|
||||||
|
@ -75,6 +101,40 @@ def test_modelStuff(outlineModelBasic):
|
||||||
text1.setData(text1.enum.text, "Sample\nNewTitle\ntext.")
|
text1.setData(text1.enum.text, "Sample\nNewTitle\ntext.")
|
||||||
text1.splitAt(7, 8)
|
text1.splitAt(7, 8)
|
||||||
assert folder.child(1).title() == "NewTitle"
|
assert folder.child(1).title() == "NewTitle"
|
||||||
|
folder.child(1).splitAt(3)
|
||||||
|
assert folder.child(2).title() == "NewTitle_2"
|
||||||
|
folder.removeChild(2)
|
||||||
folder.removeChild(1)
|
folder.removeChild(1)
|
||||||
folder.removeChild(0)
|
folder.removeChild(0)
|
||||||
assert folder.childCount() == 0
|
assert folder.childCount() == 0
|
||||||
|
|
||||||
|
# Search
|
||||||
|
folder.appendChild(text2)
|
||||||
|
text2.setData(text2.enum.POV, 1)
|
||||||
|
folder.setData(folder.enum.POV, 1)
|
||||||
|
assert len(folder.findItemsByPOV(1)) == 2
|
||||||
|
folder.setData(folder.enum.label, 1) # Idea
|
||||||
|
folder.setData(folder.enum.status, 4) # Final
|
||||||
|
text2.setData(text2.enum.text, "Some final value.")
|
||||||
|
from manuskript.functions import MW
|
||||||
|
cols = [folder.enum.text, folder.enum.POV,
|
||||||
|
folder.enum.label, folder.enum.status]
|
||||||
|
assert folder.findItemsContaining("VALUE", cols, MW, True) == []
|
||||||
|
assert folder.findItemsContaining("VALUE", cols, MW, False) == [text2.ID()]
|
||||||
|
|
||||||
|
# Revisions
|
||||||
|
# from manuskript import settings
|
||||||
|
# settings.revisions["smartremove"] = False
|
||||||
|
# text2.setData(text2.enum.text, "Some value.")
|
||||||
|
# assert text2.revisions() == 1
|
||||||
|
# text2.clearAllRevisions()
|
||||||
|
# assert text2.revisions() == []
|
||||||
|
# text2.setData(text2.enum.text, "Some value.")
|
||||||
|
# assert len(text2.revisions()) == 1
|
||||||
|
# text2.setData(text2.enum.text, "Some new value.")
|
||||||
|
# assert len(text2.revisions()) == 1 # Auto clean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#TODO: copy (with children), IDs check, childcountrecursive
|
||||||
|
# (cf. abstractItem)
|
||||||
|
|
|
@ -152,18 +152,20 @@ class welcome(QWidget, Ui_welcome):
|
||||||
pName=pName[:-4]
|
pName=pName[:-4]
|
||||||
self.mw.setWindowTitle(pName + " - " + self.tr("Manuskript"))
|
self.mw.setWindowTitle(pName + " - " + self.tr("Manuskript"))
|
||||||
|
|
||||||
def createFile(self):
|
def createFile(self, filename=None, overwrite=False):
|
||||||
"""When starting a new project, ask for a place to save it.
|
"""When starting a new project, ask for a place to save it.
|
||||||
Datas are not loaded from file, so they must be populated another way."""
|
Datas are not loaded from file, so they must be populated another way."""
|
||||||
filename = QFileDialog.getSaveFileName(self,
|
if filename is None:
|
||||||
self.tr("Create New Project"),
|
filename = QFileDialog.getSaveFileName(
|
||||||
".",
|
self,
|
||||||
self.tr("Manuskript project (*.msk)"))[0]
|
self.tr("Create New Project"),
|
||||||
|
".",
|
||||||
|
self.tr("Manuskript project (*.msk)"))[0]
|
||||||
|
|
||||||
if filename:
|
if filename:
|
||||||
if filename[-4:] != ".msk":
|
if filename[-4:] != ".msk":
|
||||||
filename += ".msk"
|
filename += ".msk"
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename) and not overwrite:
|
||||||
# Check if okay to overwrite existing project
|
# Check if okay to overwrite existing project
|
||||||
result = QMessageBox.warning(self, self.tr("Warning"),
|
result = QMessageBox.warning(self, self.tr("Warning"),
|
||||||
self.tr("Overwrite existing project {} ?").format(filename),
|
self.tr("Overwrite existing project {} ?").format(filename),
|
||||||
|
|
Loading…
Reference in a new issue