From 3aa9cadfd8840e64397a90b2022c92a17aff0c4f Mon Sep 17 00:00:00 2001 From: Jan Wester Date: Sun, 22 Sep 2019 12:28:40 +0200 Subject: [PATCH] Restore progress bar functionality A previous fix (5f9ea3) inadvertently broke the progress bar by converting to the wrong data type. (See issue #561 / PR #609). While checking the code I realized the problem occurred primarily because we weren't checking the validity of the values closer to the source. Doing so alleviates the need to check elsewhere. In the hope of inspiring a more systematic approach, a new uiParse() utility function has been added to curb the further growth of toXxx() functions that exist solely to validate user input. There is no doubt room for improvement, both on the end of the new uiParse() function as well as the spot where it is used. Ideally, the data that comes out of the model should already be 'safe', but since this is a bugfix for a bugfix I want to keep waves to a minimum. This commit fixes issue #652. --- manuskript/functions/__init__.py | 25 +++++++++++++++++++++++-- manuskript/ui/editors/mainEditor.py | 9 +++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/manuskript/functions/__init__.py b/manuskript/functions/__init__.py index 53eb519..8d49192 100644 --- a/manuskript/functions/__init__.py +++ b/manuskript/functions/__init__.py @@ -23,6 +23,27 @@ def wordCount(text): t = [l for l in t if l] return len(t) +validate_ok = lambda *args, **kwargs: True +def uiParse(input, default, converter, validator=validate_ok): + """ + uiParse is a utility function that intends to make it easy to convert + user input to data that falls in the range of expected values the + program is expecting to handle. + + It swallows all exceptions that happen during conversion. + The validator should return True to permit the converted value. + """ + result = default + try: + result = converter(input) + except: + pass # failed to convert + + # Whitelist default value in case default type differs from converter output. + if (result != default) and not validator(result): + result = default + return result + def toInt(text): if text: @@ -50,6 +71,7 @@ def toString(text): def drawProgress(painter, rect, progress, radius=0): from manuskript.ui import style as S + progress = toFloat(progress) # handle invalid input (issue #561) painter.setPen(Qt.NoPen) painter.setBrush(QColor(S.base)) # "#dddddd" painter.drawRoundedRect(rect, radius, radius) @@ -57,8 +79,7 @@ def drawProgress(painter, rect, progress, radius=0): painter.setBrush(QBrush(colorFromProgress(progress))) r2 = QRect(rect) - r2.setWidth(r2.width() * min(toInt(progress), 1)) - # ^^^^^ Avoid crash - issue #561 + r2.setWidth(r2.width() * min(progress, 1)) painter.drawRoundedRect(r2, radius, radius) diff --git a/manuskript/ui/editors/mainEditor.py b/manuskript/ui/editors/mainEditor.py index 26ac637..967f283 100644 --- a/manuskript/ui/editors/mainEditor.py +++ b/manuskript/ui/editors/mainEditor.py @@ -9,7 +9,7 @@ from PyQt5.QtWidgets import QWidget, qApp from manuskript import settings from manuskript.enums import Outline -from manuskript.functions import AUC, mainWindow, drawProgress, appPath, toInt +from manuskript.functions import AUC, mainWindow, drawProgress, appPath, uiParse from manuskript.ui import style from manuskript.ui.editors.editorWidget import editorWidget from manuskript.ui.editors.fullScreenEditor import fullScreenEditor @@ -303,7 +303,9 @@ class mainEditor(QWidget, Ui_mainEditor): wc = item.data(Outline.wordCount) goal = item.data(Outline.goal) progress = item.data(Outline.goalPercentage) - # mw = qApp.activeWindow() + + goal = uiParse(goal, None, int, lambda x: x>=0) + progress = uiParse(progress, 0.0, float) if not wc: wc = 0 @@ -319,8 +321,7 @@ class mainEditor(QWidget, Ui_mainEditor): self.lblRedacProgress.setPixmap(self.px) self.lblRedacWC.setText(self.tr("{} words / {} ").format( locale.format_string("%d", wc, grouping=True), - locale.format_string("%d", toInt(goal), grouping=True))) - # ^^^^^ Avoid crash - issue #561 + locale.format_string("%d", goal, grouping=True))) else: self.lblRedacProgress.hide() self.lblRedacWC.setText(self.tr("{} words ").format(