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
@@ -3,7 +3,8 @@ novelWriter – GUI Project Settings
|
|
3
3
|
==================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created:
|
6
|
+
Created: 2018-09-29 [0.0.1] GuiProjectSettings
|
7
|
+
Rewritten: 2024-01-26 [2.3b1] GuiProjectSettings
|
7
8
|
|
8
9
|
This file is a part of novelWriter
|
9
10
|
Copyright 2018–2024, Veronica Berglyd Olsen
|
@@ -25,75 +26,105 @@ from __future__ import annotations
|
|
25
26
|
|
26
27
|
import logging
|
27
28
|
|
28
|
-
from
|
29
|
-
|
30
|
-
from PyQt5.QtGui import QCloseEvent, QIcon, QPixmap, QColor
|
29
|
+
from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap
|
31
30
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
32
31
|
from PyQt5.QtWidgets import (
|
33
|
-
QColorDialog,
|
34
|
-
QPushButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
32
|
+
QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout, QLineEdit,
|
33
|
+
QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
34
|
+
QWidget, qApp
|
35
35
|
)
|
36
36
|
|
37
37
|
from novelwriter import CONFIG, SHARED
|
38
38
|
from novelwriter.common import simplified
|
39
39
|
from novelwriter.extensions.switch import NSwitch
|
40
|
-
from novelwriter.extensions.
|
41
|
-
from novelwriter.extensions.configlayout import
|
42
|
-
|
43
|
-
if TYPE_CHECKING: # pragma: no cover
|
44
|
-
from novelwriter.guimain import GuiMain
|
40
|
+
from novelwriter.extensions.modified import NComboBox
|
41
|
+
from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollableForm
|
42
|
+
from novelwriter.extensions.pagedsidebar import NPagedSideBar
|
45
43
|
|
46
44
|
logger = logging.getLogger(__name__)
|
47
45
|
|
48
46
|
|
49
|
-
class GuiProjectSettings(
|
47
|
+
class GuiProjectSettings(QDialog):
|
50
48
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
PAGE_SETTINGS = 0
|
50
|
+
PAGE_STATUS = 1
|
51
|
+
PAGE_IMPORT = 2
|
52
|
+
PAGE_REPLACE = 3
|
55
53
|
|
56
|
-
newProjectSettingsReady = pyqtSignal()
|
54
|
+
newProjectSettingsReady = pyqtSignal(bool)
|
57
55
|
|
58
|
-
def __init__(self,
|
59
|
-
super().__init__(parent=
|
56
|
+
def __init__(self, parent: QWidget, gotoPage: int = PAGE_SETTINGS) -> None:
|
57
|
+
super().__init__(parent=parent)
|
60
58
|
|
61
59
|
logger.debug("Create: GuiProjectSettings")
|
62
60
|
self.setObjectName("GuiProjectSettings")
|
63
|
-
|
64
|
-
self.mainGui = mainGui
|
65
|
-
SHARED.project.countStatus()
|
66
61
|
self.setWindowTitle(self.tr("Project Settings"))
|
67
62
|
|
68
|
-
|
69
|
-
|
70
|
-
pOptions = SHARED.project.options
|
71
|
-
|
72
|
-
self.setMinimumWidth(wW)
|
73
|
-
self.setMinimumHeight(wH)
|
63
|
+
options = SHARED.project.options
|
64
|
+
self.setMinimumSize(CONFIG.pxInt(500), CONFIG.pxInt(400))
|
74
65
|
self.resize(
|
75
|
-
CONFIG.pxInt(
|
76
|
-
CONFIG.pxInt(
|
66
|
+
CONFIG.pxInt(options.getInt("GuiProjectSettings", "winWidth", CONFIG.pxInt(650))),
|
67
|
+
CONFIG.pxInt(options.getInt("GuiProjectSettings", "winHeight", CONFIG.pxInt(500)))
|
77
68
|
)
|
78
69
|
|
79
|
-
|
80
|
-
self.
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
self.addTab(self.tabMain, self.tr("Settings"))
|
85
|
-
self.addTab(self.tabStatus, self.tr("Status"))
|
86
|
-
self.addTab(self.tabImport, self.tr("Importance"))
|
87
|
-
self.addTab(self.tabReplace, self.tr("Auto-Replace"))
|
70
|
+
# Title
|
71
|
+
self.titleLabel = NColourLabel(
|
72
|
+
self.tr("Project Settings"), SHARED.theme.helpText,
|
73
|
+
parent=self, scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
|
74
|
+
)
|
88
75
|
|
89
|
-
|
76
|
+
# SideBar
|
77
|
+
self.sidebar = NPagedSideBar(self)
|
78
|
+
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
79
|
+
self.sidebar.addButton(self.tr("Settings"), self.PAGE_SETTINGS)
|
80
|
+
self.sidebar.addButton(self.tr("Status"), self.PAGE_STATUS)
|
81
|
+
self.sidebar.addButton(self.tr("Importance"), self.PAGE_IMPORT)
|
82
|
+
self.sidebar.addButton(self.tr("Auto-Replace"), self.PAGE_REPLACE)
|
83
|
+
self.sidebar.buttonClicked.connect(self._sidebarClicked)
|
84
|
+
|
85
|
+
# Buttons
|
86
|
+
self.buttonBox = QDialogButtonBox(
|
87
|
+
QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel
|
88
|
+
)
|
90
89
|
self.buttonBox.accepted.connect(self._doSave)
|
91
90
|
self.buttonBox.rejected.connect(self.close)
|
92
|
-
self.rejected.connect(self.close)
|
93
|
-
self.addControls(self.buttonBox)
|
94
91
|
|
95
|
-
#
|
96
|
-
|
92
|
+
# Content
|
93
|
+
SHARED.project.countStatus()
|
94
|
+
|
95
|
+
self.settingsPage = _SettingsPage(self)
|
96
|
+
self.statusPage = _StatusPage(self, True)
|
97
|
+
self.importPage = _StatusPage(self, False)
|
98
|
+
self.replacePage = _ReplacePage(self)
|
99
|
+
|
100
|
+
self.mainStack = QStackedWidget(self)
|
101
|
+
self.mainStack.addWidget(self.settingsPage)
|
102
|
+
self.mainStack.addWidget(self.statusPage)
|
103
|
+
self.mainStack.addWidget(self.importPage)
|
104
|
+
self.mainStack.addWidget(self.replacePage)
|
105
|
+
|
106
|
+
# Assemble
|
107
|
+
self.topBox = QHBoxLayout()
|
108
|
+
self.topBox.addWidget(self.titleLabel)
|
109
|
+
self.topBox.addStretch(1)
|
110
|
+
|
111
|
+
self.mainBox = QHBoxLayout()
|
112
|
+
self.mainBox.addWidget(self.sidebar)
|
113
|
+
self.mainBox.addWidget(self.mainStack)
|
114
|
+
self.mainBox.setContentsMargins(0, 0, 0, 0)
|
115
|
+
|
116
|
+
self.outerBox = QVBoxLayout()
|
117
|
+
self.outerBox.addLayout(self.topBox)
|
118
|
+
self.outerBox.addLayout(self.mainBox)
|
119
|
+
self.outerBox.addWidget(self.buttonBox)
|
120
|
+
self.outerBox.setSpacing(CONFIG.pxInt(8))
|
121
|
+
|
122
|
+
self.setLayout(self.outerBox)
|
123
|
+
self.setSizeGripEnabled(True)
|
124
|
+
|
125
|
+
# Jump to Specified Page
|
126
|
+
self.sidebar.setSelected(gotoPage)
|
127
|
+
self._sidebarClicked(gotoPage)
|
97
128
|
|
98
129
|
logger.debug("Ready: GuiProjectSettings")
|
99
130
|
|
@@ -103,9 +134,13 @@ class GuiProjectSettings(NPagedDialog):
|
|
103
134
|
logger.debug("Delete: GuiProjectSettings")
|
104
135
|
return
|
105
136
|
|
137
|
+
##
|
138
|
+
# Events
|
139
|
+
##
|
140
|
+
|
106
141
|
def closeEvent(self, event: QCloseEvent) -> None:
|
107
|
-
"""Capture the
|
108
|
-
self.
|
142
|
+
"""Capture the user closing the window and save settings."""
|
143
|
+
self._saveSettings()
|
109
144
|
event.accept()
|
110
145
|
self.deleteLater()
|
111
146
|
return
|
@@ -114,40 +149,52 @@ class GuiProjectSettings(NPagedDialog):
|
|
114
149
|
# Private Slots
|
115
150
|
##
|
116
151
|
|
152
|
+
@pyqtSlot(int)
|
153
|
+
def _sidebarClicked(self, pageId: int) -> None:
|
154
|
+
"""Process a user request to switch page."""
|
155
|
+
if pageId == self.PAGE_SETTINGS:
|
156
|
+
self.mainStack.setCurrentWidget(self.settingsPage)
|
157
|
+
elif pageId == self.PAGE_STATUS:
|
158
|
+
self.mainStack.setCurrentWidget(self.statusPage)
|
159
|
+
elif pageId == self.PAGE_IMPORT:
|
160
|
+
self.mainStack.setCurrentWidget(self.importPage)
|
161
|
+
elif pageId == self.PAGE_REPLACE:
|
162
|
+
self.mainStack.setCurrentWidget(self.replacePage)
|
163
|
+
return
|
164
|
+
|
117
165
|
@pyqtSlot()
|
118
166
|
def _doSave(self) -> None:
|
119
167
|
"""Save settings and close dialog."""
|
120
168
|
project = SHARED.project
|
121
|
-
projName = self.
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
doBackup = not self.tabMain.doBackup.isChecked()
|
169
|
+
projName = self.settingsPage.projName.text()
|
170
|
+
projAuthor = self.settingsPage.projAuthor.text()
|
171
|
+
projLang = self.settingsPage.projLang.currentData()
|
172
|
+
spellLang = self.settingsPage.spellLang.currentData()
|
173
|
+
doBackup = not self.settingsPage.doBackup.isChecked()
|
127
174
|
|
128
175
|
project.data.setName(projName)
|
129
|
-
project.data.
|
130
|
-
project.data.setAuthor(bookAuthor)
|
176
|
+
project.data.setAuthor(projAuthor)
|
131
177
|
project.data.setDoBackup(doBackup)
|
132
178
|
project.data.setSpellLang(spellLang)
|
133
179
|
project.setProjectLang(projLang)
|
134
180
|
|
135
|
-
|
136
|
-
|
181
|
+
rebuildTrees = False
|
182
|
+
|
183
|
+
if self.statusPage.wasChanged:
|
184
|
+
newList, delList = self.statusPage.getNewList()
|
137
185
|
project.setStatusColours(newList, delList)
|
186
|
+
rebuildTrees = True
|
138
187
|
|
139
|
-
if self.
|
140
|
-
newList, delList = self.
|
188
|
+
if self.importPage.wasChanged:
|
189
|
+
newList, delList = self.importPage.getNewList()
|
141
190
|
project.setImportColours(newList, delList)
|
191
|
+
rebuildTrees = True
|
142
192
|
|
143
|
-
if self.
|
144
|
-
self.
|
145
|
-
|
146
|
-
if self.tabReplace.arChanged:
|
147
|
-
newList = self.tabReplace.getNewList()
|
193
|
+
if self.replacePage.wasChanged:
|
194
|
+
newList = self.replacePage.getNewList()
|
148
195
|
project.data.setAutoReplace(newList)
|
149
196
|
|
150
|
-
self.newProjectSettingsReady.emit()
|
197
|
+
self.newProjectSettingsReady.emit(rebuildTrees)
|
151
198
|
qApp.processEvents()
|
152
199
|
self.close()
|
153
200
|
|
@@ -157,134 +204,103 @@ class GuiProjectSettings(NPagedDialog):
|
|
157
204
|
# Internal Functions
|
158
205
|
##
|
159
206
|
|
160
|
-
def
|
161
|
-
"""Change which is the focused tab."""
|
162
|
-
if tab == self.TAB_MAIN:
|
163
|
-
self.setCurrentWidget(self.tabMain)
|
164
|
-
elif tab == self.TAB_STATUS:
|
165
|
-
self.setCurrentWidget(self.tabStatus)
|
166
|
-
elif tab == self.TAB_IMPORT:
|
167
|
-
self.setCurrentWidget(self.tabImport)
|
168
|
-
elif tab == self.TAB_REPLACE:
|
169
|
-
self.setCurrentWidget(self.tabReplace)
|
170
|
-
return
|
171
|
-
|
172
|
-
def _saveGuiSettings(self) -> None:
|
207
|
+
def _saveSettings(self) -> None:
|
173
208
|
"""Save GUI settings."""
|
174
209
|
winWidth = CONFIG.rpxInt(self.width())
|
175
210
|
winHeight = CONFIG.rpxInt(self.height())
|
176
|
-
|
177
|
-
|
178
|
-
|
211
|
+
statusColW = CONFIG.rpxInt(self.statusPage.columnWidth())
|
212
|
+
importColW = CONFIG.rpxInt(self.importPage.columnWidth())
|
213
|
+
replaceColW = CONFIG.rpxInt(self.replacePage.columnWidth())
|
179
214
|
|
180
215
|
logger.debug("Saving State: GuiProjectSettings")
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
216
|
+
options = SHARED.project.options
|
217
|
+
options.setValue("GuiProjectSettings", "winWidth", winWidth)
|
218
|
+
options.setValue("GuiProjectSettings", "winHeight", winHeight)
|
219
|
+
options.setValue("GuiProjectSettings", "statusColW", statusColW)
|
220
|
+
options.setValue("GuiProjectSettings", "importColW", importColW)
|
221
|
+
options.setValue("GuiProjectSettings", "replaceColW", replaceColW)
|
187
222
|
|
188
223
|
return
|
189
224
|
|
190
225
|
# END Class GuiProjectSettings
|
191
226
|
|
192
227
|
|
193
|
-
class
|
228
|
+
class _SettingsPage(NScrollableForm):
|
194
229
|
|
195
230
|
def __init__(self, parent: QWidget) -> None:
|
196
231
|
super().__init__(parent=parent)
|
197
232
|
|
198
|
-
|
199
|
-
|
200
|
-
self.
|
201
|
-
self.
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
self.
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
self.mainForm.addRow(
|
213
|
-
self.tr("Project name"),
|
214
|
-
self.editName,
|
215
|
-
self.tr("Should be set only once.")
|
233
|
+
xW = CONFIG.pxInt(200)
|
234
|
+
data = SHARED.project.data
|
235
|
+
self.setHelpTextStyle(SHARED.theme.helpText)
|
236
|
+
self.setRowIndent(0)
|
237
|
+
|
238
|
+
# Project Name
|
239
|
+
self.projName = QLineEdit(self)
|
240
|
+
self.projName.setMaxLength(200)
|
241
|
+
self.projName.setMinimumWidth(xW)
|
242
|
+
self.projName.setText(data.name)
|
243
|
+
self.addRow(
|
244
|
+
self.tr("Project name"), self.projName,
|
245
|
+
self.tr("Changing this will affect the backup path."),
|
246
|
+
stretch=(3, 2)
|
216
247
|
)
|
217
248
|
|
218
|
-
|
219
|
-
self.
|
220
|
-
self.
|
221
|
-
self.
|
222
|
-
self.
|
223
|
-
|
224
|
-
self.
|
225
|
-
self.tr("
|
249
|
+
# Project Author
|
250
|
+
self.projAuthor = QLineEdit(self)
|
251
|
+
self.projAuthor.setMaxLength(200)
|
252
|
+
self.projAuthor.setMinimumWidth(xW)
|
253
|
+
self.projAuthor.setText(data.author)
|
254
|
+
self.addRow(
|
255
|
+
self.tr("Author(s)"), self.projAuthor,
|
256
|
+
self.tr("Only used when building the manuscript."),
|
257
|
+
stretch=(3, 2)
|
226
258
|
)
|
227
259
|
|
228
|
-
|
229
|
-
self.
|
230
|
-
self.
|
231
|
-
self.editAuthor.setText(pData.author)
|
232
|
-
self.mainForm.addRow(
|
233
|
-
self.tr("Author(s)"),
|
234
|
-
self.editAuthor,
|
235
|
-
self.tr("Change whenever you want!")
|
236
|
-
)
|
237
|
-
|
238
|
-
self.projLang = QComboBox(self)
|
239
|
-
self.projLang.setMaximumWidth(xW)
|
260
|
+
# Project Language
|
261
|
+
self.projLang = NComboBox(self)
|
262
|
+
self.projLang.setMinimumWidth(xW)
|
240
263
|
for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
|
241
264
|
self.projLang.addItem(language, tag)
|
242
|
-
self.
|
243
|
-
self.tr("Project language"),
|
244
|
-
self.
|
245
|
-
|
265
|
+
self.addRow(
|
266
|
+
self.tr("Project language"), self.projLang,
|
267
|
+
self.tr("Only used when building the manuscript."),
|
268
|
+
stretch=(3, 2)
|
246
269
|
)
|
270
|
+
if (idx := self.projLang.findData(data.language)) != -1:
|
271
|
+
self.projLang.setCurrentIndex(idx)
|
247
272
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
if langIdx == -1:
|
252
|
-
langIdx = self.projLang.findData("en_GB")
|
253
|
-
if langIdx != -1:
|
254
|
-
self.projLang.setCurrentIndex(langIdx)
|
255
|
-
|
256
|
-
self.spellLang = QComboBox(self)
|
257
|
-
self.spellLang.setMaximumWidth(xW)
|
273
|
+
# Spell Check Language
|
274
|
+
self.spellLang = NComboBox(self)
|
275
|
+
self.spellLang.setMinimumWidth(xW)
|
258
276
|
self.spellLang.addItem(self.tr("Default"), "None")
|
259
277
|
if CONFIG.hasEnchant:
|
260
278
|
for tag, language in SHARED.spelling.listDictionaries():
|
261
279
|
self.spellLang.addItem(language, tag)
|
262
|
-
self.
|
263
|
-
self.tr("Spell check language"),
|
264
|
-
self.
|
265
|
-
|
280
|
+
self.addRow(
|
281
|
+
self.tr("Spell check language"), self.spellLang,
|
282
|
+
self.tr("Overrides main preferences."),
|
283
|
+
stretch=(3, 2)
|
266
284
|
)
|
285
|
+
if (idx := self.spellLang.findData(data.spellLang)) != -1:
|
286
|
+
self.spellLang.setCurrentIndex(idx)
|
267
287
|
|
268
|
-
|
269
|
-
if pData.spellLang is not None:
|
270
|
-
langIdx = self.spellLang.findData(pData.spellLang)
|
271
|
-
if langIdx != -1:
|
272
|
-
self.spellLang.setCurrentIndex(langIdx)
|
273
|
-
|
288
|
+
# Backup on Close
|
274
289
|
self.doBackup = NSwitch(self)
|
275
|
-
self.doBackup.setChecked(not
|
276
|
-
self.
|
277
|
-
self.tr("
|
278
|
-
self.doBackup,
|
290
|
+
self.doBackup.setChecked(not data.doBackup)
|
291
|
+
self.addRow(
|
292
|
+
self.tr("Disable backup on close"), self.doBackup,
|
279
293
|
self.tr("Overrides main preferences.")
|
280
294
|
)
|
281
295
|
|
296
|
+
self.finalise()
|
297
|
+
|
282
298
|
return
|
283
299
|
|
284
|
-
# END Class
|
300
|
+
# END Class _SettingsPage
|
285
301
|
|
286
302
|
|
287
|
-
class
|
303
|
+
class _StatusPage(NFixedPage):
|
288
304
|
|
289
305
|
COL_LABEL = 0
|
290
306
|
COL_USAGE = 1
|
@@ -297,57 +313,55 @@ class GuiProjectEditStatus(QWidget):
|
|
297
313
|
super().__init__(parent=parent)
|
298
314
|
|
299
315
|
if isStatus:
|
300
|
-
|
301
|
-
pageLabel = self.tr("Novel
|
316
|
+
status = SHARED.project.data.itemStatus
|
317
|
+
pageLabel = self.tr("Novel Document Status Levels")
|
302
318
|
colSetting = "statusColW"
|
303
319
|
else:
|
304
|
-
|
305
|
-
pageLabel = self.tr("Note
|
320
|
+
status = SHARED.project.data.itemImport
|
321
|
+
pageLabel = self.tr("Project Note Importance Levels")
|
306
322
|
colSetting = "importColW"
|
307
323
|
|
308
324
|
wCol0 = CONFIG.pxInt(
|
309
325
|
SHARED.project.options.getInt("GuiProjectSettings", colSetting, 130)
|
310
326
|
)
|
311
327
|
|
312
|
-
self.
|
313
|
-
self.
|
314
|
-
self.
|
328
|
+
self._changed = False
|
329
|
+
self._colDeleted = []
|
330
|
+
self._selColour = QColor(100, 100, 100)
|
315
331
|
|
316
332
|
self.iPx = SHARED.theme.baseIconSize
|
317
333
|
|
318
|
-
#
|
319
|
-
|
334
|
+
# Title
|
335
|
+
self.pageTitle = NColourLabel(
|
336
|
+
pageLabel, SHARED.theme.helpText, parent=self,
|
337
|
+
scale=NColourLabel.HEADER_SCALE
|
338
|
+
)
|
320
339
|
|
321
|
-
|
322
|
-
self.listBox
|
323
|
-
|
324
|
-
])
|
340
|
+
# List Box
|
341
|
+
self.listBox = QTreeWidget(self)
|
342
|
+
self.listBox.setHeaderLabels([self.tr("Label"), self.tr("Usage")])
|
325
343
|
self.listBox.itemSelectionChanged.connect(self._selectedItem)
|
326
344
|
self.listBox.setColumnWidth(self.COL_LABEL, wCol0)
|
327
345
|
self.listBox.setIndentation(0)
|
328
346
|
|
329
|
-
for key, entry in
|
347
|
+
for key, entry in status.items():
|
330
348
|
self._addItem(key, entry["name"], entry["cols"], entry["count"])
|
331
349
|
|
332
350
|
# List Controls
|
333
|
-
|
334
|
-
|
335
|
-
self.addButton = QPushButton(SHARED.theme.getIcon("add"), "")
|
351
|
+
self.addButton = QPushButton(SHARED.theme.getIcon("add"), "", self)
|
336
352
|
self.addButton.clicked.connect(self._newItem)
|
337
353
|
|
338
|
-
self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "")
|
354
|
+
self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "", self)
|
339
355
|
self.delButton.clicked.connect(self._delItem)
|
340
356
|
|
341
|
-
self.upButton = QPushButton(SHARED.theme.getIcon("up"), "")
|
357
|
+
self.upButton = QPushButton(SHARED.theme.getIcon("up"), "", self)
|
342
358
|
self.upButton.clicked.connect(lambda: self._moveItem(-1))
|
343
359
|
|
344
|
-
self.dnButton = QPushButton(SHARED.theme.getIcon("down"), "")
|
360
|
+
self.dnButton = QPushButton(SHARED.theme.getIcon("down"), "", self)
|
345
361
|
self.dnButton.clicked.connect(lambda: self._moveItem(1))
|
346
362
|
|
347
363
|
# Edit Form
|
348
|
-
|
349
|
-
|
350
|
-
self.editName = QLineEdit()
|
364
|
+
self.editName = QLineEdit(self)
|
351
365
|
self.editName.setMaxLength(40)
|
352
366
|
self.editName.setPlaceholderText(self.tr("Select item to edit"))
|
353
367
|
self.editName.setEnabled(False)
|
@@ -364,8 +378,6 @@ class GuiProjectEditStatus(QWidget):
|
|
364
378
|
self.saveButton.clicked.connect(self._saveItem)
|
365
379
|
|
366
380
|
# Assemble
|
367
|
-
# ========
|
368
|
-
|
369
381
|
self.listControls = QVBoxLayout()
|
370
382
|
self.listControls.addWidget(self.addButton)
|
371
383
|
self.listControls.addWidget(self.delButton)
|
@@ -387,16 +399,25 @@ class GuiProjectEditStatus(QWidget):
|
|
387
399
|
self.innerBox.addLayout(self.listControls)
|
388
400
|
|
389
401
|
self.outerBox = QVBoxLayout()
|
390
|
-
self.outerBox.addWidget(
|
402
|
+
self.outerBox.addWidget(self.pageTitle)
|
391
403
|
self.outerBox.addLayout(self.innerBox)
|
392
404
|
|
393
|
-
self.
|
405
|
+
self.setCentralLayout(self.outerBox)
|
394
406
|
|
395
407
|
return
|
396
408
|
|
409
|
+
@property
|
410
|
+
def wasChanged(self) -> bool:
|
411
|
+
"""The user changed these settings."""
|
412
|
+
return self._changed
|
413
|
+
|
414
|
+
##
|
415
|
+
# Methods
|
416
|
+
##
|
417
|
+
|
397
418
|
def getNewList(self) -> tuple[list, list]:
|
398
419
|
"""Return list of entries."""
|
399
|
-
if self.
|
420
|
+
if self._changed:
|
400
421
|
newList = []
|
401
422
|
for n in range(self.listBox.topLevelItemCount()):
|
402
423
|
item = self.listBox.topLevelItem(n)
|
@@ -406,10 +427,13 @@ class GuiProjectEditStatus(QWidget):
|
|
406
427
|
"name": item.text(self.COL_LABEL),
|
407
428
|
"cols": item.data(self.COL_LABEL, self.COL_ROLE),
|
408
429
|
})
|
409
|
-
return newList, self.
|
410
|
-
|
430
|
+
return newList, self._colDeleted
|
411
431
|
return [], []
|
412
432
|
|
433
|
+
def columnWidth(self) -> int:
|
434
|
+
"""Return the size of the header column."""
|
435
|
+
return self.listBox.columnWidth(0)
|
436
|
+
|
413
437
|
##
|
414
438
|
# Private Slots
|
415
439
|
##
|
@@ -417,12 +441,12 @@ class GuiProjectEditStatus(QWidget):
|
|
417
441
|
@pyqtSlot()
|
418
442
|
def _selectColour(self) -> None:
|
419
443
|
"""Open a dialog to select the status icon colour."""
|
420
|
-
if self.
|
444
|
+
if self._selColour is not None:
|
421
445
|
newCol = QColorDialog.getColor(
|
422
|
-
self.
|
446
|
+
self._selColour, self, self.tr("Select Colour")
|
423
447
|
)
|
424
448
|
if newCol.isValid():
|
425
|
-
self.
|
449
|
+
self._selColour = newCol
|
426
450
|
pixmap = QPixmap(self.iPx, self.iPx)
|
427
451
|
pixmap.fill(newCol)
|
428
452
|
self.colButton.setIcon(QIcon(pixmap))
|
@@ -433,7 +457,7 @@ class GuiProjectEditStatus(QWidget):
|
|
433
457
|
def _newItem(self) -> None:
|
434
458
|
"""Create a new status item."""
|
435
459
|
self._addItem(None, self.tr("New Item"), (100, 100, 100), 0)
|
436
|
-
self.
|
460
|
+
self._changed = True
|
437
461
|
return
|
438
462
|
|
439
463
|
@pyqtSlot()
|
@@ -446,8 +470,8 @@ class GuiProjectEditStatus(QWidget):
|
|
446
470
|
SHARED.error(self.tr("Cannot delete a status item that is in use."))
|
447
471
|
else:
|
448
472
|
self.listBox.takeTopLevelItem(iRow)
|
449
|
-
self.
|
450
|
-
self.
|
473
|
+
self._colDeleted.append(selItem.data(self.COL_LABEL, self.KEY_ROLE))
|
474
|
+
self._changed = True
|
451
475
|
return
|
452
476
|
|
453
477
|
@pyqtSlot()
|
@@ -458,9 +482,9 @@ class GuiProjectEditStatus(QWidget):
|
|
458
482
|
selItem.setText(self.COL_LABEL, simplified(self.editName.text()))
|
459
483
|
selItem.setIcon(self.COL_LABEL, self.colButton.icon())
|
460
484
|
selItem.setData(self.COL_LABEL, self.COL_ROLE, (
|
461
|
-
self.
|
485
|
+
self._selColour.red(), self._selColour.green(), self._selColour.blue()
|
462
486
|
))
|
463
|
-
self.
|
487
|
+
self._changed = True
|
464
488
|
return
|
465
489
|
|
466
490
|
@pyqtSlot()
|
@@ -474,7 +498,7 @@ class GuiProjectEditStatus(QWidget):
|
|
474
498
|
name = selItem.text(self.COL_LABEL)
|
475
499
|
pixmap = QPixmap(self.iPx, self.iPx)
|
476
500
|
pixmap.fill(QColor(*cols))
|
477
|
-
self.
|
501
|
+
self._selColour = QColor(*cols)
|
478
502
|
self.editName.setText(name)
|
479
503
|
self.colButton.setIcon(QIcon(pixmap))
|
480
504
|
self.editName.selectAll()
|
@@ -485,7 +509,7 @@ class GuiProjectEditStatus(QWidget):
|
|
485
509
|
else:
|
486
510
|
pixmap = QPixmap(self.iPx, self.iPx)
|
487
511
|
pixmap.fill(QColor(100, 100, 100))
|
488
|
-
self.
|
512
|
+
self._selColour = QColor(100, 100, 100)
|
489
513
|
self.editName.setText("")
|
490
514
|
self.colButton.setIcon(QIcon(pixmap))
|
491
515
|
self.editName.setEnabled(False)
|
@@ -498,16 +522,16 @@ class GuiProjectEditStatus(QWidget):
|
|
498
522
|
##
|
499
523
|
|
500
524
|
def _addItem(self, key: str | None, name: str,
|
501
|
-
|
525
|
+
colour: tuple[int, int, int], count: int) -> None:
|
502
526
|
"""Add a status item to the list."""
|
503
527
|
pixmap = QPixmap(self.iPx, self.iPx)
|
504
|
-
pixmap.fill(QColor(*
|
528
|
+
pixmap.fill(QColor(*colour))
|
505
529
|
|
506
530
|
item = QTreeWidgetItem()
|
507
531
|
item.setText(self.COL_LABEL, name)
|
508
532
|
item.setIcon(self.COL_LABEL, QIcon(pixmap))
|
509
533
|
item.setData(self.COL_LABEL, self.KEY_ROLE, key)
|
510
|
-
item.setData(self.COL_LABEL, self.COL_ROLE,
|
534
|
+
item.setData(self.COL_LABEL, self.COL_ROLE, colour)
|
511
535
|
item.setData(self.COL_LABEL, self.NUM_ROLE, count)
|
512
536
|
item.setText(self.COL_USAGE, self._usageString(count))
|
513
537
|
|
@@ -533,30 +557,29 @@ class GuiProjectEditStatus(QWidget):
|
|
533
557
|
|
534
558
|
if cItem is not None:
|
535
559
|
cItem.setSelected(True)
|
536
|
-
self.
|
560
|
+
self._changed = True
|
537
561
|
|
538
562
|
return
|
539
563
|
|
540
564
|
def _getSelectedItem(self) -> QTreeWidgetItem | None:
|
541
565
|
"""Get the currently selected item."""
|
542
|
-
|
543
|
-
|
544
|
-
return selItem[0]
|
566
|
+
if items := self.listBox.selectedItems():
|
567
|
+
return items[0]
|
545
568
|
return None
|
546
569
|
|
547
|
-
def _usageString(self,
|
570
|
+
def _usageString(self, count: int) -> str:
|
548
571
|
"""Generate usage string."""
|
549
|
-
if
|
572
|
+
if count == 0:
|
550
573
|
return self.tr("Not in use")
|
551
|
-
elif
|
574
|
+
elif count == 1:
|
552
575
|
return self.tr("Used once")
|
553
576
|
else:
|
554
|
-
return self.tr("Used by {0} items").format(
|
577
|
+
return self.tr("Used by {0} items").format(count)
|
555
578
|
|
556
|
-
# END Class
|
579
|
+
# END Class _StatusPage
|
557
580
|
|
558
581
|
|
559
|
-
class
|
582
|
+
class _ReplacePage(NFixedPage):
|
560
583
|
|
561
584
|
COL_KEY = 0
|
562
585
|
COL_REPL = 1
|
@@ -564,24 +587,24 @@ class GuiProjectEditReplace(QWidget):
|
|
564
587
|
def __init__(self, parent: QWidget) -> None:
|
565
588
|
super().__init__(parent=parent)
|
566
589
|
|
567
|
-
self.
|
590
|
+
self._changed = False
|
568
591
|
|
569
592
|
wCol0 = CONFIG.pxInt(
|
570
593
|
SHARED.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
|
571
594
|
)
|
572
|
-
pageLabel = self.tr("Text Replace List for Preview and Export")
|
573
595
|
|
574
|
-
#
|
575
|
-
|
596
|
+
# Title
|
597
|
+
self.pageTitle = NColourLabel(
|
598
|
+
self.tr("Text Auto-Replace for Preview and Build"),
|
599
|
+
SHARED.theme.helpText, parent=self, scale=NColourLabel.HEADER_SCALE
|
600
|
+
)
|
576
601
|
|
602
|
+
# List Box
|
577
603
|
self.listBox = QTreeWidget()
|
578
|
-
self.listBox.setHeaderLabels([
|
579
|
-
self.tr("Keyword"),
|
580
|
-
self.tr("Replace With"),
|
581
|
-
])
|
582
|
-
self.listBox.itemSelectionChanged.connect(self._selectedItem)
|
604
|
+
self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")])
|
583
605
|
self.listBox.setColumnWidth(self.COL_KEY, wCol0)
|
584
606
|
self.listBox.setIndentation(0)
|
607
|
+
self.listBox.itemSelectionChanged.connect(self._selectedItem)
|
585
608
|
|
586
609
|
for aKey, aVal in SHARED.project.data.autoReplace.items():
|
587
610
|
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
|
@@ -591,8 +614,6 @@ class GuiProjectEditReplace(QWidget):
|
|
591
614
|
self.listBox.setSortingEnabled(True)
|
592
615
|
|
593
616
|
# List Controls
|
594
|
-
# =============
|
595
|
-
|
596
617
|
self.addButton = QPushButton(SHARED.theme.getIcon("add"), "")
|
597
618
|
self.addButton.clicked.connect(self._addEntry)
|
598
619
|
|
@@ -600,14 +621,12 @@ class GuiProjectEditReplace(QWidget):
|
|
600
621
|
self.delButton.clicked.connect(self._delEntry)
|
601
622
|
|
602
623
|
# Edit Form
|
603
|
-
|
604
|
-
|
605
|
-
self.editKey = QLineEdit()
|
624
|
+
self.editKey = QLineEdit(self)
|
606
625
|
self.editKey.setPlaceholderText(self.tr("Select item to edit"))
|
607
626
|
self.editKey.setEnabled(False)
|
608
627
|
self.editKey.setMaxLength(40)
|
609
628
|
|
610
|
-
self.editValue = QLineEdit()
|
629
|
+
self.editValue = QLineEdit(self)
|
611
630
|
self.editValue.setEnabled(False)
|
612
631
|
self.editValue.setMaxLength(80)
|
613
632
|
|
@@ -615,8 +634,6 @@ class GuiProjectEditReplace(QWidget):
|
|
615
634
|
self.saveButton.clicked.connect(self._saveEntry)
|
616
635
|
|
617
636
|
# Assemble
|
618
|
-
# ========
|
619
|
-
|
620
637
|
self.listControls = QVBoxLayout()
|
621
638
|
self.listControls.addWidget(self.addButton)
|
622
639
|
self.listControls.addWidget(self.delButton)
|
@@ -636,50 +653,61 @@ class GuiProjectEditReplace(QWidget):
|
|
636
653
|
self.innerBox.addLayout(self.listControls)
|
637
654
|
|
638
655
|
self.outerBox = QVBoxLayout()
|
639
|
-
self.outerBox.addWidget(
|
656
|
+
self.outerBox.addWidget(self.pageTitle)
|
640
657
|
self.outerBox.addLayout(self.innerBox)
|
641
658
|
|
642
|
-
self.
|
659
|
+
self.setCentralLayout(self.outerBox)
|
643
660
|
|
644
661
|
return
|
645
662
|
|
663
|
+
@property
|
664
|
+
def wasChanged(self) -> bool:
|
665
|
+
"""The user changed these settings."""
|
666
|
+
return self._changed
|
667
|
+
|
668
|
+
##
|
669
|
+
# Methods
|
670
|
+
##
|
671
|
+
|
646
672
|
def getNewList(self) -> dict:
|
647
673
|
"""Extract the list from the widget."""
|
648
674
|
new = {}
|
649
675
|
for n in range(self.listBox.topLevelItemCount()):
|
650
|
-
tItem
|
651
|
-
if tItem is not None:
|
676
|
+
if tItem := self.listBox.topLevelItem(n):
|
652
677
|
aKey = self._stripNotAllowed(tItem.text(0))
|
653
678
|
aVal = tItem.text(1)
|
654
679
|
if len(aKey) > 0:
|
655
680
|
new[aKey] = aVal
|
656
681
|
return new
|
657
682
|
|
683
|
+
def columnWidth(self) -> int:
|
684
|
+
"""Return the size of the header column."""
|
685
|
+
return self.listBox.columnWidth(0)
|
686
|
+
|
658
687
|
##
|
659
|
-
#
|
688
|
+
# Private Slots
|
660
689
|
##
|
661
690
|
|
662
|
-
|
691
|
+
@pyqtSlot()
|
692
|
+
def _selectedItem(self) -> None:
|
663
693
|
"""Extract the details from the selected item and populate the
|
664
694
|
edit form.
|
665
695
|
"""
|
666
|
-
selItem
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
self.editKey.setFocus()
|
677
|
-
return True
|
696
|
+
if selItem := self._getSelectedItem():
|
697
|
+
editKey = self._stripNotAllowed(selItem.text(0))
|
698
|
+
editVal = selItem.text(1)
|
699
|
+
self.editKey.setText(editKey)
|
700
|
+
self.editValue.setText(editVal)
|
701
|
+
self.editKey.setEnabled(True)
|
702
|
+
self.editValue.setEnabled(True)
|
703
|
+
self.editKey.selectAll()
|
704
|
+
self.editKey.setFocus()
|
705
|
+
return
|
678
706
|
|
707
|
+
@pyqtSlot()
|
679
708
|
def _saveEntry(self) -> None:
|
680
709
|
"""Save the form data into the list widget."""
|
681
|
-
selItem
|
682
|
-
if selItem:
|
710
|
+
if selItem := self._getSelectedItem():
|
683
711
|
newKey = self.editKey.text()
|
684
712
|
newVal = self.editValue.text()
|
685
713
|
saveKey = self._stripNotAllowed(newKey)
|
@@ -691,38 +719,36 @@ class GuiProjectEditReplace(QWidget):
|
|
691
719
|
self.editKey.setEnabled(False)
|
692
720
|
self.editValue.setEnabled(False)
|
693
721
|
self.listBox.clearSelection()
|
694
|
-
self.
|
722
|
+
self._changed = True
|
695
723
|
return
|
696
724
|
|
725
|
+
@pyqtSlot()
|
697
726
|
def _addEntry(self) -> None:
|
698
727
|
"""Add a new list entry."""
|
699
728
|
saveKey = "<keyword%d>" % (self.listBox.topLevelItemCount() + 1)
|
700
|
-
|
701
|
-
newItem = QTreeWidgetItem([saveKey, newVal])
|
702
|
-
self.listBox.addTopLevelItem(newItem)
|
729
|
+
self.listBox.addTopLevelItem(QTreeWidgetItem([saveKey, ""]))
|
703
730
|
return
|
704
731
|
|
732
|
+
@pyqtSlot()
|
705
733
|
def _delEntry(self) -> None:
|
706
734
|
"""Delete the selected entry."""
|
707
|
-
selItem
|
708
|
-
if selItem:
|
735
|
+
if selItem := self._getSelectedItem():
|
709
736
|
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(selItem))
|
710
|
-
self.
|
737
|
+
self._changed = True
|
711
738
|
return
|
712
739
|
|
740
|
+
##
|
741
|
+
# Internal Functions
|
742
|
+
##
|
743
|
+
|
713
744
|
def _getSelectedItem(self) -> QTreeWidgetItem | None:
|
714
745
|
"""Extract the currently selected item."""
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
return selItem[0]
|
746
|
+
if items := self.listBox.selectedItems():
|
747
|
+
return items[0]
|
748
|
+
return None
|
719
749
|
|
720
750
|
def _stripNotAllowed(self, key: str) -> str:
|
721
751
|
"""Clean up the replace key string."""
|
722
|
-
|
723
|
-
for c in key:
|
724
|
-
if c.isalnum():
|
725
|
-
result += c
|
726
|
-
return result
|
752
|
+
return "".join(c for c in key if c.isalnum())
|
727
753
|
|
728
|
-
# END Class
|
754
|
+
# END Class _ReplacePage
|