novelWriter 2.1.1__py3-none-any.whl → 2.2rc1__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.1.1.dist-info → novelWriter-2.2rc1.dist-info}/METADATA +3 -3
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/RECORD +105 -76
- novelwriter/__init__.py +6 -24
- novelwriter/assets/i18n/project_de_DE.json +10 -0
- novelwriter/assets/i18n/project_en_GB.json +11 -0
- novelwriter/assets/i18n/project_en_US.json +10 -0
- novelwriter/assets/i18n/project_ja_JP.json +11 -1
- novelwriter/assets/i18n/project_nb_NO.json +10 -0
- novelwriter/assets/i18n/project_nn_NO.json +10 -0
- novelwriter/assets/icons/novelwriter.ico +0 -0
- novelwriter/assets/icons/novelwriter.svg +8 -183
- novelwriter/assets/icons/typicons_dark/icons.conf +17 -2
- novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +8 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +8 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +5 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +5 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +5 -0
- novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +17 -2
- novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +8 -0
- novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +8 -0
- novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +5 -0
- novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +5 -0
- novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +5 -0
- novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +4 -0
- novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
- novelwriter/assets/icons/x-novelwriter-project.svg +7 -206
- 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 +7 -0
- novelwriter/assets/text/release_notes.htm +7 -37
- novelwriter/common.py +22 -1
- novelwriter/config.py +27 -42
- novelwriter/constants.py +45 -7
- novelwriter/core/buildsettings.py +40 -24
- novelwriter/core/coretools.py +8 -1
- novelwriter/core/docbuild.py +2 -6
- novelwriter/core/index.py +264 -175
- novelwriter/core/options.py +8 -3
- novelwriter/core/project.py +2 -2
- novelwriter/core/projectdata.py +3 -3
- novelwriter/core/tohtml.py +60 -59
- novelwriter/core/tokenizer.py +110 -70
- novelwriter/core/tomd.py +51 -38
- novelwriter/core/toodt.py +184 -147
- novelwriter/dialogs/preferences.py +75 -106
- novelwriter/dialogs/projsettings.py +101 -110
- novelwriter/dialogs/updates.py +25 -14
- novelwriter/enum.py +28 -3
- novelwriter/extensions/novelselector.py +1 -1
- novelwriter/gui/doceditor.py +1345 -1235
- novelwriter/gui/dochighlight.py +98 -62
- novelwriter/gui/docviewer.py +151 -340
- novelwriter/gui/docviewerpanel.py +457 -0
- novelwriter/gui/editordocument.py +126 -0
- novelwriter/gui/mainmenu.py +350 -300
- novelwriter/gui/noveltree.py +101 -125
- novelwriter/gui/outline.py +154 -171
- novelwriter/gui/projtree.py +480 -380
- novelwriter/gui/sidebar.py +106 -75
- novelwriter/gui/statusbar.py +1 -1
- novelwriter/gui/theme.py +114 -75
- novelwriter/guimain.py +353 -254
- novelwriter/shared.py +36 -3
- novelwriter/tools/dictionaries.py +268 -0
- novelwriter/tools/manusbuild.py +17 -6
- novelwriter/tools/manuscript.py +11 -3
- novelwriter/tools/manussettings.py +0 -14
- novelwriter/tools/projwizard.py +16 -2
- novelwriter/tools/writingstats.py +1 -1
- novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-menu.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-menu.svg +0 -4
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/WHEEL +0 -0
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/top_level.txt +0 -0
novelwriter/guimain.py
CHANGED
@@ -30,11 +30,11 @@ from time import time
|
|
30
30
|
from pathlib import Path
|
31
31
|
from datetime import datetime
|
32
32
|
|
33
|
-
from PyQt5.QtCore import Qt, QTimer,
|
34
|
-
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
|
33
|
+
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
|
34
|
+
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
|
35
35
|
from PyQt5.QtWidgets import (
|
36
|
-
|
37
|
-
QStackedWidget, QVBoxLayout, QWidget
|
36
|
+
QDialog, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut,
|
37
|
+
QSplitter, QStackedWidget, QVBoxLayout, QWidget, qApp
|
38
38
|
)
|
39
39
|
|
40
40
|
from novelwriter import CONFIG, SHARED, __hexversion__
|
@@ -44,10 +44,11 @@ from novelwriter.gui.outline import GuiOutlineView
|
|
44
44
|
from novelwriter.gui.mainmenu import GuiMainMenu
|
45
45
|
from novelwriter.gui.projtree import GuiProjectView
|
46
46
|
from novelwriter.gui.doceditor import GuiDocEditor
|
47
|
-
from novelwriter.gui.docviewer import
|
47
|
+
from novelwriter.gui.docviewer import GuiDocViewer
|
48
48
|
from novelwriter.gui.noveltree import GuiNovelView
|
49
49
|
from novelwriter.gui.statusbar import GuiMainStatus
|
50
50
|
from novelwriter.gui.itemdetails import GuiItemDetails
|
51
|
+
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
|
51
52
|
from novelwriter.dialogs.about import GuiAbout
|
52
53
|
from novelwriter.dialogs.updates import GuiUpdates
|
53
54
|
from novelwriter.dialogs.projload import GuiProjectLoad
|
@@ -58,11 +59,12 @@ from novelwriter.dialogs.projsettings import GuiProjectSettings
|
|
58
59
|
from novelwriter.tools.lipsum import GuiLipsum
|
59
60
|
from novelwriter.tools.manuscript import GuiManuscript
|
60
61
|
from novelwriter.tools.projwizard import GuiProjectWizard
|
62
|
+
from novelwriter.tools.dictionaries import GuiDictionaries
|
61
63
|
from novelwriter.tools.writingstats import GuiWritingStats
|
62
64
|
from novelwriter.core.coretools import ProjectBuilder
|
63
65
|
|
64
66
|
from novelwriter.enum import (
|
65
|
-
nwDocAction, nwDocMode, nwItemType, nwItemClass, nwWidget, nwView
|
67
|
+
nwDocAction, nwDocInsert, nwDocMode, nwItemType, nwItemClass, nwWidget, nwView
|
66
68
|
)
|
67
69
|
from novelwriter.common import getGuiItem, hexToInt
|
68
70
|
from novelwriter.constants import nwFiles
|
@@ -95,7 +97,6 @@ class GuiMain(QMainWindow):
|
|
95
97
|
|
96
98
|
logger.debug("Create: GUI")
|
97
99
|
self.setObjectName("GuiMain")
|
98
|
-
self.threadPool = QThreadPool()
|
99
100
|
|
100
101
|
# System Info
|
101
102
|
# ===========
|
@@ -134,25 +135,25 @@ class GuiMain(QMainWindow):
|
|
134
135
|
hWd = CONFIG.pxInt(4)
|
135
136
|
|
136
137
|
# Main GUI Elements
|
137
|
-
self.mainStatus
|
138
|
-
self.projView
|
139
|
-
self.novelView
|
140
|
-
self.docEditor
|
141
|
-
self.
|
142
|
-
self.
|
143
|
-
self.itemDetails
|
144
|
-
self.outlineView
|
145
|
-
self.mainMenu
|
146
|
-
self.
|
138
|
+
self.mainStatus = GuiMainStatus(self)
|
139
|
+
self.projView = GuiProjectView(self)
|
140
|
+
self.novelView = GuiNovelView(self)
|
141
|
+
self.docEditor = GuiDocEditor(self)
|
142
|
+
self.docViewer = GuiDocViewer(self)
|
143
|
+
self.docViewerPanel = GuiDocViewerPanel(self)
|
144
|
+
self.itemDetails = GuiItemDetails(self)
|
145
|
+
self.outlineView = GuiOutlineView(self)
|
146
|
+
self.mainMenu = GuiMainMenu(self)
|
147
|
+
self.sideBar = GuiSideBar(self)
|
147
148
|
|
148
149
|
# Project Tree Stack
|
149
|
-
self.projStack = QStackedWidget()
|
150
|
+
self.projStack = QStackedWidget(self)
|
150
151
|
self.projStack.addWidget(self.projView)
|
151
152
|
self.projStack.addWidget(self.novelView)
|
152
153
|
self.projStack.currentChanged.connect(self._projStackChanged)
|
153
154
|
|
154
155
|
# Project Tree View
|
155
|
-
self.treePane = QWidget()
|
156
|
+
self.treePane = QWidget(self)
|
156
157
|
self.treeBox = QVBoxLayout()
|
157
158
|
self.treeBox.setContentsMargins(0, 0, 0, 0)
|
158
159
|
self.treeBox.setSpacing(mPx)
|
@@ -161,15 +162,15 @@ class GuiMain(QMainWindow):
|
|
161
162
|
self.treePane.setLayout(self.treeBox)
|
162
163
|
|
163
164
|
# Splitter : Document Viewer / Document Meta
|
164
|
-
self.splitView = QSplitter(Qt.Vertical)
|
165
|
+
self.splitView = QSplitter(Qt.Vertical, self)
|
165
166
|
self.splitView.addWidget(self.docViewer)
|
166
|
-
self.splitView.addWidget(self.
|
167
|
+
self.splitView.addWidget(self.docViewerPanel)
|
167
168
|
self.splitView.setHandleWidth(hWd)
|
168
169
|
self.splitView.setOpaqueResize(False)
|
169
170
|
self.splitView.setSizes(CONFIG.viewPanePos)
|
170
171
|
|
171
172
|
# Splitter : Document Editor / Document Viewer
|
172
|
-
self.splitDocs = QSplitter(Qt.Horizontal)
|
173
|
+
self.splitDocs = QSplitter(Qt.Horizontal, self)
|
173
174
|
self.splitDocs.addWidget(self.docEditor)
|
174
175
|
self.splitDocs.addWidget(self.splitView)
|
175
176
|
self.splitDocs.setOpaqueResize(False)
|
@@ -185,18 +186,18 @@ class GuiMain(QMainWindow):
|
|
185
186
|
self.splitMain.setSizes(CONFIG.mainPanePos)
|
186
187
|
|
187
188
|
# Main Stack : Editor / Outline
|
188
|
-
self.mainStack = QStackedWidget()
|
189
|
+
self.mainStack = QStackedWidget(self)
|
189
190
|
self.mainStack.addWidget(self.splitMain)
|
190
191
|
self.mainStack.addWidget(self.outlineView)
|
191
192
|
self.mainStack.currentChanged.connect(self._mainStackChanged)
|
192
193
|
|
193
194
|
# Indices of Splitter Widgets
|
194
|
-
self.idxTree
|
195
|
-
self.idxMain
|
196
|
-
self.idxEditor
|
197
|
-
self.idxViewer
|
198
|
-
self.idxViewDoc
|
199
|
-
self.
|
195
|
+
self.idxTree = self.splitMain.indexOf(self.treePane)
|
196
|
+
self.idxMain = self.splitMain.indexOf(self.splitDocs)
|
197
|
+
self.idxEditor = self.splitDocs.indexOf(self.docEditor)
|
198
|
+
self.idxViewer = self.splitDocs.indexOf(self.splitView)
|
199
|
+
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
|
200
|
+
self.idxViewDocPanel = self.splitView.indexOf(self.docViewerPanel)
|
200
201
|
|
201
202
|
# Indices of Stack Widgets
|
202
203
|
self.idxEditorView = self.mainStack.indexOf(self.splitMain)
|
@@ -210,7 +211,7 @@ class GuiMain(QMainWindow):
|
|
210
211
|
self.splitDocs.setCollapsible(self.idxEditor, False)
|
211
212
|
self.splitDocs.setCollapsible(self.idxViewer, False)
|
212
213
|
self.splitView.setCollapsible(self.idxViewDoc, False)
|
213
|
-
self.splitView.setCollapsible(self.
|
214
|
+
self.splitView.setCollapsible(self.idxViewDocPanel, False)
|
214
215
|
|
215
216
|
self.splitMain.setStretchFactor(self.idxTree, 0)
|
216
217
|
self.splitMain.setStretchFactor(self.idxMain, 1)
|
@@ -222,11 +223,19 @@ class GuiMain(QMainWindow):
|
|
222
223
|
# Initialise the Project Tree
|
223
224
|
self.rebuildTrees()
|
224
225
|
|
225
|
-
#
|
226
|
+
# Assemble Main Window Elements
|
227
|
+
self.mainBox = QHBoxLayout()
|
228
|
+
self.mainBox.addWidget(self.sideBar)
|
229
|
+
self.mainBox.addWidget(self.mainStack)
|
230
|
+
self.mainBox.setContentsMargins(0, 0, 0, 0)
|
231
|
+
self.mainBox.setSpacing(0)
|
232
|
+
|
233
|
+
self.mainWidget = QWidget(self)
|
234
|
+
self.mainWidget.setLayout(self.mainBox)
|
235
|
+
|
226
236
|
self.setMenuBar(self.mainMenu)
|
227
|
-
self.setCentralWidget(self.
|
237
|
+
self.setCentralWidget(self.mainWidget)
|
228
238
|
self.setStatusBar(self.mainStatus)
|
229
|
-
self.addToolBar(Qt.LeftToolBarArea, self.viewsBar)
|
230
239
|
self.setContextMenuPolicy(Qt.NoContextMenu) # Issue #1147
|
231
240
|
|
232
241
|
# Connect Signals
|
@@ -235,8 +244,20 @@ class GuiMain(QMainWindow):
|
|
235
244
|
SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
|
236
245
|
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
|
237
246
|
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
|
247
|
+
SHARED.indexChangedTags.connect(self.docViewerPanel.updateChangedTags)
|
248
|
+
SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged)
|
249
|
+
SHARED.indexScannedText.connect(self.projView.updateItemValues)
|
250
|
+
SHARED.indexScannedText.connect(self.itemDetails.updateViewBox)
|
251
|
+
SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared)
|
252
|
+
SHARED.indexAvailable.connect(self.docViewerPanel.indexHasAppeared)
|
238
253
|
|
239
|
-
self.
|
254
|
+
self.mainMenu.requestDocAction.connect(self._passDocumentAction)
|
255
|
+
self.mainMenu.requestDocInsert.connect(self._passDocumentInsert)
|
256
|
+
self.mainMenu.requestDocInsertText.connect(self._passDocumentInsert)
|
257
|
+
self.mainMenu.requestDocKeyWordInsert.connect(self.docEditor.insertKeyWord)
|
258
|
+
self.mainMenu.requestFocusChange.connect(self.switchFocus)
|
259
|
+
|
260
|
+
self.sideBar.viewChangeRequested.connect(self._changeView)
|
240
261
|
|
241
262
|
self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
242
263
|
self.projView.openDocumentRequest.connect(self._openDocument)
|
@@ -244,6 +265,7 @@ class GuiMain(QMainWindow):
|
|
244
265
|
self.projView.treeItemChanged.connect(self.docEditor.updateDocInfo)
|
245
266
|
self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
|
246
267
|
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
|
268
|
+
self.projView.treeItemChanged.connect(self.docViewerPanel.projectItemChanged)
|
247
269
|
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
|
248
270
|
self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
|
249
271
|
self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
|
@@ -259,8 +281,19 @@ class GuiMain(QMainWindow):
|
|
259
281
|
self.docEditor.novelStructureChanged.connect(self.novelView.refreshTree)
|
260
282
|
self.docEditor.novelItemMetaChanged.connect(self.novelView.updateNovelItemMeta)
|
261
283
|
self.docEditor.statusMessage.connect(self.mainStatus.setStatusMessage)
|
284
|
+
self.docEditor.spellCheckStateChanged.connect(self.mainMenu.setSpellCheckState)
|
285
|
+
self.docEditor.closeDocumentRequest.connect(self.closeDocEditor)
|
286
|
+
self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode)
|
287
|
+
self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
288
|
+
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
|
262
289
|
|
290
|
+
self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
|
263
291
|
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
|
292
|
+
self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility)
|
293
|
+
self.docViewer.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
294
|
+
|
295
|
+
self.docViewerPanel.loadDocumentTagRequest.connect(self._followTag)
|
296
|
+
self.docViewerPanel.openDocumentRequest.connect(self._openDocument)
|
264
297
|
|
265
298
|
self.outlineView.loadDocumentTagRequest.connect(self._followTag)
|
266
299
|
self.outlineView.openDocumentRequest.connect(self._openDocument)
|
@@ -269,15 +302,15 @@ class GuiMain(QMainWindow):
|
|
269
302
|
# =======================
|
270
303
|
|
271
304
|
# Set Up Auto-Save Project Timer
|
272
|
-
self.asProjTimer = QTimer()
|
305
|
+
self.asProjTimer = QTimer(self)
|
273
306
|
self.asProjTimer.timeout.connect(self._autoSaveProject)
|
274
307
|
|
275
308
|
# Set Up Auto-Save Document Timer
|
276
|
-
self.asDocTimer = QTimer()
|
309
|
+
self.asDocTimer = QTimer(self)
|
277
310
|
self.asDocTimer.timeout.connect(self._autoSaveDocument)
|
278
311
|
|
279
312
|
# Main Clock
|
280
|
-
self.mainTimer = QTimer()
|
313
|
+
self.mainTimer = QTimer(self)
|
281
314
|
self.mainTimer.setInterval(1000)
|
282
315
|
self.mainTimer.timeout.connect(self._timeTick)
|
283
316
|
self.mainTimer.start()
|
@@ -285,17 +318,17 @@ class GuiMain(QMainWindow):
|
|
285
318
|
# Shortcuts and Actions
|
286
319
|
self._connectMenuActions()
|
287
320
|
|
288
|
-
keyReturn = QShortcut(self)
|
289
|
-
keyReturn.setKey(
|
290
|
-
keyReturn.activated.connect(self._keyPressReturn)
|
321
|
+
self.keyReturn = QShortcut(self)
|
322
|
+
self.keyReturn.setKey(Qt.Key.Key_Return)
|
323
|
+
self.keyReturn.activated.connect(self._keyPressReturn)
|
291
324
|
|
292
|
-
keyEnter = QShortcut(self)
|
293
|
-
keyEnter.setKey(
|
294
|
-
keyEnter.activated.connect(self._keyPressReturn)
|
325
|
+
self.keyEnter = QShortcut(self)
|
326
|
+
self.keyEnter.setKey(Qt.Key.Key_Enter)
|
327
|
+
self.keyEnter.activated.connect(self._keyPressReturn)
|
295
328
|
|
296
|
-
keyEscape = QShortcut(self)
|
297
|
-
keyEscape.setKey(
|
298
|
-
keyEscape.activated.connect(self._keyPressEscape)
|
329
|
+
self.keyEscape = QShortcut(self)
|
330
|
+
self.keyEscape.setKey(Qt.Key.Key_Escape)
|
331
|
+
self.keyEscape.activated.connect(self._keyPressEscape)
|
299
332
|
|
300
333
|
# Check that config loaded fine
|
301
334
|
self.reportConfErr()
|
@@ -311,12 +344,12 @@ class GuiMain(QMainWindow):
|
|
311
344
|
|
312
345
|
logger.debug("Ready: GUI")
|
313
346
|
|
314
|
-
if __hexversion__[-2] == "a" and
|
315
|
-
SHARED.warn(
|
347
|
+
if __hexversion__[-2] == "a" and not CONFIG.isDebug:
|
348
|
+
SHARED.warn(
|
316
349
|
"You are running an untested development version of novelWriter. "
|
317
|
-
"Please be careful when working on
|
350
|
+
"Please be careful when you are working on live projects "
|
318
351
|
"and make sure you take regular backups."
|
319
|
-
)
|
352
|
+
)
|
320
353
|
|
321
354
|
logger.info("novelWriter is ready ...")
|
322
355
|
self.mainStatus.setStatusMessage(self.tr("novelWriter is ready ..."))
|
@@ -332,6 +365,7 @@ class GuiMain(QMainWindow):
|
|
332
365
|
def postLaunchTasks(self, cmdOpen: str | None) -> None:
|
333
366
|
"""Process tasks after the main window has been created."""
|
334
367
|
if cmdOpen:
|
368
|
+
qApp.processEvents()
|
335
369
|
logger.info("Command line path: %s", cmdOpen)
|
336
370
|
self.openProject(cmdOpen)
|
337
371
|
|
@@ -420,6 +454,7 @@ class GuiMain(QMainWindow):
|
|
420
454
|
self.docViewer.clearNavHistory()
|
421
455
|
self.closeDocViewer(byUser=False)
|
422
456
|
|
457
|
+
self.docViewerPanel.closeProjectTasks()
|
423
458
|
self.outlineView.closeProjectTasks()
|
424
459
|
self.novelView.closeProjectTasks()
|
425
460
|
self.projView.clearProjectView()
|
@@ -493,6 +528,7 @@ class GuiMain(QMainWindow):
|
|
493
528
|
self.projView.openProjectTasks()
|
494
529
|
self.novelView.openProjectTasks()
|
495
530
|
self.outlineView.openProjectTasks()
|
531
|
+
self.docViewerPanel.openProjectTasks()
|
496
532
|
self._updateStatusWordCount()
|
497
533
|
|
498
534
|
# Restore previously open documents, if any
|
@@ -505,10 +541,12 @@ class GuiMain(QMainWindow):
|
|
505
541
|
break
|
506
542
|
|
507
543
|
if lastEdited is not None:
|
544
|
+
qApp.processEvents()
|
508
545
|
self.openDocument(lastEdited, doScroll=True)
|
509
546
|
|
510
547
|
lastViewed = SHARED.project.data.getLastHandle("viewer")
|
511
548
|
if lastViewed is not None:
|
549
|
+
qApp.processEvents()
|
512
550
|
self.viewDocument(lastViewed)
|
513
551
|
|
514
552
|
# Check if we need to rebuild the index
|
@@ -610,10 +648,10 @@ class GuiMain(QMainWindow):
|
|
610
648
|
break
|
611
649
|
|
612
650
|
if nHandle is not None:
|
613
|
-
self.openDocument(nHandle, tLine=
|
651
|
+
self.openDocument(nHandle, tLine=1, doScroll=True)
|
614
652
|
return True
|
615
653
|
elif wrapAround:
|
616
|
-
self.openDocument(fHandle, tLine=
|
654
|
+
self.openDocument(fHandle, tLine=1, doScroll=True)
|
617
655
|
return False
|
618
656
|
|
619
657
|
return False
|
@@ -656,13 +694,19 @@ class GuiMain(QMainWindow):
|
|
656
694
|
logger.debug("Viewing document with handle '%s'", tHandle)
|
657
695
|
if self.docViewer.loadText(tHandle):
|
658
696
|
if not self.splitView.isVisible():
|
697
|
+
cursorVisible = self.docEditor.cursorIsVisible()
|
659
698
|
bPos = self.splitMain.sizes()
|
660
699
|
self.splitView.setVisible(True)
|
661
700
|
vPos = [0, 0]
|
662
701
|
vPos[0] = int(bPos[1]/2)
|
663
702
|
vPos[1] = bPos[1] - vPos[0]
|
664
703
|
self.splitDocs.setSizes(vPos)
|
665
|
-
self.
|
704
|
+
self.docViewerPanel.setVisible(CONFIG.showViewerPanel)
|
705
|
+
|
706
|
+
# Since editor width changes, we need to make sure we
|
707
|
+
# restore cursor visibility in the editor. See #1302
|
708
|
+
if cursorVisible:
|
709
|
+
self.docEditor.ensureCursorVisibleNoCentre()
|
666
710
|
|
667
711
|
if sTitle:
|
668
712
|
self.docViewer.navigateTo(f"#{sTitle}")
|
@@ -722,20 +766,6 @@ class GuiMain(QMainWindow):
|
|
722
766
|
|
723
767
|
return True
|
724
768
|
|
725
|
-
def passDocumentAction(self, action: nwDocAction) -> None:
|
726
|
-
"""Pass on document action to the document viewer if it has
|
727
|
-
focus, or pass it to the document editor if it or any of
|
728
|
-
its child widgets have focus. If neither has focus, ignore the
|
729
|
-
action.
|
730
|
-
"""
|
731
|
-
if self.docViewer.hasFocus():
|
732
|
-
self.docViewer.docAction(action)
|
733
|
-
elif self.docEditor.hasFocus():
|
734
|
-
self.docEditor.docAction(action)
|
735
|
-
else:
|
736
|
-
logger.debug("Action cancelled as neither editor nor viewer has focus")
|
737
|
-
return
|
738
|
-
|
739
769
|
##
|
740
770
|
# Tree Item Actions
|
741
771
|
##
|
@@ -777,11 +807,9 @@ class GuiMain(QMainWindow):
|
|
777
807
|
if not SHARED.hasProject:
|
778
808
|
logger.error("No project open")
|
779
809
|
return False
|
780
|
-
|
781
810
|
if tHandle is None and (self.docEditor.anyFocus() or self.isFocusMode):
|
782
811
|
tHandle = self.docEditor.docHandle
|
783
812
|
self.projView.renameTreeItem(tHandle)
|
784
|
-
|
785
813
|
return True
|
786
814
|
|
787
815
|
def rebuildTrees(self) -> None:
|
@@ -872,7 +900,8 @@ class GuiMain(QMainWindow):
|
|
872
900
|
SHARED.theme.loadTheme()
|
873
901
|
self.docEditor.updateTheme()
|
874
902
|
self.docViewer.updateTheme()
|
875
|
-
self.
|
903
|
+
self.docViewerPanel.updateTheme()
|
904
|
+
self.sideBar.updateTheme()
|
876
905
|
self.projView.updateTheme()
|
877
906
|
self.novelView.updateTheme()
|
878
907
|
self.outlineView.updateTheme()
|
@@ -1023,7 +1052,7 @@ class GuiMain(QMainWindow):
|
|
1023
1052
|
|
1024
1053
|
def showAboutQtDialog(self) -> None:
|
1025
1054
|
"""Show the about dialog for Qt."""
|
1026
|
-
msgBox = QMessageBox()
|
1055
|
+
msgBox = QMessageBox(self)
|
1027
1056
|
msgBox.aboutQt(self, "About Qt")
|
1028
1057
|
return
|
1029
1058
|
|
@@ -1042,6 +1071,20 @@ class GuiMain(QMainWindow):
|
|
1042
1071
|
|
1043
1072
|
return
|
1044
1073
|
|
1074
|
+
@pyqtSlot()
|
1075
|
+
def showDictionariesDialog(self) -> None:
|
1076
|
+
"""Show the download dictionaries dialog."""
|
1077
|
+
dlgDicts = GuiDictionaries(self)
|
1078
|
+
dlgDicts.setModal(True)
|
1079
|
+
dlgDicts.show()
|
1080
|
+
dlgDicts.raise_()
|
1081
|
+
qApp.processEvents()
|
1082
|
+
if not dlgDicts.initDialog():
|
1083
|
+
dlgDicts.close()
|
1084
|
+
SHARED.error(self.tr("Could not initialise the dialog."))
|
1085
|
+
|
1086
|
+
return
|
1087
|
+
|
1045
1088
|
def reportConfErr(self) -> bool:
|
1046
1089
|
"""Checks if the Config module has any errors to report, and let
|
1047
1090
|
the user know if this is the case. The Config module caches
|
@@ -1071,10 +1114,10 @@ class GuiMain(QMainWindow):
|
|
1071
1114
|
if not self.isFocusMode:
|
1072
1115
|
CONFIG.setMainPanePos(self.splitMain.sizes())
|
1073
1116
|
CONFIG.setOutlinePanePos(self.outlineView.splitSizes())
|
1074
|
-
if self.
|
1117
|
+
if self.docViewerPanel.isVisible():
|
1075
1118
|
CONFIG.setViewPanePos(self.splitView.sizes())
|
1076
1119
|
|
1077
|
-
CONFIG.
|
1120
|
+
CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
|
1078
1121
|
if self.windowState() & Qt.WindowFullScreen != Qt.WindowFullScreen:
|
1079
1122
|
# Ignore window size if in full screen mode
|
1080
1123
|
CONFIG.setMainWinSize(self.width(), self.height())
|
@@ -1089,31 +1132,6 @@ class GuiMain(QMainWindow):
|
|
1089
1132
|
|
1090
1133
|
return True
|
1091
1134
|
|
1092
|
-
def switchFocus(self, paneNo: nwWidget) -> None:
|
1093
|
-
"""Switch focus between main GUI views."""
|
1094
|
-
if paneNo == nwWidget.TREE:
|
1095
|
-
tabIdx = self.projStack.currentIndex()
|
1096
|
-
if tabIdx == self.idxProjView:
|
1097
|
-
self.projView.setFocus()
|
1098
|
-
elif tabIdx == self.idxNovelView:
|
1099
|
-
self.novelView.setTreeFocus()
|
1100
|
-
elif paneNo == nwWidget.EDITOR:
|
1101
|
-
self._changeView(nwView.EDITOR)
|
1102
|
-
self.docEditor.setFocus()
|
1103
|
-
elif paneNo == nwWidget.VIEWER:
|
1104
|
-
self._changeView(nwView.EDITOR)
|
1105
|
-
self.docViewer.setFocus()
|
1106
|
-
elif paneNo == nwWidget.OUTLINE:
|
1107
|
-
self._changeView(nwView.OUTLINE)
|
1108
|
-
self.outlineView.setTreeFocus()
|
1109
|
-
return
|
1110
|
-
|
1111
|
-
def closeDocEditor(self) -> None:
|
1112
|
-
"""Close the document editor. This does not hide the editor."""
|
1113
|
-
self.closeDocument()
|
1114
|
-
SHARED.project.data.setLastHandle(None, "editor")
|
1115
|
-
return
|
1116
|
-
|
1117
1135
|
def closeDocViewer(self, byUser: bool = True) -> bool:
|
1118
1136
|
"""Close the document view panel."""
|
1119
1137
|
self.docViewer.clearViewer()
|
@@ -1121,20 +1139,55 @@ class GuiMain(QMainWindow):
|
|
1121
1139
|
# Only reset the last handle if the user called this
|
1122
1140
|
SHARED.project.data.setLastHandle(None, "viewer")
|
1123
1141
|
|
1142
|
+
cursorVisible = self.docEditor.cursorIsVisible()
|
1143
|
+
|
1124
1144
|
# Hide the panel
|
1125
1145
|
bPos = self.splitMain.sizes()
|
1126
1146
|
self.splitView.setVisible(False)
|
1127
1147
|
self.splitDocs.setSizes([bPos[1], 0])
|
1128
1148
|
|
1149
|
+
# Since editor width changes, we need to make sure we restore
|
1150
|
+
# cursor visibility in the editor. See #1302
|
1151
|
+
if cursorVisible:
|
1152
|
+
self.docEditor.ensureCursorVisibleNoCentre()
|
1153
|
+
|
1129
1154
|
return not self.splitView.isVisible()
|
1130
1155
|
|
1131
|
-
def
|
1156
|
+
def toggleFullScreenMode(self) -> None:
|
1157
|
+
"""Toggle full screen mode"""
|
1158
|
+
self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
|
1159
|
+
return
|
1160
|
+
|
1161
|
+
##
|
1162
|
+
# Events
|
1163
|
+
##
|
1164
|
+
|
1165
|
+
def closeEvent(self, event: QCloseEvent):
|
1166
|
+
"""Capture the closing event of the GUI and call the close
|
1167
|
+
function to handle all the close process steps.
|
1168
|
+
"""
|
1169
|
+
event.accept() if self.closeMain() else event.ignore()
|
1170
|
+
return
|
1171
|
+
|
1172
|
+
##
|
1173
|
+
# Public Slots
|
1174
|
+
##
|
1175
|
+
|
1176
|
+
@pyqtSlot()
|
1177
|
+
def closeDocEditor(self) -> None:
|
1178
|
+
"""Close the document editor. This does not hide the editor."""
|
1179
|
+
self.closeDocument()
|
1180
|
+
SHARED.project.data.setLastHandle(None, "editor")
|
1181
|
+
return
|
1182
|
+
|
1183
|
+
@pyqtSlot()
|
1184
|
+
def toggleFocusMode(self) -> None:
|
1132
1185
|
"""Handle toggle focus mode. The Main GUI Focus Mode hides tree,
|
1133
1186
|
view, statusbar and menu.
|
1134
1187
|
"""
|
1135
1188
|
if self.docEditor.docHandle is None:
|
1136
1189
|
logger.error("No document open, so not activating Focus Mode")
|
1137
|
-
return
|
1190
|
+
return
|
1138
1191
|
|
1139
1192
|
self.isFocusMode = not self.isFocusMode
|
1140
1193
|
if self.isFocusMode:
|
@@ -1143,11 +1196,12 @@ class GuiMain(QMainWindow):
|
|
1143
1196
|
else:
|
1144
1197
|
logger.debug("Deactivating Focus Mode")
|
1145
1198
|
|
1199
|
+
cursorVisible = self.docEditor.cursorIsVisible()
|
1146
1200
|
isVisible = not self.isFocusMode
|
1147
1201
|
self.treePane.setVisible(isVisible)
|
1148
1202
|
self.mainStatus.setVisible(isVisible)
|
1149
1203
|
self.mainMenu.setVisible(isVisible)
|
1150
|
-
self.
|
1204
|
+
self.sideBar.setVisible(isVisible)
|
1151
1205
|
|
1152
1206
|
hideDocFooter = self.isFocusMode and CONFIG.hideFocusFooter
|
1153
1207
|
self.docEditor.docFooter.setVisible(not hideDocFooter)
|
@@ -1158,11 +1212,198 @@ class GuiMain(QMainWindow):
|
|
1158
1212
|
elif self.docViewer.docHandle is not None:
|
1159
1213
|
self.splitView.setVisible(True)
|
1160
1214
|
|
1161
|
-
|
1215
|
+
if cursorVisible:
|
1216
|
+
self.docEditor.ensureCursorVisibleNoCentre()
|
1217
|
+
|
1218
|
+
return
|
1219
|
+
|
1220
|
+
@pyqtSlot(nwWidget)
|
1221
|
+
def switchFocus(self, paneNo: nwWidget) -> None:
|
1222
|
+
"""Switch focus between main GUI views."""
|
1223
|
+
if paneNo == nwWidget.TREE:
|
1224
|
+
if self.projStack.currentWidget() is self.projView:
|
1225
|
+
if self.projView.treeHasFocus():
|
1226
|
+
self._changeView(nwView.NOVEL)
|
1227
|
+
self.novelView.setTreeFocus()
|
1228
|
+
else:
|
1229
|
+
self.projView.setTreeFocus()
|
1230
|
+
else:
|
1231
|
+
if self.novelView.treeHasFocus():
|
1232
|
+
self._changeView(nwView.PROJECT)
|
1233
|
+
self.projView.setTreeFocus()
|
1234
|
+
else:
|
1235
|
+
self.novelView.setTreeFocus()
|
1236
|
+
elif paneNo == nwWidget.EDITOR:
|
1237
|
+
self._changeView(nwView.EDITOR)
|
1238
|
+
self.docEditor.setFocus()
|
1239
|
+
elif paneNo == nwWidget.VIEWER:
|
1240
|
+
self._changeView(nwView.EDITOR)
|
1241
|
+
self.docViewer.setFocus()
|
1242
|
+
elif paneNo == nwWidget.OUTLINE:
|
1243
|
+
self._changeView(nwView.OUTLINE)
|
1244
|
+
self.outlineView.setTreeFocus()
|
1245
|
+
return
|
1246
|
+
|
1247
|
+
##
|
1248
|
+
# Private Slots
|
1249
|
+
##
|
1250
|
+
|
1251
|
+
@pyqtSlot(str, nwDocMode)
|
1252
|
+
def _followTag(self, tag: str, mode: nwDocMode) -> None:
|
1253
|
+
"""Follow a tag after user interaction with a link."""
|
1254
|
+
tHandle, sTitle = self._getTagSource(tag)
|
1255
|
+
if tHandle is not None:
|
1256
|
+
if mode == nwDocMode.EDIT:
|
1257
|
+
self.openDocument(tHandle)
|
1258
|
+
elif mode == nwDocMode.VIEW:
|
1259
|
+
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
1260
|
+
return
|
1261
|
+
|
1262
|
+
@pyqtSlot(str, nwDocMode, str, bool)
|
1263
|
+
def _openDocument(self, tHandle: str, mode: nwDocMode, sTitle: str, setFocus: bool) -> None:
|
1264
|
+
"""Handle an open document request."""
|
1265
|
+
if tHandle is not None:
|
1266
|
+
if mode == nwDocMode.EDIT:
|
1267
|
+
tLine = None
|
1268
|
+
hItem = SHARED.project.index.getItemHeader(tHandle, sTitle)
|
1269
|
+
if hItem is not None:
|
1270
|
+
tLine = hItem.line
|
1271
|
+
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
1272
|
+
elif mode == nwDocMode.VIEW:
|
1273
|
+
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
1274
|
+
return
|
1275
|
+
|
1276
|
+
@pyqtSlot(nwView)
|
1277
|
+
def _changeView(self, view: nwView) -> None:
|
1278
|
+
"""Handle the requested change of view from the GuiViewBar."""
|
1279
|
+
if view == nwView.EDITOR:
|
1280
|
+
# Only change the main stack, but not the project stack
|
1281
|
+
self.mainStack.setCurrentWidget(self.splitMain)
|
1282
|
+
elif view == nwView.PROJECT:
|
1283
|
+
self.mainStack.setCurrentWidget(self.splitMain)
|
1284
|
+
self.projStack.setCurrentWidget(self.projView)
|
1285
|
+
elif view == nwView.NOVEL:
|
1286
|
+
self.mainStack.setCurrentWidget(self.splitMain)
|
1287
|
+
self.projStack.setCurrentWidget(self.novelView)
|
1288
|
+
elif view == nwView.OUTLINE:
|
1289
|
+
self.mainStack.setCurrentWidget(self.outlineView)
|
1290
|
+
return
|
1291
|
+
|
1292
|
+
@pyqtSlot(nwDocAction)
|
1293
|
+
def _passDocumentAction(self, action: nwDocAction) -> None:
|
1294
|
+
"""Pass on a document action to the document viewer if it has
|
1295
|
+
focus, or pass it to the document editor if it or any of its
|
1296
|
+
child widgets have focus. If neither has focus, ignore it.
|
1297
|
+
"""
|
1298
|
+
if self.docViewer.hasFocus():
|
1299
|
+
self.docViewer.docAction(action)
|
1300
|
+
elif self.docEditor.hasFocus():
|
1301
|
+
self.docEditor.docAction(action)
|
1302
|
+
else:
|
1303
|
+
logger.debug("Action cancelled as neither editor nor viewer has focus")
|
1304
|
+
return
|
1305
|
+
|
1306
|
+
@pyqtSlot(str)
|
1307
|
+
@pyqtSlot(nwDocInsert)
|
1308
|
+
def _passDocumentInsert(self, content: str | nwDocInsert) -> None:
|
1309
|
+
"""Pass on a document insert action to the document editor if it
|
1310
|
+
has focus. If not, ignore it.
|
1311
|
+
"""
|
1312
|
+
if self.docEditor.hasFocus():
|
1313
|
+
self.docEditor.insertText(content)
|
1314
|
+
return
|
1315
|
+
|
1316
|
+
@pyqtSlot()
|
1317
|
+
def _toggleViewerPanelVisibility(self):
|
1318
|
+
"""Toggle the visibility of the document viewer panel."""
|
1319
|
+
CONFIG.showViewerPanel = not CONFIG.showViewerPanel
|
1320
|
+
self.docViewerPanel.setVisible(CONFIG.showViewerPanel)
|
1321
|
+
return
|
1322
|
+
|
1323
|
+
@pyqtSlot()
|
1324
|
+
def _timeTick(self) -> None:
|
1325
|
+
"""Process time tick of the main timer."""
|
1326
|
+
if not SHARED.hasProject:
|
1327
|
+
return
|
1328
|
+
currTime = time()
|
1329
|
+
editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime
|
1330
|
+
userIdle = qApp.applicationState() != Qt.ApplicationActive
|
1331
|
+
self.mainStatus.setUserIdle(editIdle or userIdle)
|
1332
|
+
SHARED.updateIdleTime(currTime, editIdle or userIdle)
|
1333
|
+
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
|
1334
|
+
return
|
1335
|
+
|
1336
|
+
@pyqtSlot()
|
1337
|
+
def _autoSaveProject(self) -> None:
|
1338
|
+
"""Autosave of the project. This is a timer-activated slot."""
|
1339
|
+
doSave = SHARED.hasProject
|
1340
|
+
doSave &= SHARED.project.projChanged
|
1341
|
+
doSave &= SHARED.project.storage.isOpen()
|
1342
|
+
if doSave:
|
1343
|
+
logger.debug("Autosaving project")
|
1344
|
+
self.saveProject(autoSave=True)
|
1345
|
+
return
|
1346
|
+
|
1347
|
+
@pyqtSlot()
|
1348
|
+
def _autoSaveDocument(self) -> None:
|
1349
|
+
"""Autosave of the document. This is a timer-activated slot."""
|
1350
|
+
if SHARED.hasProject and self.docEditor.docChanged:
|
1351
|
+
logger.debug("Autosaving document")
|
1352
|
+
self.saveDocument()
|
1353
|
+
return
|
1354
|
+
|
1355
|
+
@pyqtSlot()
|
1356
|
+
def _updateStatusWordCount(self) -> None:
|
1357
|
+
"""Update the word count on the status bar."""
|
1358
|
+
if not SHARED.hasProject:
|
1359
|
+
self.mainStatus.setProjectStats(0, 0)
|
1360
|
+
|
1361
|
+
SHARED.project.updateWordCounts()
|
1362
|
+
if CONFIG.incNotesWCount:
|
1363
|
+
iTotal = sum(SHARED.project.data.initCounts)
|
1364
|
+
cTotal = sum(SHARED.project.data.currCounts)
|
1365
|
+
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
|
1366
|
+
else:
|
1367
|
+
iNovel, _ = SHARED.project.data.initCounts
|
1368
|
+
cNovel, _ = SHARED.project.data.currCounts
|
1369
|
+
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
|
1162
1370
|
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1371
|
+
return
|
1372
|
+
|
1373
|
+
@pyqtSlot()
|
1374
|
+
def _keyPressReturn(self) -> None:
|
1375
|
+
"""Forward the return/enter keypress to the function that opens
|
1376
|
+
the currently selected item.
|
1377
|
+
"""
|
1378
|
+
self.openSelectedItem()
|
1379
|
+
return
|
1380
|
+
|
1381
|
+
@pyqtSlot()
|
1382
|
+
def _keyPressEscape(self) -> None:
|
1383
|
+
"""Process escape keypress in the main window."""
|
1384
|
+
if self.docEditor.docSearch.isVisible():
|
1385
|
+
self.docEditor.closeSearch()
|
1386
|
+
elif self.isFocusMode:
|
1387
|
+
self.toggleFocusMode()
|
1388
|
+
return
|
1389
|
+
|
1390
|
+
@pyqtSlot(int)
|
1391
|
+
def _mainStackChanged(self, index: int) -> None:
|
1392
|
+
"""Process main window tab change."""
|
1393
|
+
if index == self.idxOutlineView:
|
1394
|
+
if SHARED.hasProject:
|
1395
|
+
self.outlineView.refreshTree()
|
1396
|
+
return
|
1397
|
+
|
1398
|
+
@pyqtSlot(int)
|
1399
|
+
def _projStackChanged(self, index: int) -> None:
|
1400
|
+
"""Process project view tab change."""
|
1401
|
+
sHandle = None
|
1402
|
+
if index == self.idxProjView:
|
1403
|
+
sHandle = self.projView.getSelectedHandle()
|
1404
|
+
elif index == self.idxNovelView:
|
1405
|
+
sHandle, _ = self.novelView.getSelectedHandle()
|
1406
|
+
self.itemDetails.updateViewBox(sHandle)
|
1166
1407
|
return
|
1167
1408
|
|
1168
1409
|
##
|
@@ -1220,6 +1461,7 @@ class GuiMain(QMainWindow):
|
|
1220
1461
|
self.addAction(self.mainMenu.aInsTimes)
|
1221
1462
|
self.addAction(self.mainMenu.aInsDivide)
|
1222
1463
|
self.addAction(self.mainMenu.aInsSynopsis)
|
1464
|
+
self.addAction(self.mainMenu.aInsShort)
|
1223
1465
|
|
1224
1466
|
for mAction, _ in self.mainMenu.mInsKWItems.values():
|
1225
1467
|
self.addAction(mAction)
|
@@ -1299,6 +1541,12 @@ class GuiMain(QMainWindow):
|
|
1299
1541
|
projData["numChapters"] = newProj.field("numChapters")
|
1300
1542
|
projData["numScenes"] = newProj.field("numScenes")
|
1301
1543
|
|
1544
|
+
try:
|
1545
|
+
langIdx = newProj.field("projLang")
|
1546
|
+
projData["projLang"] = CONFIG.listLanguages(CONFIG.LANG_PROJ)[langIdx][0]
|
1547
|
+
except Exception:
|
1548
|
+
projData["projLang"] = "en_GB"
|
1549
|
+
|
1302
1550
|
return projData
|
1303
1551
|
|
1304
1552
|
def _getTagSource(self, tag: str) -> tuple[str | None, str | None]:
|
@@ -1317,153 +1565,4 @@ class GuiMain(QMainWindow):
|
|
1317
1565
|
return None, None
|
1318
1566
|
return tHandle, sTitle
|
1319
1567
|
|
1320
|
-
##
|
1321
|
-
# Events
|
1322
|
-
##
|
1323
|
-
|
1324
|
-
def closeEvent(self, event: QCloseEvent):
|
1325
|
-
"""Capture the closing event of the GUI and call the close
|
1326
|
-
function to handle all the close process steps.
|
1327
|
-
"""
|
1328
|
-
if self.closeMain():
|
1329
|
-
event.accept()
|
1330
|
-
else:
|
1331
|
-
event.ignore()
|
1332
|
-
return
|
1333
|
-
|
1334
|
-
##
|
1335
|
-
# Private Slots
|
1336
|
-
##
|
1337
|
-
|
1338
|
-
@pyqtSlot(str, nwDocMode)
|
1339
|
-
def _followTag(self, tag: str, mode: nwDocMode) -> None:
|
1340
|
-
"""Follow a tag after user interaction with a link."""
|
1341
|
-
tHandle, sTitle = self._getTagSource(tag)
|
1342
|
-
if tHandle is not None:
|
1343
|
-
if mode == nwDocMode.EDIT:
|
1344
|
-
self.openDocument(tHandle)
|
1345
|
-
elif mode == nwDocMode.VIEW:
|
1346
|
-
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
1347
|
-
return
|
1348
|
-
|
1349
|
-
@pyqtSlot(str, nwDocMode, str, bool)
|
1350
|
-
def _openDocument(self, tHandle: str, mode: nwDocMode, sTitle: str, setFocus: bool) -> None:
|
1351
|
-
"""Handle an open document request."""
|
1352
|
-
if tHandle is not None:
|
1353
|
-
if mode == nwDocMode.EDIT:
|
1354
|
-
tLine = None
|
1355
|
-
hItem = SHARED.project.index.getItemHeader(tHandle, sTitle)
|
1356
|
-
if hItem is not None:
|
1357
|
-
tLine = hItem.line
|
1358
|
-
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
1359
|
-
elif mode == nwDocMode.VIEW:
|
1360
|
-
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
1361
|
-
return
|
1362
|
-
|
1363
|
-
@pyqtSlot(nwView)
|
1364
|
-
def _changeView(self, view: nwView) -> None:
|
1365
|
-
"""Handle the requested change of view from the GuiViewBar."""
|
1366
|
-
if view == nwView.EDITOR:
|
1367
|
-
# Only change the main stack, but not the project stack
|
1368
|
-
self.mainStack.setCurrentWidget(self.splitMain)
|
1369
|
-
|
1370
|
-
elif view == nwView.PROJECT:
|
1371
|
-
self.mainStack.setCurrentWidget(self.splitMain)
|
1372
|
-
self.projStack.setCurrentWidget(self.projView)
|
1373
|
-
|
1374
|
-
elif view == nwView.NOVEL:
|
1375
|
-
self.mainStack.setCurrentWidget(self.splitMain)
|
1376
|
-
self.projStack.setCurrentWidget(self.novelView)
|
1377
|
-
|
1378
|
-
elif view == nwView.OUTLINE:
|
1379
|
-
self.mainStack.setCurrentWidget(self.outlineView)
|
1380
|
-
|
1381
|
-
return
|
1382
|
-
|
1383
|
-
@pyqtSlot()
|
1384
|
-
def _timeTick(self) -> None:
|
1385
|
-
"""Process time tick of the main timer."""
|
1386
|
-
if not SHARED.hasProject:
|
1387
|
-
return
|
1388
|
-
currTime = time()
|
1389
|
-
editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime
|
1390
|
-
userIdle = qApp.applicationState() != Qt.ApplicationActive
|
1391
|
-
self.mainStatus.setUserIdle(editIdle or userIdle)
|
1392
|
-
SHARED.updateIdleTime(currTime, editIdle or userIdle)
|
1393
|
-
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
|
1394
|
-
return
|
1395
|
-
|
1396
|
-
@pyqtSlot()
|
1397
|
-
def _autoSaveProject(self) -> None:
|
1398
|
-
"""Autosave of the project. This is a timer-activated slot."""
|
1399
|
-
doSave = SHARED.hasProject
|
1400
|
-
doSave &= SHARED.project.projChanged
|
1401
|
-
doSave &= SHARED.project.storage.isOpen()
|
1402
|
-
if doSave:
|
1403
|
-
logger.debug("Autosaving project")
|
1404
|
-
self.saveProject(autoSave=True)
|
1405
|
-
return
|
1406
|
-
|
1407
|
-
@pyqtSlot()
|
1408
|
-
def _autoSaveDocument(self) -> None:
|
1409
|
-
"""Autosave of the document. This is a timer-activated slot."""
|
1410
|
-
if SHARED.hasProject and self.docEditor.docChanged:
|
1411
|
-
logger.debug("Autosaving document")
|
1412
|
-
self.saveDocument()
|
1413
|
-
return
|
1414
|
-
|
1415
|
-
@pyqtSlot()
|
1416
|
-
def _updateStatusWordCount(self) -> None:
|
1417
|
-
"""Update the word count on the status bar."""
|
1418
|
-
if not SHARED.hasProject:
|
1419
|
-
self.mainStatus.setProjectStats(0, 0)
|
1420
|
-
|
1421
|
-
SHARED.project.updateWordCounts()
|
1422
|
-
if CONFIG.incNotesWCount:
|
1423
|
-
iTotal = sum(SHARED.project.data.initCounts)
|
1424
|
-
cTotal = sum(SHARED.project.data.currCounts)
|
1425
|
-
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
|
1426
|
-
else:
|
1427
|
-
iNovel, _ = SHARED.project.data.initCounts
|
1428
|
-
cNovel, _ = SHARED.project.data.currCounts
|
1429
|
-
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
|
1430
|
-
|
1431
|
-
return
|
1432
|
-
|
1433
|
-
@pyqtSlot()
|
1434
|
-
def _keyPressReturn(self) -> None:
|
1435
|
-
"""Forward the return/enter keypress to the function that opens
|
1436
|
-
the currently selected item.
|
1437
|
-
"""
|
1438
|
-
self.openSelectedItem()
|
1439
|
-
return
|
1440
|
-
|
1441
|
-
@pyqtSlot()
|
1442
|
-
def _keyPressEscape(self) -> None:
|
1443
|
-
"""Process escape keypress in the main window."""
|
1444
|
-
if self.docEditor.docSearch.isVisible():
|
1445
|
-
self.docEditor.closeSearch()
|
1446
|
-
elif self.isFocusMode:
|
1447
|
-
self.toggleFocusMode()
|
1448
|
-
return
|
1449
|
-
|
1450
|
-
@pyqtSlot(int)
|
1451
|
-
def _mainStackChanged(self, index: int) -> None:
|
1452
|
-
"""Process main window tab change."""
|
1453
|
-
if index == self.idxOutlineView:
|
1454
|
-
if SHARED.hasProject:
|
1455
|
-
self.outlineView.refreshTree()
|
1456
|
-
return
|
1457
|
-
|
1458
|
-
@pyqtSlot(int)
|
1459
|
-
def _projStackChanged(self, index: int) -> None:
|
1460
|
-
"""Process project view tab change."""
|
1461
|
-
sHandle = None
|
1462
|
-
if index == self.idxProjView:
|
1463
|
-
sHandle = self.projView.getSelectedHandle()
|
1464
|
-
elif index == self.idxNovelView:
|
1465
|
-
sHandle, _ = self.novelView.getSelectedHandle()
|
1466
|
-
self.itemDetails.updateViewBox(sHandle)
|
1467
|
-
return
|
1468
|
-
|
1469
1568
|
# END Class GuiMain
|