Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for a number of reported bugs #901

Merged
merged 5 commits into from
Jul 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 22 additions & 8 deletions manuskript/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
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")
Expand Down Expand Up @@ -160,7 +164,7 @@ def respectSystemDarkThemeSetting():
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))
Expand All @@ -175,12 +179,12 @@ def respectSystemDarkThemeSetting():
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

Expand Down Expand Up @@ -255,14 +259,24 @@ 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.")
parser.add_argument("--console", help="open the IPython Jupyter QT Console as a debugging aid",
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)

Expand All @@ -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)

Expand Down
8 changes: 6 additions & 2 deletions manuskript/models/characterPOVModel.py
Original file line number Diff line number Diff line change
@@ -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):

Expand All @@ -14,7 +14,11 @@ def __init__(self, sourceModel, parent=None):
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)
Expand Down
7 changes: 6 additions & 1 deletion manuskript/models/outlineItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def __str__(self):
)

__repr__ = __str__

def charCount(self):
return self._data.get(self.enum.charCount, 0)

Expand All @@ -116,6 +116,9 @@ def data(self, column, role=Qt.DisplayRole):
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:
Expand Down Expand Up @@ -158,6 +161,8 @@ def setData(self, column, data, role=Qt.DisplayRole):
# 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)
Expand Down
5 changes: 4 additions & 1 deletion manuskript/ui/views/MDEditView.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,10 @@ def getClickRects(self):
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

Expand Down
15 changes: 13 additions & 2 deletions manuskript/ui/views/textEditView.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
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)
Expand Down Expand Up @@ -278,13 +282,20 @@ def disconnectDocument(self):
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()
Expand Down Expand Up @@ -319,7 +330,7 @@ def submit(self):
self.updateTimer.stop()

self._updating.lock()
text = self.toPlainText()
text = self.toIdealText()
self._updating.unlock()

# LOGGER.debug("Submitting %s", self.objectName())
Expand Down