novelWriter 2.2.1__py3-none-any.whl → 2.3b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/METADATA +1 -1
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/RECORD +102 -92
- novelwriter/__init__.py +4 -4
- novelwriter/assets/icons/typicons_dark/icons.conf +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_dark/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +6 -0
- novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_light/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
- novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
- novelwriter/assets/images/novelwriter-text-light.svg +4 -0
- novelwriter/assets/images/welcome-dark.jpg +0 -0
- novelwriter/assets/images/welcome-light.jpg +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/default_dark.conf +1 -0
- novelwriter/assets/syntax/default_light.conf +1 -0
- novelwriter/assets/syntax/grey_dark.conf +1 -0
- novelwriter/assets/syntax/grey_light.conf +1 -0
- novelwriter/assets/syntax/light_owl.conf +1 -0
- novelwriter/assets/syntax/night_owl.conf +1 -0
- novelwriter/assets/syntax/solarized_dark.conf +1 -0
- novelwriter/assets/syntax/solarized_light.conf +1 -0
- novelwriter/assets/syntax/tomorrow.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
- novelwriter/assets/text/credits_en.htm +4 -2
- novelwriter/assets/themes/default_dark.conf +2 -2
- novelwriter/assets/themes/default_light.conf +2 -2
- novelwriter/common.py +48 -37
- novelwriter/config.py +36 -41
- novelwriter/constants.py +38 -16
- novelwriter/core/buildsettings.py +7 -7
- novelwriter/core/coretools.py +192 -154
- novelwriter/core/docbuild.py +6 -3
- novelwriter/core/document.py +6 -6
- novelwriter/core/index.py +89 -56
- novelwriter/core/item.py +21 -3
- novelwriter/core/options.py +8 -7
- novelwriter/core/project.py +69 -44
- novelwriter/core/projectdata.py +1 -14
- novelwriter/core/projectxml.py +13 -41
- novelwriter/core/sessions.py +2 -1
- novelwriter/core/spellcheck.py +2 -1
- novelwriter/core/status.py +2 -1
- novelwriter/core/storage.py +178 -140
- novelwriter/core/tohtml.py +4 -2
- novelwriter/core/tokenizer.py +73 -45
- novelwriter/core/toodt.py +40 -30
- novelwriter/core/tree.py +3 -2
- novelwriter/dialogs/about.py +70 -160
- novelwriter/dialogs/docmerge.py +6 -5
- novelwriter/dialogs/docsplit.py +6 -6
- novelwriter/dialogs/editlabel.py +1 -1
- novelwriter/dialogs/preferences.py +553 -703
- novelwriter/dialogs/{projsettings.py → projectsettings.py} +288 -262
- novelwriter/dialogs/quotes.py +27 -23
- novelwriter/dialogs/wordlist.py +96 -40
- novelwriter/enum.py +20 -18
- novelwriter/error.py +1 -1
- novelwriter/extensions/circularprogress.py +11 -11
- novelwriter/extensions/configlayout.py +185 -134
- novelwriter/extensions/modified.py +81 -0
- novelwriter/extensions/novelselector.py +26 -12
- novelwriter/extensions/pagedsidebar.py +14 -16
- novelwriter/extensions/simpleprogress.py +5 -5
- novelwriter/extensions/statusled.py +8 -8
- novelwriter/extensions/switch.py +31 -63
- novelwriter/extensions/switchbox.py +1 -1
- novelwriter/extensions/versioninfo.py +153 -0
- novelwriter/gui/doceditor.py +178 -150
- novelwriter/gui/dochighlight.py +63 -92
- novelwriter/gui/docviewer.py +49 -51
- novelwriter/gui/docviewerpanel.py +72 -24
- novelwriter/gui/itemdetails.py +7 -7
- novelwriter/gui/mainmenu.py +14 -18
- novelwriter/gui/noveltree.py +9 -8
- novelwriter/gui/outline.py +98 -75
- novelwriter/gui/projtree.py +188 -61
- novelwriter/gui/sidebar.py +3 -4
- novelwriter/gui/statusbar.py +3 -4
- novelwriter/gui/theme.py +60 -68
- novelwriter/guimain.py +49 -156
- novelwriter/shared.py +15 -1
- novelwriter/tools/dictionaries.py +5 -6
- novelwriter/tools/manuscript.py +6 -6
- novelwriter/tools/manussettings.py +192 -221
- novelwriter/tools/noveldetails.py +525 -0
- novelwriter/tools/welcome.py +802 -0
- novelwriter/tools/writingstats.py +9 -9
- novelwriter/assets/images/wizard-back.jpg +0 -0
- novelwriter/assets/text/gplv3_en.htm +0 -641
- novelwriter/assets/text/release_notes.htm +0 -60
- novelwriter/dialogs/projdetails.py +0 -518
- novelwriter/dialogs/projload.py +0 -294
- novelwriter/dialogs/updates.py +0 -172
- novelwriter/extensions/pageddialog.py +0 -130
- novelwriter/tools/projwizard.py +0 -478
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/WHEEL +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/top_level.txt +0 -0
@@ -1,60 +0,0 @@
|
|
1
|
-
<!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
2
|
-
<html>
|
3
|
-
<body>
|
4
|
-
|
5
|
-
<h2>Release Notes for 2.2</h2>
|
6
|
-
<p><i>Released on 17 December 2023</i></p>
|
7
|
-
|
8
|
-
<p>Scroll down for <a href="#patch">Patch Notes</a></p>
|
9
|
-
|
10
|
-
<p>This release comes with a number of new features. These are some highlights.</p>
|
11
|
-
<p>In addition to the common Markdown style formatting for bold, italic and strike through, a set
|
12
|
-
of new shortcodes have been added. The shortcodes are far more flexible than the Markdown style
|
13
|
-
syntax, and can be used for more complex formatting cases. Like when you need to add multiple,
|
14
|
-
overlapping formats, or add emphasis to just a part of a word. The shortcodes also allow for
|
15
|
-
underline, subscript and superscript, which the Markdown syntax does not. The new formats are
|
16
|
-
available in the "Format" menu, and in a new toolbar in the editor that can be enabled by clicking
|
17
|
-
the three dots in the top–left corner. The shortcode format was chosen because it can later be
|
18
|
-
extended to include other requested features as well. Please have a look at the documentation for
|
19
|
-
more details about the new shortcodes.</p>
|
20
|
-
<p>The Tags and References system has been improved. The tags themselves are no longer case
|
21
|
-
sensitive when you use them in references, but they are still displayed as you typed them in the
|
22
|
-
tag definition when they are displayed in the user interface. Starting to type the '@' symbol in
|
23
|
-
the text editor, on a new line, will now open an auto-completer menu which will display available
|
24
|
-
options. It may not display all of your tags if you have a lot of them, but starting to type more
|
25
|
-
characters will filter the list down further.</p>
|
26
|
-
<p>You can now automatically create a note file for a new tag that you have added to a reference
|
27
|
-
list in a document, but is not yet defined in a project note. So, for instance, if you come up with
|
28
|
-
a new character while writing, and add a new tag to your '@char' references, you can right-click
|
29
|
-
the new tag and create a new note for that entry directly. In addition, it is now also possible to
|
30
|
-
right-click a heading in an open document and set the item label in the project tree to match the
|
31
|
-
heading.</p>
|
32
|
-
<p>In addition to the changes in the editor, the "References" panel below the document viewer has
|
33
|
-
also been completely redesigned. It now shows all the references to the document you are viewing as
|
34
|
-
a list, with a lot more details than before. In addition, tabs in the panel will appear to show all
|
35
|
-
the tags you have defined in your notes, sorted as one tab per category. Like for instance
|
36
|
-
Characters, Locations, Objects, etc. You can also give each note a short description comment on the
|
37
|
-
same format as the summary comments for chapters and scenes. The short description comment can be
|
38
|
-
added from the "Insert" menu under "Special Comments".</p>
|
39
|
-
<p>The last major change in this release is the new multi-select feature in the project tree. You
|
40
|
-
can now select multiple documents and folders using the mouse while pressing 'Ctrl' or 'Shift'. By
|
41
|
-
right-clicking the selected items, you can perform a limited set of operations on all of them, like
|
42
|
-
changing active status, and the status or importance labels. You can also drag and drop multiple
|
43
|
-
items under the condition that all the selected items are in the same folder, at the same level.
|
44
|
-
This restriction is in place due to limitations in the framework novelWriter is based on. But this
|
45
|
-
should help in cases where multiple documents need to be moved in and out of folders or between
|
46
|
-
folders. Note that adding the multi-select feature meant that the undo feature of the project tree
|
47
|
-
had to be removed. It may be added back later.</p>
|
48
|
-
|
49
|
-
<p><i>See also the <a href="https://github.com/vkbo/novelWriter/releases">Releases</a> page.</i></p>
|
50
|
-
|
51
|
-
<a name="patch"></a><h2>Patch Notes</h2>
|
52
|
-
|
53
|
-
<h3>Patch 2.2.1 – 27 January 2024</h3>
|
54
|
-
|
55
|
-
<p>This is a patch release that fixes an issue where the Project View would sometimes switch to the
|
56
|
-
Novel View when a new item was created. This patch also includes updated translations for German
|
57
|
-
and Chinese.</p>
|
58
|
-
|
59
|
-
</body>
|
60
|
-
</html>
|
@@ -1,518 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
novelWriter – GUI Project Details
|
3
|
-
=================================
|
4
|
-
|
5
|
-
File History:
|
6
|
-
Created: 2021-01-03 [1.1rc1] GuiProjectDetails
|
7
|
-
|
8
|
-
This file is a part of novelWriter
|
9
|
-
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
|
-
|
11
|
-
This program is free software: you can redistribute it and/or modify
|
12
|
-
it under the terms of the GNU General Public License as published by
|
13
|
-
the Free Software Foundation, either version 3 of the License, or
|
14
|
-
(at your option) any later version.
|
15
|
-
|
16
|
-
This program is distributed in the hope that it will be useful, but
|
17
|
-
WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19
|
-
General Public License for more details.
|
20
|
-
|
21
|
-
You should have received a copy of the GNU General Public License
|
22
|
-
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
23
|
-
"""
|
24
|
-
from __future__ import annotations
|
25
|
-
|
26
|
-
import math
|
27
|
-
import logging
|
28
|
-
|
29
|
-
from PyQt5.QtGui import QCloseEvent, QFont
|
30
|
-
from PyQt5.QtCore import Qt, QSize, pyqtSlot
|
31
|
-
from PyQt5.QtWidgets import (
|
32
|
-
QAbstractItemView, QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel,
|
33
|
-
QLineEdit, QSpinBox, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
34
|
-
)
|
35
|
-
|
36
|
-
from novelwriter import CONFIG, SHARED
|
37
|
-
from novelwriter.common import formatTime, numberToRoman
|
38
|
-
from novelwriter.constants import nwUnicode
|
39
|
-
from novelwriter.extensions.switch import NSwitch
|
40
|
-
from novelwriter.extensions.pageddialog import NPagedDialog
|
41
|
-
from novelwriter.extensions.novelselector import NovelSelector
|
42
|
-
|
43
|
-
logger = logging.getLogger(__name__)
|
44
|
-
|
45
|
-
|
46
|
-
class GuiProjectDetails(NPagedDialog):
|
47
|
-
|
48
|
-
def __init__(self, parent: QWidget) -> None:
|
49
|
-
super().__init__(parent=parent)
|
50
|
-
|
51
|
-
logger.debug("Create: GuiProjectDetails")
|
52
|
-
self.setObjectName("GuiProjectDetails")
|
53
|
-
|
54
|
-
self.setWindowTitle(self.tr("Project Details"))
|
55
|
-
|
56
|
-
wW = CONFIG.pxInt(600)
|
57
|
-
wH = CONFIG.pxInt(400)
|
58
|
-
pOptions = SHARED.project.options
|
59
|
-
|
60
|
-
self.setMinimumWidth(wW)
|
61
|
-
self.setMinimumHeight(wH)
|
62
|
-
self.resize(
|
63
|
-
CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "winWidth", wW)),
|
64
|
-
CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "winHeight", wH))
|
65
|
-
)
|
66
|
-
|
67
|
-
self.tabMain = GuiProjectDetailsMain(self)
|
68
|
-
self.tabContents = GuiProjectDetailsContents(self)
|
69
|
-
|
70
|
-
self.addTab(self.tabMain, self.tr("Overview"))
|
71
|
-
self.addTab(self.tabContents, self.tr("Contents"))
|
72
|
-
|
73
|
-
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
|
74
|
-
self.buttonBox.rejected.connect(self.close)
|
75
|
-
self.rejected.connect(self.close)
|
76
|
-
self.addControls(self.buttonBox)
|
77
|
-
|
78
|
-
logger.debug("Ready: GuiProjectDetails")
|
79
|
-
|
80
|
-
return
|
81
|
-
|
82
|
-
def __del__(self) -> None: # pragma: no cover
|
83
|
-
logger.debug("Delete: GuiProjectDetails")
|
84
|
-
return
|
85
|
-
|
86
|
-
def updateValues(self) -> None:
|
87
|
-
"""Set all the values of the pages."""
|
88
|
-
self.tabMain.updateValues()
|
89
|
-
self.tabContents.updateValues()
|
90
|
-
return
|
91
|
-
|
92
|
-
##
|
93
|
-
# Events
|
94
|
-
##
|
95
|
-
|
96
|
-
def closeEvent(self, event: QCloseEvent) -> None:
|
97
|
-
"""Capture the close event and perform cleanup."""
|
98
|
-
self._saveGuiSettings()
|
99
|
-
event.accept()
|
100
|
-
self.deleteLater()
|
101
|
-
return
|
102
|
-
|
103
|
-
##
|
104
|
-
# Internal Functions
|
105
|
-
##
|
106
|
-
|
107
|
-
def _saveGuiSettings(self) -> None:
|
108
|
-
"""Save GUI settings."""
|
109
|
-
winWidth = CONFIG.rpxInt(self.width())
|
110
|
-
winHeight = CONFIG.rpxInt(self.height())
|
111
|
-
|
112
|
-
cColWidth = self.tabContents.getColumnSizes()
|
113
|
-
widthCol0 = CONFIG.rpxInt(cColWidth[0])
|
114
|
-
widthCol1 = CONFIG.rpxInt(cColWidth[1])
|
115
|
-
widthCol2 = CONFIG.rpxInt(cColWidth[2])
|
116
|
-
widthCol3 = CONFIG.rpxInt(cColWidth[3])
|
117
|
-
widthCol4 = CONFIG.rpxInt(cColWidth[4])
|
118
|
-
|
119
|
-
wordsPerPage = self.tabContents.wpValue.value()
|
120
|
-
countFrom = self.tabContents.poValue.value()
|
121
|
-
clearDouble = self.tabContents.dblValue.isChecked()
|
122
|
-
|
123
|
-
logger.debug("Saving State: GuiProjectDetails")
|
124
|
-
pOptions = SHARED.project.options
|
125
|
-
pOptions.setValue("GuiProjectDetails", "winWidth", winWidth)
|
126
|
-
pOptions.setValue("GuiProjectDetails", "winHeight", winHeight)
|
127
|
-
pOptions.setValue("GuiProjectDetails", "widthCol0", widthCol0)
|
128
|
-
pOptions.setValue("GuiProjectDetails", "widthCol1", widthCol1)
|
129
|
-
pOptions.setValue("GuiProjectDetails", "widthCol2", widthCol2)
|
130
|
-
pOptions.setValue("GuiProjectDetails", "widthCol3", widthCol3)
|
131
|
-
pOptions.setValue("GuiProjectDetails", "widthCol4", widthCol4)
|
132
|
-
pOptions.setValue("GuiProjectDetails", "wordsPerPage", wordsPerPage)
|
133
|
-
pOptions.setValue("GuiProjectDetails", "countFrom", countFrom)
|
134
|
-
pOptions.setValue("GuiProjectDetails", "clearDouble", clearDouble)
|
135
|
-
|
136
|
-
return
|
137
|
-
|
138
|
-
# END Class GuiProjectDetails
|
139
|
-
|
140
|
-
|
141
|
-
class GuiProjectDetailsMain(QWidget):
|
142
|
-
|
143
|
-
def __init__(self, parent: QWidget) -> None:
|
144
|
-
super().__init__(parent=parent)
|
145
|
-
|
146
|
-
fPx = SHARED.theme.fontPixelSize
|
147
|
-
fPt = SHARED.theme.fontPointSize
|
148
|
-
vPx = CONFIG.pxInt(4)
|
149
|
-
hPx = CONFIG.pxInt(12)
|
150
|
-
|
151
|
-
# Header
|
152
|
-
# ======
|
153
|
-
|
154
|
-
self.bookTitle = QLabel("")
|
155
|
-
bookFont = self.bookTitle.font()
|
156
|
-
bookFont.setPointSizeF(2.2*fPt)
|
157
|
-
bookFont.setWeight(QFont.Bold)
|
158
|
-
self.bookTitle.setFont(bookFont)
|
159
|
-
self.bookTitle.setAlignment(Qt.AlignHCenter)
|
160
|
-
self.bookTitle.setWordWrap(True)
|
161
|
-
|
162
|
-
self.projName = QLabel("")
|
163
|
-
workFont = self.projName.font()
|
164
|
-
workFont.setPointSizeF(0.8*fPt)
|
165
|
-
workFont.setItalic(True)
|
166
|
-
self.projName.setFont(workFont)
|
167
|
-
self.projName.setAlignment(Qt.AlignHCenter)
|
168
|
-
self.projName.setWordWrap(True)
|
169
|
-
|
170
|
-
self.bookAuthors = QLabel("")
|
171
|
-
authFont = self.bookAuthors.font()
|
172
|
-
authFont.setPointSizeF(1.2*fPt)
|
173
|
-
self.bookAuthors.setFont(authFont)
|
174
|
-
self.bookAuthors.setAlignment(Qt.AlignHCenter)
|
175
|
-
self.bookAuthors.setWordWrap(True)
|
176
|
-
|
177
|
-
# Stats
|
178
|
-
# =====
|
179
|
-
|
180
|
-
self.wordCountLbl = QLabel("<b>%s:</b>" % self.tr("Words"))
|
181
|
-
self.wordCountVal = QLabel("")
|
182
|
-
|
183
|
-
self.chapCountLbl = QLabel("<b>%s:</b>" % self.tr("Chapters"))
|
184
|
-
self.chapCountVal = QLabel("")
|
185
|
-
|
186
|
-
self.sceneCountLbl = QLabel("<b>%s:</b>" % self.tr("Scenes"))
|
187
|
-
self.sceneCountVal = QLabel("")
|
188
|
-
|
189
|
-
self.revCountLbl = QLabel("<b>%s:</b>" % self.tr("Revisions"))
|
190
|
-
self.revCountVal = QLabel("")
|
191
|
-
|
192
|
-
self.editTimeLbl = QLabel("<b>%s:</b>" % self.tr("Editing Time"))
|
193
|
-
self.editTimeVal = QLabel("")
|
194
|
-
|
195
|
-
self.statsGrid = QGridLayout()
|
196
|
-
self.statsGrid.addWidget(self.wordCountLbl, 0, 0, 1, 1, Qt.AlignRight)
|
197
|
-
self.statsGrid.addWidget(self.wordCountVal, 0, 1, 1, 1, Qt.AlignLeft)
|
198
|
-
self.statsGrid.addWidget(self.chapCountLbl, 1, 0, 1, 1, Qt.AlignRight)
|
199
|
-
self.statsGrid.addWidget(self.chapCountVal, 1, 1, 1, 1, Qt.AlignLeft)
|
200
|
-
self.statsGrid.addWidget(self.sceneCountLbl, 2, 0, 1, 1, Qt.AlignRight)
|
201
|
-
self.statsGrid.addWidget(self.sceneCountVal, 2, 1, 1, 1, Qt.AlignLeft)
|
202
|
-
self.statsGrid.addWidget(self.revCountLbl, 3, 0, 1, 1, Qt.AlignRight)
|
203
|
-
self.statsGrid.addWidget(self.revCountVal, 3, 1, 1, 1, Qt.AlignLeft)
|
204
|
-
self.statsGrid.addWidget(self.editTimeLbl, 4, 0, 1, 1, Qt.AlignRight)
|
205
|
-
self.statsGrid.addWidget(self.editTimeVal, 4, 1, 1, 1, Qt.AlignLeft)
|
206
|
-
self.statsGrid.setHorizontalSpacing(hPx)
|
207
|
-
self.statsGrid.setVerticalSpacing(vPx)
|
208
|
-
|
209
|
-
# Meta
|
210
|
-
# ====
|
211
|
-
|
212
|
-
self.projPathLbl = QLabel("<b>%s:</b>" % self.tr("Path"))
|
213
|
-
self.projPathVal = QLineEdit()
|
214
|
-
self.projPathVal.setReadOnly(True)
|
215
|
-
|
216
|
-
self.projPathBox = QHBoxLayout()
|
217
|
-
self.projPathBox.addWidget(self.projPathLbl)
|
218
|
-
self.projPathBox.addWidget(self.projPathVal)
|
219
|
-
self.projPathBox.setSpacing(hPx)
|
220
|
-
|
221
|
-
# Assemble
|
222
|
-
# ========
|
223
|
-
|
224
|
-
self.outerBox = QVBoxLayout()
|
225
|
-
self.outerBox.addSpacing(fPx)
|
226
|
-
self.outerBox.addWidget(self.bookTitle)
|
227
|
-
self.outerBox.addWidget(self.projName)
|
228
|
-
self.outerBox.addWidget(self.bookAuthors)
|
229
|
-
self.outerBox.addSpacing(2*fPx)
|
230
|
-
self.outerBox.addLayout(self.statsGrid)
|
231
|
-
self.outerBox.addSpacing(fPx)
|
232
|
-
self.outerBox.addStretch(1)
|
233
|
-
self.outerBox.addLayout(self.projPathBox)
|
234
|
-
|
235
|
-
self.setLayout(self.outerBox)
|
236
|
-
|
237
|
-
return
|
238
|
-
|
239
|
-
def updateValues(self) -> None:
|
240
|
-
"""Set all the values."""
|
241
|
-
project = SHARED.project
|
242
|
-
pIndex = project.index
|
243
|
-
hCounts = pIndex.getNovelTitleCounts()
|
244
|
-
nwCount = pIndex.getNovelWordCount()
|
245
|
-
edTime = project.currentEditTime
|
246
|
-
|
247
|
-
self.bookTitle.setText(project.data.title or project.data.name)
|
248
|
-
self.projName.setText(self.tr("Project: {0}").format(project.data.name))
|
249
|
-
self.bookAuthors.setText(self.tr("By {0}").format(project.data.author))
|
250
|
-
|
251
|
-
self.wordCountVal.setText(f"{nwCount:n}")
|
252
|
-
self.chapCountVal.setText(f"{hCounts[2]:n}")
|
253
|
-
self.sceneCountVal.setText(f"{hCounts[3]:n}")
|
254
|
-
self.revCountVal.setText(f"{project.data.saveCount:n}")
|
255
|
-
self.editTimeVal.setText(formatTime(edTime))
|
256
|
-
|
257
|
-
self.projPathVal.setText(str(project.storage.storagePath))
|
258
|
-
|
259
|
-
return
|
260
|
-
|
261
|
-
# END Class GuiProjectDetailsMain
|
262
|
-
|
263
|
-
|
264
|
-
class GuiProjectDetailsContents(QWidget):
|
265
|
-
|
266
|
-
C_TITLE = 0
|
267
|
-
C_WORDS = 1
|
268
|
-
C_PAGES = 2
|
269
|
-
C_PAGE = 3
|
270
|
-
C_PROG = 4
|
271
|
-
|
272
|
-
def __init__(self, parent: QWidget) -> None:
|
273
|
-
super().__init__(parent=parent)
|
274
|
-
|
275
|
-
# Internal
|
276
|
-
self._theToC = []
|
277
|
-
self._currentRoot = None
|
278
|
-
|
279
|
-
iPx = SHARED.theme.baseIconSize
|
280
|
-
hPx = CONFIG.pxInt(12)
|
281
|
-
vPx = CONFIG.pxInt(4)
|
282
|
-
pOptions = SHARED.project.options
|
283
|
-
|
284
|
-
# Header
|
285
|
-
# ======
|
286
|
-
|
287
|
-
self.tocLabel = QLabel("<b>%s</b>" % self.tr("Table of Contents"))
|
288
|
-
|
289
|
-
self.novelValue = NovelSelector(self)
|
290
|
-
self.novelValue.setMinimumWidth(CONFIG.pxInt(200))
|
291
|
-
self.novelValue.novelSelectionChanged.connect(self._novelValueChanged)
|
292
|
-
|
293
|
-
self.headBox = QHBoxLayout()
|
294
|
-
self.headBox.addWidget(self.tocLabel)
|
295
|
-
self.headBox.addWidget(self.novelValue)
|
296
|
-
|
297
|
-
# Contents Tree
|
298
|
-
# =============
|
299
|
-
|
300
|
-
self.tocTree = QTreeWidget()
|
301
|
-
self.tocTree.setIconSize(QSize(iPx, iPx))
|
302
|
-
self.tocTree.setIndentation(0)
|
303
|
-
self.tocTree.setColumnCount(6)
|
304
|
-
self.tocTree.setSelectionMode(QAbstractItemView.NoSelection)
|
305
|
-
self.tocTree.setHeaderLabels([
|
306
|
-
self.tr("Title"),
|
307
|
-
self.tr("Words"),
|
308
|
-
self.tr("Pages"),
|
309
|
-
self.tr("Page"),
|
310
|
-
self.tr("Progress"),
|
311
|
-
""
|
312
|
-
])
|
313
|
-
|
314
|
-
treeHeadItem = self.tocTree.headerItem()
|
315
|
-
if treeHeadItem:
|
316
|
-
treeHeadItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
317
|
-
treeHeadItem.setTextAlignment(self.C_PAGES, Qt.AlignRight)
|
318
|
-
treeHeadItem.setTextAlignment(self.C_PAGE, Qt.AlignRight)
|
319
|
-
treeHeadItem.setTextAlignment(self.C_PROG, Qt.AlignRight)
|
320
|
-
|
321
|
-
treeHeader = self.tocTree.header()
|
322
|
-
treeHeader.setStretchLastSection(True)
|
323
|
-
treeHeader.setMinimumSectionSize(hPx)
|
324
|
-
|
325
|
-
wCol0 = CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "widthCol0", 200))
|
326
|
-
wCol1 = CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "widthCol1", 60))
|
327
|
-
wCol2 = CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "widthCol2", 60))
|
328
|
-
wCol3 = CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "widthCol3", 60))
|
329
|
-
wCol4 = CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "widthCol4", 90))
|
330
|
-
|
331
|
-
self.tocTree.setColumnWidth(0, wCol0)
|
332
|
-
self.tocTree.setColumnWidth(1, wCol1)
|
333
|
-
self.tocTree.setColumnWidth(2, wCol2)
|
334
|
-
self.tocTree.setColumnWidth(3, wCol3)
|
335
|
-
self.tocTree.setColumnWidth(4, wCol4)
|
336
|
-
self.tocTree.setColumnWidth(5, hPx)
|
337
|
-
|
338
|
-
# Options
|
339
|
-
# =======
|
340
|
-
|
341
|
-
wordsPerPage = pOptions.getInt("GuiProjectDetails", "wordsPerPage", 350)
|
342
|
-
countFrom = pOptions.getInt("GuiProjectDetails", "countFrom", 1)
|
343
|
-
clearDouble = pOptions.getBool("GuiProjectDetails", "clearDouble", True)
|
344
|
-
|
345
|
-
wordsHelp = (
|
346
|
-
self.tr("Typical word count for a 5 by 8 inch book page with 11 pt font is 350.")
|
347
|
-
)
|
348
|
-
offsetHelp = (
|
349
|
-
self.tr("Start counting page numbers from this page.")
|
350
|
-
)
|
351
|
-
dblHelp = (
|
352
|
-
self.tr("Assume a new chapter or partition always start on an odd numbered page.")
|
353
|
-
)
|
354
|
-
|
355
|
-
self.wpLabel = QLabel(self.tr("Words per page"))
|
356
|
-
self.wpLabel.setToolTip(wordsHelp)
|
357
|
-
|
358
|
-
self.wpValue = QSpinBox()
|
359
|
-
self.wpValue.setMinimum(10)
|
360
|
-
self.wpValue.setMaximum(1000)
|
361
|
-
self.wpValue.setSingleStep(10)
|
362
|
-
self.wpValue.setValue(wordsPerPage)
|
363
|
-
self.wpValue.setToolTip(wordsHelp)
|
364
|
-
self.wpValue.valueChanged.connect(self._populateTree)
|
365
|
-
|
366
|
-
self.poLabel = QLabel(self.tr("Count pages from"))
|
367
|
-
self.poLabel.setToolTip(offsetHelp)
|
368
|
-
|
369
|
-
self.poValue = QSpinBox()
|
370
|
-
self.poValue.setMinimum(1)
|
371
|
-
self.poValue.setMaximum(9999)
|
372
|
-
self.poValue.setSingleStep(1)
|
373
|
-
self.poValue.setValue(countFrom)
|
374
|
-
self.poValue.setToolTip(offsetHelp)
|
375
|
-
self.poValue.valueChanged.connect(self._populateTree)
|
376
|
-
|
377
|
-
self.dblLabel = QLabel(self.tr("Clear double pages"))
|
378
|
-
self.dblLabel.setToolTip(dblHelp)
|
379
|
-
|
380
|
-
self.dblValue = NSwitch(self, 2*iPx, iPx)
|
381
|
-
self.dblValue.setChecked(clearDouble)
|
382
|
-
self.dblValue.setToolTip(dblHelp)
|
383
|
-
self.dblValue.clicked.connect(self._populateTree)
|
384
|
-
|
385
|
-
self.optionsBox = QGridLayout()
|
386
|
-
self.optionsBox.addWidget(self.wpLabel, 0, 0)
|
387
|
-
self.optionsBox.addWidget(self.wpValue, 0, 1)
|
388
|
-
self.optionsBox.addWidget(self.dblLabel, 0, 3)
|
389
|
-
self.optionsBox.addWidget(self.dblValue, 0, 4)
|
390
|
-
self.optionsBox.addWidget(self.poLabel, 1, 0)
|
391
|
-
self.optionsBox.addWidget(self.poValue, 1, 1)
|
392
|
-
self.optionsBox.setHorizontalSpacing(hPx)
|
393
|
-
self.optionsBox.setVerticalSpacing(vPx)
|
394
|
-
self.optionsBox.setColumnStretch(2, 1)
|
395
|
-
|
396
|
-
# Assemble
|
397
|
-
# ========
|
398
|
-
|
399
|
-
self.outerBox = QVBoxLayout()
|
400
|
-
self.outerBox.addLayout(self.headBox)
|
401
|
-
self.outerBox.addWidget(self.tocTree)
|
402
|
-
self.outerBox.addLayout(self.optionsBox)
|
403
|
-
|
404
|
-
self.setLayout(self.outerBox)
|
405
|
-
|
406
|
-
return
|
407
|
-
|
408
|
-
def getColumnSizes(self) -> list[int]:
|
409
|
-
"""Return the column widths for the tree columns."""
|
410
|
-
retVals = [
|
411
|
-
self.tocTree.columnWidth(0),
|
412
|
-
self.tocTree.columnWidth(1),
|
413
|
-
self.tocTree.columnWidth(2),
|
414
|
-
self.tocTree.columnWidth(3),
|
415
|
-
self.tocTree.columnWidth(4),
|
416
|
-
]
|
417
|
-
return retVals
|
418
|
-
|
419
|
-
def updateValues(self) -> None:
|
420
|
-
"""Populate the tree."""
|
421
|
-
self._currentRoot = None
|
422
|
-
self.novelValue.updateList()
|
423
|
-
self.novelValue.setHandle(self.novelValue.firstHandle)
|
424
|
-
self._prepareData(self.novelValue.firstHandle)
|
425
|
-
self._populateTree()
|
426
|
-
return
|
427
|
-
|
428
|
-
##
|
429
|
-
# Internal Functions
|
430
|
-
##
|
431
|
-
|
432
|
-
def _prepareData(self, rootHandle: str | None) -> None:
|
433
|
-
"""Extract the information from the project index."""
|
434
|
-
logger.debug("Populating ToC from handle '%s'", rootHandle)
|
435
|
-
self._theToC = SHARED.project.index.getTableOfContents(rootHandle, 2)
|
436
|
-
self._theToC.append(("", 0, self.tr("END"), 0))
|
437
|
-
return
|
438
|
-
|
439
|
-
##
|
440
|
-
# Slots
|
441
|
-
##
|
442
|
-
|
443
|
-
@pyqtSlot(str)
|
444
|
-
def _novelValueChanged(self, tHandle: str) -> None:
|
445
|
-
"""Refresh the tree with another root item."""
|
446
|
-
if tHandle != self._currentRoot:
|
447
|
-
self._prepareData(tHandle)
|
448
|
-
self._populateTree()
|
449
|
-
self._currentRoot = self.novelValue.handle
|
450
|
-
return
|
451
|
-
|
452
|
-
@pyqtSlot()
|
453
|
-
def _populateTree(self) -> None:
|
454
|
-
"""Set the content of the chapter/page tree."""
|
455
|
-
dblPages = self.dblValue.isChecked()
|
456
|
-
wpPage = self.wpValue.value()
|
457
|
-
fstPage = self.poValue.value() - 1
|
458
|
-
|
459
|
-
pTotal = 0
|
460
|
-
tPages = 1
|
461
|
-
|
462
|
-
theList = []
|
463
|
-
for _, tLevel, tTitle, wCount in self._theToC:
|
464
|
-
pCount = math.ceil(wCount/wpPage)
|
465
|
-
if dblPages:
|
466
|
-
pCount += pCount%2
|
467
|
-
|
468
|
-
pTotal += pCount
|
469
|
-
theList.append((tLevel, tTitle, wCount, pCount))
|
470
|
-
|
471
|
-
pMax = pTotal - fstPage
|
472
|
-
|
473
|
-
self.tocTree.clear()
|
474
|
-
for tLevel, tTitle, wCount, pCount in theList:
|
475
|
-
newItem = QTreeWidgetItem()
|
476
|
-
|
477
|
-
if tPages <= fstPage:
|
478
|
-
progPage = numberToRoman(tPages, True)
|
479
|
-
progText = ""
|
480
|
-
else:
|
481
|
-
cPage = tPages - fstPage
|
482
|
-
pgProg = 100.0*(cPage - 1)/pMax if pMax > 0 else 0.0
|
483
|
-
progPage = f"{cPage:n}"
|
484
|
-
progText = f"{pgProg:.1f}{nwUnicode.U_THSP}%"
|
485
|
-
|
486
|
-
hDec = SHARED.theme.getHeaderDecoration(tLevel)
|
487
|
-
if tTitle.strip() == "":
|
488
|
-
tTitle = self.tr("Untitled")
|
489
|
-
|
490
|
-
newItem.setData(self.C_TITLE, Qt.DecorationRole, hDec)
|
491
|
-
newItem.setText(self.C_TITLE, tTitle)
|
492
|
-
newItem.setText(self.C_WORDS, f"{wCount:n}")
|
493
|
-
newItem.setText(self.C_PAGES, f"{pCount:n}")
|
494
|
-
newItem.setText(self.C_PAGE, progPage)
|
495
|
-
newItem.setText(self.C_PROG, progText)
|
496
|
-
|
497
|
-
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
498
|
-
newItem.setTextAlignment(self.C_PAGES, Qt.AlignRight)
|
499
|
-
newItem.setTextAlignment(self.C_PAGE, Qt.AlignRight)
|
500
|
-
newItem.setTextAlignment(self.C_PROG, Qt.AlignRight)
|
501
|
-
|
502
|
-
# Make pages and titles/partitions stand out
|
503
|
-
if tLevel < 2:
|
504
|
-
bFont = newItem.font(self.C_TITLE)
|
505
|
-
if tLevel == 0:
|
506
|
-
bFont.setItalic(True)
|
507
|
-
else:
|
508
|
-
bFont.setBold(True)
|
509
|
-
bFont.setUnderline(True)
|
510
|
-
newItem.setFont(self.C_TITLE, bFont)
|
511
|
-
|
512
|
-
tPages += pCount
|
513
|
-
|
514
|
-
self.tocTree.addTopLevelItem(newItem)
|
515
|
-
|
516
|
-
return
|
517
|
-
|
518
|
-
# END Class GuiProjectDetailsContents
|