Merge pull request #901 from worstje/dot-twelve-assorted

Fixes for a number of reported bugs
This commit is contained in:
Tobias Frisch 2021-07-10 19:57:48 +02:00 committed by GitHub
commit 731e017e9e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 14 deletions

View file

@ -20,6 +20,10 @@ import logging
LOGGER = logging.getLogger(__name__)
def prepare(arguments, tests=False):
# Qt WebEngine demands this attribute be set _before_ we create our QApplication object.
QApplication.setAttribute(Qt.AA_ShareOpenGLContexts, True)
# Create the foundation that provides our Qt application with its event loop.
app = QApplication(sys.argv)
app.setOrganizationName("manuskript" + ("_tests" if tests else ""))
app.setOrganizationDomain("www.theologeek.ch")
@ -160,7 +164,7 @@ def prepare(arguments, tests=False):
QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")])
QIcon.setThemeName("NumixMsk")
# Font siue
# Font size
if settings.contains("appFontSize"):
f = qApp.font()
f.setPointSize(settings.value("appFontSize", type=int))
@ -175,12 +179,12 @@ def prepare(arguments, tests=False):
MW._defaultCursorFlashTime = qApp.cursorFlashTime()
# Command line project
#if len(sys.argv) > 1 and sys.argv[1][-4:] == ".msk":
if arguments.filename is not None and arguments.filename[-4:] == ".msk":
#TODO: integrate better with argparsing.
if os.path.exists(sys.argv[1]):
path = os.path.abspath(sys.argv[1])
MW._autoLoadProject = path
# The file is verified to already exist during argument parsing.
# Our ".msk" check has been moved there too for better feedback,
# but leaving it here to err on the side of caution.
path = os.path.abspath(arguments.filename)
MW._autoLoadProject = path
return app, MW
@ -255,6 +259,15 @@ def setup_signal_handlers(MW):
signal.signal(signal.SIGTERM, sigint_handler("SIGTERM", MW))
def is_valid_project(parser, arg):
if arg[-4:] != ".msk":
parser.error("only manuskript projects (.msk) are supported!")
if not os.path.isfile(arg):
parser.error("the project %s does not exist!" % arg)
else:
return arg
def process_commandline(argv):
import argparse
parser = argparse.ArgumentParser(description="Run the manuskript application.")
@ -262,7 +275,8 @@ def process_commandline(argv):
action="store_true")
parser.add_argument("-v", "--verbose", action="count", default=1, help="lower the threshold for messages logged to the terminal")
parser.add_argument("-L", "--logfile", default=None, help="override the default log file location")
parser.add_argument("filename", nargs="?", metavar="FILENAME", help="the manuskript project (.msk) to open")
parser.add_argument("filename", nargs="?", metavar="FILENAME", help="the manuskript project (.msk) to open",
type=lambda x: is_valid_project(parser, x))
args = parser.parse_args(args=argv)
@ -283,7 +297,7 @@ def run():
2. So that prepare can be used in tests, without running the whole thing
"""
# Parse command-line arguments.
arguments = process_commandline(sys.argv)
arguments = process_commandline(sys.argv[1:])
# Initialize logging. (Does not include Qt integration yet.)
manuskript.logging.setUp(console_level=arguments.verbose)

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
from PyQt5.QtCore import QModelIndex, QSortFilterProxyModel
from manuskript.enums import Character as C
class characterPOVModel(QSortFilterProxyModel):
@ -14,7 +14,11 @@ class characterPOVModel(QSortFilterProxyModel):
sourceModel.dataChanged.connect(self.sourceDataChanged)
def filterAcceptsRow(self, sourceRow, sourceParent):
return self.sourceModel().pov(sourceRow)
# Although I would prefer to reuse the existing characterModel.pov() method,
# this is simpler to do, actually works and also more ideomatic Qt code.
index = self.sourceModel().index(sourceRow, C.pov.value, sourceParent)
value = self.sourceModel().data(index)
return bool(value)
def rowToSource(self, row):
index = self.index(row, 0)

View file

@ -98,7 +98,7 @@ class outlineItem(abstractItem, searchableItem):
)
__repr__ = __str__
def charCount(self):
return self._data.get(self.enum.charCount, 0)
@ -116,6 +116,9 @@ class outlineItem(abstractItem, searchableItem):
return []
else:
# Used to verify nbsp characters not getting clobbered.
#if column == E.text:
# print("GET", str(role), "-->", str([hex(ord(x)) for x in data]))
return data
elif role == Qt.DecorationRole and column == E.title:
@ -158,6 +161,8 @@ class outlineItem(abstractItem, searchableItem):
# Stuff to do before
if column == E.text:
self.addRevision()
# Used to verify nbsp characters not getting clobbered.
#print("SET", str(role), "-->", str([hex(ord(x)) for x in data]))
# Calling base class implementation
abstractItem.setData(self, column, data, role)

View file

@ -500,7 +500,10 @@ class MDEditView(textEditView):
r3.setLeft(self.viewport().geometry().left())
r3.setRight(self.viewport().geometry().right())
refs.append(ClickThing(r3, rx, rx.capturedTexts()))
cursor.movePosition(cursor.Down)
if not cursor.movePosition(cursor.Down):
# Super-rare failure. Leaving log message for future investigation.
LOGGER.debug("Failed to move cursor down while calculating clickables. Aborting.")
break
self.clickRects = refs

View file

@ -20,7 +20,11 @@ from manuskript.models.characterModel import Character, CharacterInfo
import logging
LOGGER = logging.getLogger(__name__)
# See implementation of QTextDocument::toPlainText()
PLAIN_TRANSLATION_TABLE = {0x2028: "\n", 0x2029: "\n", 0xfdd0: "\n", 0xfdd1: "\n"}
class textEditView(QTextEdit):
def __init__(self, parent=None, index=None, html=None, spellcheck=None,
highlighting=False, dict="", autoResize=False):
QTextEdit.__init__(self, parent)
@ -278,13 +282,20 @@ class textEditView(QTextEdit):
def reconnectDocument(self):
self.document().contentsChanged.connect(self.updateTimer.start, F.AUC)
def toIdealText(self):
"""QTextDocument::toPlainText() replaces NBSP with spaces, which we don't want.
QTextDocument::toRawText() replaces nothing, but that leaves fancy paragraph and line separators that users would likely complain about.
This reimplements toPlainText(), except without the NBSP destruction."""
return self.document().toRawText().translate(PLAIN_TRANSLATION_TABLE)
toPlainText = toIdealText
def updateText(self):
self._updating.lock()
# LOGGER.debug("Updating %s", self.objectName())
if self._index:
self.disconnectDocument()
if self.toPlainText() != F.toString(self._index.data()):
if self.toIdealText() != F.toString(self._index.data()):
# LOGGER.debug(" Updating plaintext")
self.document().setPlainText(F.toString(self._index.data()))
self.reconnectDocument()
@ -319,7 +330,7 @@ class textEditView(QTextEdit):
self.updateTimer.stop()
self._updating.lock()
text = self.toPlainText()
text = self.toIdealText()
self._updating.unlock()
# LOGGER.debug("Submitting %s", self.objectName())