Merge pull request #460 from nephlm/session-target

Session target
This commit is contained in:
Tobias Frisch 2022-12-10 20:12:15 +01:00 committed by GitHub
commit 0203872cd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 468 additions and 2 deletions

View file

@ -30,6 +30,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
@ -69,6 +70,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self._defaultCursorFlashTime = 1000 # Overridden 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()
@ -164,12 +166,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Main Menu:: Tool
self.actToolFrequency.triggered.connect(self.frequencyAnalyzer)
self.actToolTargets.triggered.connect(self.sessionTargets)
self.actSupport.triggered.connect(self.support)
self.actLocateLog.triggered.connect(self.locateLogFile)
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):
@ -646,6 +653,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.projectDirty = False
QSettings().setValue("lastProject", project)
item = self.mdlOutline.rootItem
wc = item.data(Outline.wordCount)
self.sessionStartWordCount = int(wc) if wc != "" else 0
# Add project name to Window's name
self.setWindowTitle(self.projectName() + " - " + self.tr("Manuskript"))
@ -789,6 +799,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()
# User may have canceled close event, so make sure we indeed want to close.
# This is necessary because self.updateDockVisibility() hides UI elements.
if event.isAccepted():
@ -1491,6 +1507,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.fw.show()
self.centerChildWindow(self.fw)
def sessionTargets(self):
self.td = TargetsDialog(self)
self.td.show()
self.centerChildWindow(self.td)
###############################################################################
# VIEW MENU
###############################################################################

View file

@ -278,11 +278,11 @@ class Character(searchableItem):
def index(self, column=0):
return self._model.indexFromItem(self, column)
def data(self, column):
def data(self, column, role=Qt.DisplayRole):
if column == "Info":
return self.infos
else:
return self._data.get(column, None)
return self._data.get(column, role)
def assignRandomColor(self):
"""

View file

@ -1228,6 +1228,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.actSearch = QtWidgets.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme("edit-find")
self.actSearch.setIcon(icon)
@ -1254,6 +1256,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()
@ -1593,6 +1596,10 @@ 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+,"))
self.actSearch.setText(_translate("MainWindow", "Search"))
self.actSearch.setShortcut(_translate("MainWindow", "Ctrl+F"))
self.actSupport.setText(_translate("MainWindow", "&Technical Support"))
@ -1616,3 +1623,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_())

View file

@ -2038,6 +2038,7 @@
</property>
<addaction name="actSpellcheck"/>
<addaction name="actToolFrequency"/>
<addaction name="actToolTargets"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
@ -2720,6 +2721,15 @@
<string>B&amp;lockquote</string>
</property>
</action>
<action name="actToolTargets">
<property name="text">
<string>&amp;Targets</string>
</property>
<property name="toolTip">
<string>Draft and session word count targets</string>
</property>
<property name="shortcut">
<string>Ctrl+,</string>
<action name="actSearch">
<property name="icon">
<iconset theme="edit-find">

View file

@ -0,0 +1,68 @@
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.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 (
int(wc) if wc != "" else 0,
int(goal) if goal != "" else 0,
float(progress) if progress != "" else 0.0
)
def resetSession(self):
wc, _, _ = self.getDraftStats()
self.mw.sessionStartWordCount = wc
self.tick()
@staticmethod
def progress_bar_value(value):
return int(min(max(float(value) * 100, 0), 100))
def tick(self):
wc, goal, progress = self.getDraftStats()
self.draft_wc_label.setText(locale.format_string("%d", wc, grouping=True))
self.draft_goal_label.setText(locale.format_string("%d", goal, grouping=True))
# limit to 0-100 for display
self.draft_progress_bar.setValue(self.progress_bar_value(progress))
session_wc = wc - int(self.mw.sessionStartWordCount)
self.session_wc_label.setText(locale.format_string("%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()))
def closeEvent(self, event):
self.timer = None

View file

@ -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_())

View file

@ -0,0 +1,201 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>targets</class>
<widget class="QWidget" name="targets">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>322</width>
<height>216</height>
</rect>
</property>
<property name="windowTitle">
<string>Project Targets</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>../../../../../../../../../../home/icons/Manuskript/icon-64px.png</normaloff>../../../../../../../../../../home/icons/Manuskript/icon-64px.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Draft Target</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QProgressBar" name="draft_progress_bar">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="draft_wc_label">
<property name="text">
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="draft_of_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>of</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="draft_goal_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>10,000</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Words</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Session Target</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="session_reset">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QProgressBar" name="session_progress_bar">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="session_wc_label">
<property name="text">
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>of</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="session_target">
<property name="decimals">
<number>0</number>
</property>
<property name="maximum">
<double>99999999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>50.000000000000000</double>
</property>
<property name="value">
<double>500.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>words</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>