From 4f2d57e86ffd028b1614796af4d8af188211edb7 Mon Sep 17 00:00:00 2001 From: nephlm Date: Tue, 22 Jan 2019 00:37:22 -0500 Subject: [PATCH] Issue 459 - session progress/goal window --- manuskript/mainWindow.py | 21 ++++ manuskript/ui/mainWindow.py | 23 +++- manuskript/ui/mainWindow.ui | 18 ++- manuskript/ui/tools/targets.py | 66 ++++++++++ manuskript/ui/tools/targets_ui.py | 149 ++++++++++++++++++++++ manuskript/ui/tools/targets_ui.ui | 201 ++++++++++++++++++++++++++++++ 6 files changed, 472 insertions(+), 6 deletions(-) create mode 100644 manuskript/ui/tools/targets.py create mode 100644 manuskript/ui/tools/targets_ui.py create mode 100644 manuskript/ui/tools/targets_ui.ui diff --git a/manuskript/mainWindow.py b/manuskript/mainWindow.py index 87bce2c7..8dae33d9 100644 --- a/manuskript/mainWindow.py +++ b/manuskript/mainWindow.py @@ -27,6 +27,7 @@ from manuskript.ui.exporters.exporter import exporterDialog from manuskript.ui.helpLabel import helpLabel from manuskript.ui.mainWindow import Ui_MainWindow from manuskript.ui.tools.frequencyAnalyzer import frequencyAnalyzer +from manuskript.ui.tools.targets import targetsDialog from manuskript.ui.views.outlineDelegates import outlineCharacterDelegate from manuskript.ui.views.plotDelegate import plotDelegate from manuskript.ui.views.MDEditView import MDEditView @@ -67,6 +68,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self._defaultCursorFlashTime = 1000 # Overriden at startup with system # value. In manuskript.main. self._autoLoadProject = None # Used to load a command line project + self.sessionStartWordCount = 0 # Used to track session targets self.readSettings() @@ -177,10 +179,15 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Main Menu:: Tool self.actToolFrequency.triggered.connect(self.frequencyAnalyzer) + self.actToolTargets.triggered.connect(self.sessionTargets) self.actAbout.triggered.connect(self.about) self.makeUIConnections() + # Tools non-modal windows + self.td = None # Targets Dialog + self.fw = None # Frequency Window + # self.loadProject(os.path.join(appPath(), "test_project.zip")) def updateDockVisibility(self, restore=False): @@ -635,6 +642,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.currentProject = project QSettings().setValue("lastProject", project) + item = self.mdlOutline.rootItem + wc = item.data(Outline.wordCount) + self.sessionStartWordCount = wc + # Show main Window self.switchToProject() @@ -747,6 +758,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): # closeEvent # QMainWindow.closeEvent(self, event) # Causing segfaults? + # Close non-modal windows if they are open. + if self.td: + self.td.close() + if self.fw: + self.fw.close() + def startTimerNoChanges(self): if settings.autoSaveNoChanges: self.saveTimerNoChanges.start() @@ -1341,6 +1358,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.fw = frequencyAnalyzer(self) self.fw.show() + def sessionTargets(self): + self.td = targetsDialog(self) + self.td.show() + ############################################################################### # VIEW MENU ############################################################################### diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index e307d04a..d369527f 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'manuskript/ui/mainWindow.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt5 UI code generator 5.11.3 # # WARNING! All changes made in this file will be lost! @@ -378,7 +378,7 @@ class Ui_MainWindow(object): self.scrollAreaPersoInfos.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.scrollAreaPersoInfos.setObjectName("scrollAreaPersoInfos") self.scrollAreaPersoInfosWidget = QtWidgets.QWidget() - self.scrollAreaPersoInfosWidget.setGeometry(QtCore.QRect(0, 0, 204, 606)) + self.scrollAreaPersoInfosWidget.setGeometry(QtCore.QRect(0, 0, 252, 664)) self.scrollAreaPersoInfosWidget.setObjectName("scrollAreaPersoInfosWidget") self.formLayout_8 = QtWidgets.QFormLayout(self.scrollAreaPersoInfosWidget) self.formLayout_8.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) @@ -833,6 +833,7 @@ class Ui_MainWindow(object): self.layoutWidget = QtWidgets.QWidget(self.splitterOutlineH) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout_14 = QtWidgets.QVBoxLayout(self.layoutWidget) + self.verticalLayout_14.setContentsMargins(0, 0, 0, 0) self.verticalLayout_14.setObjectName("verticalLayout_14") self.splitterOutlineV = QtWidgets.QSplitter(self.layoutWidget) self.splitterOutlineV.setOrientation(QtCore.Qt.Vertical) @@ -1029,7 +1030,7 @@ class Ui_MainWindow(object): self.horizontalLayout_2.addWidget(self.stack) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1112, 30)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1112, 25)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") @@ -1270,6 +1271,8 @@ class Ui_MainWindow(object): self.actFormatList.setObjectName("actFormatList") self.actFormatBlockquote = QtWidgets.QAction(MainWindow) self.actFormatBlockquote.setObjectName("actFormatBlockquote") + self.actToolTargets = QtWidgets.QAction(MainWindow) + self.actToolTargets.setObjectName("actToolTargets") self.menuFile.addAction(self.actOpen) self.menuFile.addAction(self.menuRecents.menuAction()) self.menuFile.addAction(self.actSave) @@ -1284,6 +1287,7 @@ class Ui_MainWindow(object): self.menuHelp.addAction(self.actAbout) self.menuTools.addAction(self.actSpellcheck) self.menuTools.addAction(self.actToolFrequency) + self.menuTools.addAction(self.actToolTargets) self.mnuHeader.addAction(self.actHeaderSetextL1) self.mnuHeader.addAction(self.actHeaderSetextL2) self.mnuHeader.addSeparator() @@ -1539,6 +1543,9 @@ class Ui_MainWindow(object): self.actFormatOrderedList.setText(_translate("MainWindow", "&Ordered list")) self.actFormatList.setText(_translate("MainWindow", "&Unordered list")) self.actFormatBlockquote.setText(_translate("MainWindow", "B&lockquote")) + self.actToolTargets.setText(_translate("MainWindow", "&Targets")) + self.actToolTargets.setToolTip(_translate("MainWindow", "Draft and session word count targets")) + self.actToolTargets.setShortcut(_translate("MainWindow", "Ctrl+,")) from manuskript.ui.cheatSheet import cheatSheet from manuskript.ui.editors.mainEditor import mainEditor @@ -1554,3 +1561,13 @@ from manuskript.ui.views.sldImportance import sldImportance from manuskript.ui.views.storylineView import storylineView from manuskript.ui.views.treeView import treeView from manuskript.ui.welcome import welcome + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + MainWindow = QtWidgets.QMainWindow() + ui = Ui_MainWindow() + ui.setupUi(MainWindow) + MainWindow.show() + sys.exit(app.exec_()) + diff --git a/manuskript/ui/mainWindow.ui b/manuskript/ui/mainWindow.ui index 7beaa527..d0a07d6c 100644 --- a/manuskript/ui/mainWindow.ui +++ b/manuskript/ui/mainWindow.ui @@ -815,8 +815,8 @@ 0 0 - 204 - 606 + 252 + 664 @@ -2095,7 +2095,7 @@ 0 0 1112 - 30 + 25 @@ -2135,6 +2135,7 @@ + @@ -2818,6 +2819,17 @@ B&lockquote + + + &Targets + + + Draft and session word count targets + + + Ctrl+, + + diff --git a/manuskript/ui/tools/targets.py b/manuskript/ui/tools/targets.py new file mode 100644 index 00000000..b5eca994 --- /dev/null +++ b/manuskript/ui/tools/targets.py @@ -0,0 +1,66 @@ +import locale + +from PyQt5.QtGui import QIcon, QPixmap +from PyQt5.QtWidgets import QWidget +from PyQt5.QtCore import QTimer + +from manuskript.enums import Outline +from manuskript.functions import appPath +from manuskript.ui.tools.targets_ui import Ui_targets + +class targetsDialog(QWidget, Ui_targets): + def __init__(self, parent=None, mw=None): + QWidget.__init__(self) + self.mw = parent + self.setupUi(self) + iconPic = appPath("icons/Manuskript/icon-64px.png") + self.setWindowIcon(QIcon(iconPic)) + + self.session_reset.clicked.connect(self.resetSession) + #self.mw.onClose.connect(self.parentClosed) + + self.tick() + + self.timer = QTimer() + self.timer.timeout.connect(self.tick) + self.timer.start(2000) + + def getDraftStats(self): + item = self.mw.mdlOutline.rootItem + wc = item.data(Outline.wordCount) + goal = item.data(Outline.goal) + progress = item.data(Outline.goalPercentage) + return (wc, goal, progress) + + def resetSession(self): + wc, _, _ = self.getDraftStats() + self.mw.sessionStartWordCount = wc + print('reset session') + self.tick() + + @staticmethod + def progress_bar_value(value): + return min(max(float(value) * 100, 0), 100) + + def tick(self): + wc, goal, progress = self.getDraftStats() + print(wc, goal, progress) + + self.draft_wc_label.setText(locale.format("%d", wc, grouping=True)) + self.draft_goal_label.setText(locale.format("%d", goal, grouping=True)) + # limit to 0-100 for display + self.draft_progress_bar.setValue(self.progress_bar_value(progress)) + + session_wc = wc - self.mw.sessionStartWordCount + self.session_wc_label.setText(locale.format("%d", session_wc, grouping=True)) + if self.session_target.value() == 0: + self.session_progress_bar.setValue(0) + else: + self.session_progress_bar.setValue(self.progress_bar_value(session_wc / self.session_target.value())) + print(self.mw.sessionStartWordCount, session_wc, self.session_progress_bar.value()) + + def closeEvent(self, event): + self.timer = None + + def parentClosed(self): + print('App closed') \ No newline at end of file diff --git a/manuskript/ui/tools/targets_ui.py b/manuskript/ui/tools/targets_ui.py new file mode 100644 index 00000000..b280b5fd --- /dev/null +++ b/manuskript/ui/tools/targets_ui.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'manuskript/ui/tools/targets_ui.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_targets(object): + def setupUi(self, targets): + targets.setObjectName("targets") + targets.resize(322, 216) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../../../../../../../../../../home/icons/Manuskript/icon-64px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + targets.setWindowIcon(icon) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(targets) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(targets) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.line = QtWidgets.QFrame(targets) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.line.sizePolicy().hasHeightForWidth()) + self.line.setSizePolicy(sizePolicy) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.horizontalLayout.addWidget(self.line) + self.verticalLayout.addLayout(self.horizontalLayout) + self.verticalLayout_2.addLayout(self.verticalLayout) + self.draft_progress_bar = QtWidgets.QProgressBar(targets) + self.draft_progress_bar.setProperty("value", 0) + self.draft_progress_bar.setObjectName("draft_progress_bar") + self.verticalLayout_2.addWidget(self.draft_progress_bar) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.draft_wc_label = QtWidgets.QLabel(targets) + self.draft_wc_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.draft_wc_label.setObjectName("draft_wc_label") + self.horizontalLayout_4.addWidget(self.draft_wc_label) + self.draft_of_label = QtWidgets.QLabel(targets) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.draft_of_label.sizePolicy().hasHeightForWidth()) + self.draft_of_label.setSizePolicy(sizePolicy) + self.draft_of_label.setObjectName("draft_of_label") + self.horizontalLayout_4.addWidget(self.draft_of_label) + self.draft_goal_label = QtWidgets.QLabel(targets) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.draft_goal_label.sizePolicy().hasHeightForWidth()) + self.draft_goal_label.setSizePolicy(sizePolicy) + self.draft_goal_label.setObjectName("draft_goal_label") + self.horizontalLayout_4.addWidget(self.draft_goal_label) + self.label_8 = QtWidgets.QLabel(targets) + self.label_8.setObjectName("label_8") + self.horizontalLayout_4.addWidget(self.label_8) + self.verticalLayout_2.addLayout(self.horizontalLayout_4) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_2 = QtWidgets.QLabel(targets) + self.label_2.setObjectName("label_2") + self.horizontalLayout_2.addWidget(self.label_2) + self.line_2 = QtWidgets.QFrame(targets) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.line_2.sizePolicy().hasHeightForWidth()) + self.line_2.setSizePolicy(sizePolicy) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.horizontalLayout_2.addWidget(self.line_2) + self.session_reset = QtWidgets.QPushButton(targets) + self.session_reset.setObjectName("session_reset") + self.horizontalLayout_2.addWidget(self.session_reset) + self.verticalLayout_2.addLayout(self.horizontalLayout_2) + self.session_progress_bar = QtWidgets.QProgressBar(targets) + self.session_progress_bar.setProperty("value", 0) + self.session_progress_bar.setObjectName("session_progress_bar") + self.verticalLayout_2.addWidget(self.session_progress_bar) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.session_wc_label = QtWidgets.QLabel(targets) + self.session_wc_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.session_wc_label.setObjectName("session_wc_label") + self.horizontalLayout_3.addWidget(self.session_wc_label) + self.label_3 = QtWidgets.QLabel(targets) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + self.label_3.setObjectName("label_3") + self.horizontalLayout_3.addWidget(self.label_3) + self.session_target = QtWidgets.QDoubleSpinBox(targets) + self.session_target.setDecimals(0) + self.session_target.setMaximum(99999999999999.0) + self.session_target.setSingleStep(50.0) + self.session_target.setProperty("value", 500.0) + self.session_target.setObjectName("session_target") + self.horizontalLayout_3.addWidget(self.session_target) + self.label_5 = QtWidgets.QLabel(targets) + self.label_5.setObjectName("label_5") + self.horizontalLayout_3.addWidget(self.label_5) + self.verticalLayout_2.addLayout(self.horizontalLayout_3) + + self.retranslateUi(targets) + QtCore.QMetaObject.connectSlotsByName(targets) + + def retranslateUi(self, targets): + _translate = QtCore.QCoreApplication.translate + targets.setWindowTitle(_translate("targets", "Project Targets")) + self.label.setText(_translate("targets", "Draft Target")) + self.draft_wc_label.setText(_translate("targets", "0")) + self.draft_of_label.setText(_translate("targets", "of")) + self.draft_goal_label.setText(_translate("targets", "10,000")) + self.label_8.setText(_translate("targets", "Words")) + self.label_2.setText(_translate("targets", "Session Target")) + self.session_reset.setText(_translate("targets", "Reset")) + self.session_wc_label.setText(_translate("targets", "0")) + self.label_3.setText(_translate("targets", "of")) + self.label_5.setText(_translate("targets", "words")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + targets = QtWidgets.QWidget() + ui = Ui_targets() + ui.setupUi(targets) + targets.show() + sys.exit(app.exec_()) + diff --git a/manuskript/ui/tools/targets_ui.ui b/manuskript/ui/tools/targets_ui.ui new file mode 100644 index 00000000..18ccc49f --- /dev/null +++ b/manuskript/ui/tools/targets_ui.ui @@ -0,0 +1,201 @@ + + + targets + + + + 0 + 0 + 322 + 216 + + + + Project Targets + + + + ../../../../../../../../../../home/icons/Manuskript/icon-64px.png../../../../../../../../../../home/icons/Manuskript/icon-64px.png + + + + + + + + + + + 0 + 0 + + + + Draft Target + + + + + + + + 1 + 0 + + + + Qt::Horizontal + + + + + + + + + + + 0 + + + + + + + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + of + + + + + + + + 0 + 0 + + + + 10,000 + + + + + + + Words + + + + + + + + + + + Session Target + + + + + + + + 1 + 0 + + + + Qt::Horizontal + + + + + + + Reset + + + + + + + + + 0 + + + + + + + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + of + + + + + + + 0 + + + 99999999999999.000000000000000 + + + 50.000000000000000 + + + 500.000000000000000 + + + + + + + words + + + + + + + + + +