novelWriter 2.4.4__py3-none-any.whl → 2.5__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.4.4.dist-info → novelWriter-2.5.dist-info}/METADATA +4 -5
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/RECORD +121 -111
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +33 -39
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/i18n/project_pl_PL.json +116 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
- novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +2 -0
- novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
- novelwriter/assets/syntax/default_dark.conf +32 -18
- novelwriter/assets/syntax/default_light.conf +24 -10
- novelwriter/assets/syntax/dracula.conf +44 -0
- novelwriter/assets/syntax/grey_dark.conf +5 -4
- novelwriter/assets/syntax/grey_light.conf +5 -4
- novelwriter/assets/syntax/light_owl.conf +7 -6
- novelwriter/assets/syntax/night_owl.conf +7 -6
- novelwriter/assets/syntax/snazzy.conf +42 -0
- novelwriter/assets/syntax/solarized_dark.conf +4 -3
- novelwriter/assets/syntax/solarized_light.conf +4 -3
- novelwriter/assets/syntax/tango.conf +27 -11
- novelwriter/assets/syntax/tomorrow.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night.conf +7 -6
- novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
- novelwriter/assets/text/credits_en.htm +52 -41
- novelwriter/assets/themes/cyberpunk_night.conf +3 -0
- novelwriter/assets/themes/default_dark.conf +2 -0
- novelwriter/assets/themes/default_light.conf +2 -0
- novelwriter/assets/themes/dracula.conf +48 -0
- novelwriter/assets/themes/solarized_dark.conf +2 -0
- novelwriter/assets/themes/solarized_light.conf +2 -0
- novelwriter/common.py +33 -12
- novelwriter/config.py +184 -98
- novelwriter/constants.py +47 -35
- novelwriter/core/buildsettings.py +68 -69
- novelwriter/core/coretools.py +5 -23
- novelwriter/core/docbuild.py +52 -40
- novelwriter/core/document.py +3 -5
- novelwriter/core/index.py +115 -45
- novelwriter/core/item.py +8 -19
- novelwriter/core/options.py +2 -4
- novelwriter/core/project.py +37 -61
- novelwriter/core/projectdata.py +1 -3
- novelwriter/core/projectxml.py +12 -15
- novelwriter/core/sessions.py +3 -5
- novelwriter/core/spellcheck.py +4 -9
- novelwriter/core/status.py +211 -164
- novelwriter/core/storage.py +0 -8
- novelwriter/core/tohtml.py +139 -105
- novelwriter/core/tokenizer.py +278 -122
- novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
- novelwriter/core/toodt.py +257 -166
- novelwriter/core/toqdoc.py +419 -0
- novelwriter/core/tree.py +5 -7
- novelwriter/dialogs/about.py +11 -18
- novelwriter/dialogs/docmerge.py +17 -19
- novelwriter/dialogs/docsplit.py +17 -19
- novelwriter/dialogs/editlabel.py +6 -10
- novelwriter/dialogs/preferences.py +200 -164
- novelwriter/dialogs/projectsettings.py +225 -189
- novelwriter/dialogs/quotes.py +12 -9
- novelwriter/dialogs/wordlist.py +9 -15
- novelwriter/enum.py +35 -30
- novelwriter/error.py +8 -15
- novelwriter/extensions/configlayout.py +55 -21
- novelwriter/extensions/eventfilters.py +1 -5
- novelwriter/extensions/modified.py +58 -14
- novelwriter/extensions/novelselector.py +1 -3
- novelwriter/extensions/pagedsidebar.py +9 -12
- novelwriter/extensions/{circularprogress.py → progressbars.py} +30 -8
- novelwriter/extensions/statusled.py +40 -26
- novelwriter/extensions/switch.py +4 -6
- novelwriter/extensions/switchbox.py +7 -6
- novelwriter/extensions/versioninfo.py +3 -9
- novelwriter/gui/doceditor.py +120 -139
- novelwriter/gui/dochighlight.py +231 -186
- novelwriter/gui/docviewer.py +69 -108
- novelwriter/gui/docviewerpanel.py +3 -10
- novelwriter/gui/editordocument.py +1 -3
- novelwriter/gui/itemdetails.py +7 -11
- novelwriter/gui/mainmenu.py +22 -18
- novelwriter/gui/noveltree.py +11 -24
- novelwriter/gui/outline.py +15 -26
- novelwriter/gui/projtree.py +35 -60
- novelwriter/gui/search.py +10 -3
- novelwriter/gui/sidebar.py +2 -6
- novelwriter/gui/statusbar.py +29 -37
- novelwriter/gui/theme.py +26 -48
- novelwriter/guimain.py +162 -160
- novelwriter/shared.py +36 -32
- novelwriter/text/patterns.py +113 -0
- novelwriter/tools/dictionaries.py +10 -20
- novelwriter/tools/lipsum.py +10 -16
- novelwriter/tools/manusbuild.py +9 -11
- novelwriter/tools/manuscript.py +71 -145
- novelwriter/tools/manussettings.py +71 -75
- novelwriter/tools/noveldetails.py +16 -21
- novelwriter/tools/welcome.py +21 -26
- novelwriter/tools/writingstats.py +9 -12
- novelwriter/types.py +49 -4
- novelwriter/extensions/simpleprogress.py +0 -55
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/top_level.txt +0 -0
novelwriter/guimain.py
CHANGED
@@ -23,18 +23,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
23
23
|
"""
|
24
24
|
from __future__ import annotations
|
25
25
|
|
26
|
-
import sys
|
27
26
|
import logging
|
27
|
+
import sys
|
28
28
|
|
29
|
-
from time import time
|
30
|
-
from pathlib import Path
|
31
29
|
from datetime import datetime
|
30
|
+
from pathlib import Path
|
31
|
+
from time import time
|
32
32
|
|
33
33
|
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
|
34
34
|
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
|
35
35
|
from PyQt5.QtWidgets import (
|
36
|
-
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox,
|
37
|
-
QStackedWidget, QVBoxLayout, QWidget
|
36
|
+
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox,
|
37
|
+
QShortcut, QSplitter, QStackedWidget, QVBoxLayout, QWidget
|
38
38
|
)
|
39
39
|
|
40
40
|
from novelwriter import CONFIG, SHARED, __hexversion__, __version__
|
@@ -44,7 +44,7 @@ from novelwriter.dialogs.about import GuiAbout
|
|
44
44
|
from novelwriter.dialogs.preferences import GuiPreferences
|
45
45
|
from novelwriter.dialogs.projectsettings import GuiProjectSettings
|
46
46
|
from novelwriter.dialogs.wordlist import GuiWordList
|
47
|
-
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode,
|
47
|
+
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwFocus, nwItemType, nwView
|
48
48
|
from novelwriter.gui.doceditor import GuiDocEditor
|
49
49
|
from novelwriter.gui.docviewer import GuiDocViewer
|
50
50
|
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
|
@@ -210,66 +210,68 @@ class GuiMain(QMainWindow):
|
|
210
210
|
# Connect Signals
|
211
211
|
# ===============
|
212
212
|
|
213
|
-
SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
|
214
|
-
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
|
215
|
-
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
|
216
213
|
SHARED.focusModeChanged.connect(self._focusModeChanged)
|
214
|
+
SHARED.indexAvailable.connect(self.docViewerPanel.indexHasAppeared)
|
215
|
+
SHARED.indexChangedTags.connect(self.docEditor.updateChangedTags)
|
217
216
|
SHARED.indexChangedTags.connect(self.docViewerPanel.updateChangedTags)
|
217
|
+
SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared)
|
218
218
|
SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged)
|
219
|
-
SHARED.indexScannedText.connect(self.projView.updateItemValues)
|
220
219
|
SHARED.indexScannedText.connect(self.itemDetails.updateViewBox)
|
221
|
-
SHARED.
|
222
|
-
SHARED.indexAvailable.connect(self.docViewerPanel.indexHasAppeared)
|
220
|
+
SHARED.indexScannedText.connect(self.projView.updateItemValues)
|
223
221
|
SHARED.mainClockTick.connect(self._timeTick)
|
222
|
+
SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
|
223
|
+
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
|
224
|
+
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
|
224
225
|
|
225
226
|
self.mainMenu.requestDocAction.connect(self._passDocumentAction)
|
226
227
|
self.mainMenu.requestDocInsert.connect(self._passDocumentInsert)
|
227
228
|
self.mainMenu.requestDocInsertText.connect(self._passDocumentInsert)
|
228
229
|
self.mainMenu.requestDocKeyWordInsert.connect(self.docEditor.insertKeyWord)
|
229
|
-
self.mainMenu.requestFocusChange.connect(self.
|
230
|
+
self.mainMenu.requestFocusChange.connect(self._switchFocus)
|
230
231
|
self.mainMenu.requestViewChange.connect(self._changeView)
|
231
232
|
|
232
233
|
self.sideBar.requestViewChange.connect(self._changeView)
|
233
234
|
|
234
|
-
self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
235
235
|
self.projView.openDocumentRequest.connect(self._openDocument)
|
236
|
-
self.projView.
|
236
|
+
self.projView.projectSettingsRequest.connect(self.showProjectSettingsDialog)
|
237
|
+
self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
|
238
|
+
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
|
239
|
+
self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
|
240
|
+
self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
237
241
|
self.projView.treeItemChanged.connect(self.docEditor.updateDocInfo)
|
238
242
|
self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
|
239
|
-
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
|
240
243
|
self.projView.treeItemChanged.connect(self.docViewerPanel.projectItemChanged)
|
241
|
-
self.projView.
|
242
|
-
self.projView.
|
243
|
-
self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
|
244
|
-
self.projView.projectSettingsRequest.connect(self.showProjectSettingsDialog)
|
244
|
+
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
|
245
|
+
self.projView.wordCountsChanged.connect(self._updateStatusWordCount)
|
245
246
|
|
246
|
-
self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
247
247
|
self.novelView.openDocumentRequest.connect(self._openDocument)
|
248
|
+
self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
248
249
|
|
249
250
|
self.projSearch.openDocumentSelectRequest.connect(self._openDocumentSelection)
|
250
251
|
self.projSearch.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
251
252
|
|
252
|
-
self.docEditor.
|
253
|
+
self.docEditor.closeDocumentRequest.connect(self.closeDocEditor)
|
253
254
|
self.docEditor.docCountsChanged.connect(self.itemDetails.updateCounts)
|
254
255
|
self.docEditor.docCountsChanged.connect(self.projView.updateCounts)
|
256
|
+
self.docEditor.docTextChanged.connect(self.projSearch.textChanged)
|
257
|
+
self.docEditor.editedStatusChanged.connect(self.mainStatus.updateDocumentStatus)
|
255
258
|
self.docEditor.loadDocumentTagRequest.connect(self._followTag)
|
256
|
-
self.docEditor.novelStructureChanged.connect(self.novelView.refreshTree)
|
257
259
|
self.docEditor.novelItemMetaChanged.connect(self.novelView.updateNovelItemMeta)
|
258
|
-
self.docEditor.
|
260
|
+
self.docEditor.novelStructureChanged.connect(self.novelView.refreshTree)
|
261
|
+
self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote)
|
262
|
+
self.docEditor.requestNextDocument.connect(self.openNextDocument)
|
263
|
+
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
|
264
|
+
self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
259
265
|
self.docEditor.spellCheckStateChanged.connect(self.mainMenu.setSpellCheckState)
|
260
|
-
self.docEditor.
|
266
|
+
self.docEditor.statusMessage.connect(self.mainStatus.setStatusMessage)
|
261
267
|
self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode)
|
262
|
-
self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
263
|
-
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
|
264
|
-
self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote)
|
265
|
-
self.docEditor.docTextChanged.connect(self.projSearch.textChanged)
|
266
268
|
|
269
|
+
self.docViewer.closeDocumentRequest.connect(self.closeDocViewer)
|
267
270
|
self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
|
268
271
|
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
|
269
|
-
self.docViewer.closeDocumentRequest.connect(self.closeDocViewer)
|
270
272
|
self.docViewer.reloadDocumentRequest.connect(self._reloadViewer)
|
271
|
-
self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility)
|
272
273
|
self.docViewer.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
274
|
+
self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility)
|
273
275
|
|
274
276
|
self.docViewerPanel.loadDocumentTagRequest.connect(self._followTag)
|
275
277
|
self.docViewerPanel.openDocumentRequest.connect(self._openDocument)
|
@@ -303,9 +305,6 @@ class GuiMain(QMainWindow):
|
|
303
305
|
self.keyEscape.setKey(Qt.Key.Key_Escape)
|
304
306
|
self.keyEscape.activated.connect(self._keyPressEscape)
|
305
307
|
|
306
|
-
# Check that config loaded fine
|
307
|
-
self.reportConfErr()
|
308
|
-
|
309
308
|
# Initialise Main GUI
|
310
309
|
self.initMain()
|
311
310
|
self.asProjTimer.start()
|
@@ -327,6 +326,15 @@ class GuiMain(QMainWindow):
|
|
327
326
|
|
328
327
|
def postLaunchTasks(self, cmdOpen: str | None) -> None:
|
329
328
|
"""Process tasks after the main window has been created."""
|
329
|
+
QApplication.processEvents()
|
330
|
+
app = QApplication.instance()
|
331
|
+
if isinstance(app, QApplication):
|
332
|
+
app.focusChanged.connect(self._appFocusChanged)
|
333
|
+
|
334
|
+
# Check that config loaded fine
|
335
|
+
if CONFIG.hasError:
|
336
|
+
SHARED.error(CONFIG.errorText())
|
337
|
+
|
330
338
|
if cmdOpen:
|
331
339
|
QApplication.processEvents()
|
332
340
|
logger.info("Command line path: %s", cmdOpen)
|
@@ -369,9 +377,7 @@ class GuiMain(QMainWindow):
|
|
369
377
|
if not msgYes:
|
370
378
|
return False
|
371
379
|
|
372
|
-
|
373
|
-
self.saveDocument()
|
374
|
-
|
380
|
+
self.saveDocument()
|
375
381
|
saveOK = self.saveProject()
|
376
382
|
doBackup = False
|
377
383
|
if SHARED.project.data.doBackup and CONFIG.backupOnClose:
|
@@ -514,9 +520,7 @@ class GuiMain(QMainWindow):
|
|
514
520
|
# Disable focus mode if it is active
|
515
521
|
if SHARED.focusMode:
|
516
522
|
SHARED.setFocusMode(False)
|
517
|
-
self.
|
518
|
-
if self.docEditor.docChanged:
|
519
|
-
self.saveDocument()
|
523
|
+
self.saveDocument()
|
520
524
|
self.docEditor.clearEditor()
|
521
525
|
if not beforeOpen:
|
522
526
|
self.novelView.setActiveHandle(None)
|
@@ -553,42 +557,43 @@ class GuiMain(QMainWindow):
|
|
553
557
|
|
554
558
|
return True
|
555
559
|
|
556
|
-
|
560
|
+
@pyqtSlot(str, bool)
|
561
|
+
def openNextDocument(self, tHandle: str, wrapAround: bool) -> None:
|
557
562
|
"""Open the next document in the project tree, following the
|
558
563
|
document with the given handle. Stop when reaching the end.
|
559
564
|
"""
|
560
|
-
if
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
nHandle =
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
self.openDocument(nHandle, tLine=1, doScroll=True)
|
580
|
-
return True
|
581
|
-
elif wrapAround:
|
582
|
-
self.openDocument(fHandle, tLine=1, doScroll=True)
|
583
|
-
return False
|
584
|
-
|
585
|
-
return False
|
565
|
+
if SHARED.hasProject:
|
566
|
+
nHandle = None # The next handle after tHandle
|
567
|
+
fHandle = None # The first file handle we encounter
|
568
|
+
foundIt = False # We've found tHandle, pick the next we see
|
569
|
+
for tItem in SHARED.project.tree:
|
570
|
+
if not tItem.isFileType():
|
571
|
+
continue
|
572
|
+
if fHandle is None:
|
573
|
+
fHandle = tItem.itemHandle
|
574
|
+
if tItem.itemHandle == tHandle:
|
575
|
+
foundIt = True
|
576
|
+
elif foundIt:
|
577
|
+
nHandle = tItem.itemHandle
|
578
|
+
break
|
579
|
+
if nHandle is not None:
|
580
|
+
self.openDocument(nHandle, tLine=1, doScroll=True)
|
581
|
+
elif wrapAround:
|
582
|
+
self.openDocument(fHandle, tLine=1, doScroll=True)
|
583
|
+
return
|
586
584
|
|
587
|
-
|
588
|
-
def saveDocument(self) -> None:
|
585
|
+
def saveDocument(self, force: bool = False) -> None:
|
589
586
|
"""Save the current documents."""
|
590
587
|
if SHARED.hasProject:
|
591
|
-
self.docEditor.
|
588
|
+
self.docEditor.saveCursorPosition()
|
589
|
+
if force or self.docEditor.docChanged:
|
590
|
+
self.docEditor.saveText()
|
591
|
+
return
|
592
|
+
|
593
|
+
@pyqtSlot()
|
594
|
+
def forceSaveDocument(self) -> None:
|
595
|
+
"""Save document even of it has not changed."""
|
596
|
+
self.saveDocument(force=True)
|
592
597
|
return
|
593
598
|
|
594
599
|
def viewDocument(self, tHandle: str | None = None, sTitle: str | None = None) -> bool:
|
@@ -618,6 +623,10 @@ class GuiMain(QMainWindow):
|
|
618
623
|
# Make sure main tab is in Editor view
|
619
624
|
self._changeView(nwView.EDITOR)
|
620
625
|
|
626
|
+
# If we're loading the document in the editor, it may need to be saved
|
627
|
+
if tHandle == self.docEditor.docHandle and self.docEditor.docChanged:
|
628
|
+
self.saveDocument()
|
629
|
+
|
621
630
|
logger.debug("Viewing document with handle '%s'", tHandle)
|
622
631
|
updateHistory = tHandle != self.docViewer.docHandle
|
623
632
|
if self.docViewer.loadText(tHandle, updateHistory=updateHistory):
|
@@ -649,7 +658,7 @@ class GuiMain(QMainWindow):
|
|
649
658
|
logger.error("No project open")
|
650
659
|
return False
|
651
660
|
|
652
|
-
lastPath = CONFIG.lastPath()
|
661
|
+
lastPath = CONFIG.lastPath("import")
|
653
662
|
ffilter = formatFileFilter(["*.txt", "*.md", "*.nwd", "*"])
|
654
663
|
loadFile, _ = QFileDialog.getOpenFileName(
|
655
664
|
self, self.tr("Import File"), str(lastPath), filter=ffilter
|
@@ -664,7 +673,7 @@ class GuiMain(QMainWindow):
|
|
664
673
|
try:
|
665
674
|
with open(loadFile, mode="rt", encoding="utf-8") as inFile:
|
666
675
|
text = inFile.read()
|
667
|
-
CONFIG.setLastPath(loadFile)
|
676
|
+
CONFIG.setLastPath("import", loadFile)
|
668
677
|
except Exception as exc:
|
669
678
|
SHARED.error(self.tr(
|
670
679
|
"Could not read file. The file must be an existing text file."
|
@@ -721,14 +730,6 @@ class GuiMain(QMainWindow):
|
|
721
730
|
|
722
731
|
return
|
723
732
|
|
724
|
-
def editItemLabel(self, tHandle: str | None = None) -> None:
|
725
|
-
"""Open the edit item dialog."""
|
726
|
-
if SHARED.hasProject:
|
727
|
-
if tHandle is None and (self.docEditor.anyFocus() or SHARED.focusMode):
|
728
|
-
tHandle = self.docEditor.docHandle
|
729
|
-
self.projView.renameTreeItem(tHandle)
|
730
|
-
return
|
731
|
-
|
732
733
|
def rebuildTrees(self) -> None:
|
733
734
|
"""Rebuild the project tree."""
|
734
735
|
self.projView.populateTree()
|
@@ -750,7 +751,6 @@ class GuiMain(QMainWindow):
|
|
750
751
|
self.mainStatus.setStatusMessage(
|
751
752
|
self.tr("Indexing completed in {0} ms").format(f"{(tEnd - tStart)*1000.0:.1f}")
|
752
753
|
)
|
753
|
-
self.docEditor.updateTagHighLighting()
|
754
754
|
self._updateStatusWordCount()
|
755
755
|
QApplication.restoreOverrideCursor()
|
756
756
|
|
@@ -794,10 +794,7 @@ class GuiMain(QMainWindow):
|
|
794
794
|
"""Open the novel details dialog."""
|
795
795
|
if SHARED.hasProject:
|
796
796
|
dialog = GuiNovelDetails(self)
|
797
|
-
dialog.
|
798
|
-
dialog.show()
|
799
|
-
dialog.raise_()
|
800
|
-
QApplication.processEvents()
|
797
|
+
dialog.activateDialog()
|
801
798
|
dialog.updateValues()
|
802
799
|
return
|
803
800
|
|
@@ -805,12 +802,9 @@ class GuiMain(QMainWindow):
|
|
805
802
|
def showBuildManuscriptDialog(self) -> None:
|
806
803
|
"""Open the build manuscript dialog."""
|
807
804
|
if SHARED.hasProject:
|
808
|
-
if (dialog := SHARED.findTopLevelWidget(GuiManuscript))
|
805
|
+
if not (dialog := SHARED.findTopLevelWidget(GuiManuscript)):
|
809
806
|
dialog = GuiManuscript(self)
|
810
|
-
dialog.
|
811
|
-
dialog.show()
|
812
|
-
dialog.raise_()
|
813
|
-
QApplication.processEvents()
|
807
|
+
dialog.activateDialog()
|
814
808
|
dialog.loadContent()
|
815
809
|
return
|
816
810
|
|
@@ -827,12 +821,9 @@ class GuiMain(QMainWindow):
|
|
827
821
|
def showWritingStatsDialog(self) -> None:
|
828
822
|
"""Open the session stats dialog."""
|
829
823
|
if SHARED.hasProject:
|
830
|
-
if (dialog := SHARED.findTopLevelWidget(GuiWritingStats))
|
824
|
+
if not (dialog := SHARED.findTopLevelWidget(GuiWritingStats)):
|
831
825
|
dialog = GuiWritingStats(self)
|
832
|
-
dialog.
|
833
|
-
dialog.show()
|
834
|
-
dialog.raise_()
|
835
|
-
QApplication.processEvents()
|
826
|
+
dialog.activateDialog()
|
836
827
|
dialog.populateGUI()
|
837
828
|
return
|
838
829
|
|
@@ -840,11 +831,7 @@ class GuiMain(QMainWindow):
|
|
840
831
|
def showAboutNWDialog(self) -> None:
|
841
832
|
"""Show the novelWriter about dialog."""
|
842
833
|
dialog = GuiAbout(self)
|
843
|
-
dialog.
|
844
|
-
dialog.show()
|
845
|
-
dialog.raise_()
|
846
|
-
QApplication.processEvents()
|
847
|
-
dialog.populateGUI()
|
834
|
+
dialog.exec()
|
848
835
|
return
|
849
836
|
|
850
837
|
@pyqtSlot()
|
@@ -858,24 +845,12 @@ class GuiMain(QMainWindow):
|
|
858
845
|
def showDictionariesDialog(self) -> None:
|
859
846
|
"""Show the download dictionaries dialog."""
|
860
847
|
dialog = GuiDictionaries(self)
|
861
|
-
dialog.
|
862
|
-
dialog.show()
|
863
|
-
dialog.raise_()
|
864
|
-
QApplication.processEvents()
|
848
|
+
dialog.activateDialog()
|
865
849
|
if not dialog.initDialog():
|
866
850
|
dialog.close()
|
867
851
|
SHARED.error(self.tr("Could not initialise the dialog."))
|
868
852
|
return
|
869
853
|
|
870
|
-
def reportConfErr(self) -> None:
|
871
|
-
"""Checks if the Config module has any errors to report, and let
|
872
|
-
the user know if this is the case. The Config module caches
|
873
|
-
errors since it is initialised before the GUI itself.
|
874
|
-
"""
|
875
|
-
if CONFIG.hasError:
|
876
|
-
SHARED.error(CONFIG.errorText())
|
877
|
-
return
|
878
|
-
|
879
854
|
##
|
880
855
|
# Main Window Actions
|
881
856
|
##
|
@@ -906,9 +881,7 @@ class GuiMain(QMainWindow):
|
|
906
881
|
|
907
882
|
if SHARED.hasProject:
|
908
883
|
self.closeProject(True)
|
909
|
-
|
910
884
|
CONFIG.saveConfig()
|
911
|
-
self.reportConfErr()
|
912
885
|
|
913
886
|
QApplication.quit()
|
914
887
|
|
@@ -976,14 +949,37 @@ class GuiMain(QMainWindow):
|
|
976
949
|
SHARED.setFocusMode(not SHARED.focusMode)
|
977
950
|
return
|
978
951
|
|
952
|
+
##
|
953
|
+
# Private Slots
|
954
|
+
##
|
955
|
+
|
956
|
+
@pyqtSlot("QWidget*", "QWidget*")
|
957
|
+
def _appFocusChanged(self, old: QWidget, new: QWidget) -> None:
|
958
|
+
"""Alert main widgets that they have received or lost focus."""
|
959
|
+
if isinstance(new, QWidget):
|
960
|
+
docEditor = False
|
961
|
+
docViewer = False
|
962
|
+
if self.docEditor.isAncestorOf(new):
|
963
|
+
docEditor = True
|
964
|
+
elif self.docViewer.isAncestorOf(new):
|
965
|
+
docViewer = True
|
966
|
+
|
967
|
+
self.docEditor.changeFocusState(docEditor)
|
968
|
+
self.docViewer.changeFocusState(docViewer)
|
969
|
+
|
970
|
+
logger.debug("Main focus switched to: %s", type(new).__name__)
|
971
|
+
|
972
|
+
return
|
973
|
+
|
979
974
|
@pyqtSlot(bool)
|
980
975
|
def _focusModeChanged(self, focusMode: bool) -> None:
|
981
|
-
"""Handle change of focus mode. The Main GUI Focus Mode hides
|
982
|
-
view, statusbar and menu.
|
976
|
+
"""Handle change of focus mode. The Main GUI Focus Mode hides
|
977
|
+
tree, view, statusbar and menu.
|
983
978
|
"""
|
984
979
|
if focusMode:
|
985
980
|
logger.debug("Activating Focus Mode")
|
986
|
-
self.
|
981
|
+
self._changeView(nwView.EDITOR)
|
982
|
+
self.docEditor.setFocus()
|
987
983
|
else:
|
988
984
|
logger.debug("Deactivating Focus Mode")
|
989
985
|
|
@@ -1006,39 +1002,53 @@ class GuiMain(QMainWindow):
|
|
1006
1002
|
self.docEditor.ensureCursorVisibleNoCentre()
|
1007
1003
|
return
|
1008
1004
|
|
1009
|
-
@pyqtSlot(
|
1010
|
-
def
|
1005
|
+
@pyqtSlot(nwFocus)
|
1006
|
+
def _switchFocus(self, paneNo: nwFocus) -> None:
|
1011
1007
|
"""Switch focus between main GUI views."""
|
1012
|
-
if paneNo ==
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1008
|
+
if paneNo == nwFocus.TREE:
|
1009
|
+
# Decision Matrix
|
1010
|
+
# vM | vP | fP | vN | fN | Focus
|
1011
|
+
# ----|----|----|----|----|---------
|
1012
|
+
# T | T | T | F | F | Novel
|
1013
|
+
# T | T | F | F | F | Project
|
1014
|
+
# T | F | F | T | T | Project
|
1015
|
+
# T | F | F | T | F | Novel
|
1016
|
+
# T | F | F | F | F | Project
|
1017
|
+
# F | T | T | F | F | Project
|
1018
|
+
# F | T | F | F | F | Project
|
1019
|
+
# F | F | F | T | T | Novel
|
1020
|
+
# F | F | F | T | F | Novel
|
1021
|
+
# F | F | F | F | F | Project
|
1022
|
+
|
1023
|
+
vM = self.mainStack.currentWidget() is self.splitMain
|
1024
|
+
vP = self.projStack.currentWidget() is self.projView
|
1025
|
+
vN = self.projStack.currentWidget() is self.novelView
|
1026
|
+
fP = self.projView.treeHasFocus()
|
1027
|
+
fN = self.novelView.treeHasFocus()
|
1028
|
+
|
1029
|
+
self._changeView(nwView.EDITOR)
|
1030
|
+
if (vM and (vP and fP or vN and not fN)) or (not vM and vN):
|
1031
|
+
self._changeView(nwView.NOVEL)
|
1032
|
+
self.novelView.setTreeFocus()
|
1025
1033
|
else:
|
1026
1034
|
self._changeView(nwView.PROJECT)
|
1027
1035
|
self.projView.setTreeFocus()
|
1028
|
-
|
1029
|
-
|
1030
|
-
self.docEditor.setFocus()
|
1031
|
-
elif paneNo == nwWidget.VIEWER:
|
1036
|
+
|
1037
|
+
elif paneNo == nwFocus.DOCUMENT:
|
1032
1038
|
self._changeView(nwView.EDITOR)
|
1033
|
-
self.
|
1034
|
-
|
1039
|
+
hasViewer = self.splitView.isVisible()
|
1040
|
+
if hasViewer and self.docEditor.anyFocus():
|
1041
|
+
self.docViewer.setFocus()
|
1042
|
+
elif hasViewer and self.docViewer.anyFocus():
|
1043
|
+
self.docEditor.setFocus()
|
1044
|
+
else:
|
1045
|
+
self.docEditor.setFocus()
|
1046
|
+
|
1047
|
+
elif paneNo == nwFocus.OUTLINE:
|
1035
1048
|
self._changeView(nwView.OUTLINE)
|
1036
1049
|
self.outlineView.setTreeFocus()
|
1037
|
-
return
|
1038
1050
|
|
1039
|
-
|
1040
|
-
# Private Slots
|
1041
|
-
##
|
1051
|
+
return
|
1042
1052
|
|
1043
1053
|
@pyqtSlot(bool, bool, bool, bool)
|
1044
1054
|
def _processConfigChanges(self, restart: bool, tree: bool, theme: bool, syntax: bool) -> None:
|
@@ -1148,7 +1158,7 @@ class GuiMain(QMainWindow):
|
|
1148
1158
|
@pyqtSlot()
|
1149
1159
|
def _reloadViewer(self) -> None:
|
1150
1160
|
"""Reload the document in the viewer."""
|
1151
|
-
if self.docEditor.
|
1161
|
+
if self.docEditor.docHandle == self.docViewer.docHandle:
|
1152
1162
|
# If the two panels have the same document, save any changes in the editor
|
1153
1163
|
self.saveDocument()
|
1154
1164
|
self.docViewer.reloadText()
|
@@ -1178,16 +1188,13 @@ class GuiMain(QMainWindow):
|
|
1178
1188
|
|
1179
1189
|
@pyqtSlot(nwDocAction)
|
1180
1190
|
def _passDocumentAction(self, action: nwDocAction) -> None:
|
1181
|
-
"""Pass on a document action to the
|
1182
|
-
focus, or
|
1183
|
-
child widgets have focus. If neither has focus, ignore it.
|
1191
|
+
"""Pass on a document action to the editor or viewer based on
|
1192
|
+
which one has focus, or if neither has focus, ignore it.
|
1184
1193
|
"""
|
1185
|
-
if self.
|
1186
|
-
self.docViewer.docAction(action)
|
1187
|
-
elif self.docEditor.hasFocus():
|
1194
|
+
if self.docEditor.hasFocus():
|
1188
1195
|
self.docEditor.docAction(action)
|
1189
|
-
|
1190
|
-
|
1196
|
+
elif self.docViewer.hasFocus():
|
1197
|
+
self.docViewer.docAction(action)
|
1191
1198
|
return
|
1192
1199
|
|
1193
1200
|
@pyqtSlot(str)
|
@@ -1228,7 +1235,7 @@ class GuiMain(QMainWindow):
|
|
1228
1235
|
doSave &= SHARED.project.projChanged
|
1229
1236
|
doSave &= SHARED.project.storage.isOpen()
|
1230
1237
|
if doSave:
|
1231
|
-
logger.debug("
|
1238
|
+
logger.debug("Auto-saving project")
|
1232
1239
|
self.saveProject(autoSave=True)
|
1233
1240
|
return
|
1234
1241
|
|
@@ -1236,7 +1243,7 @@ class GuiMain(QMainWindow):
|
|
1236
1243
|
def _autoSaveDocument(self) -> None:
|
1237
1244
|
"""Autosave of the document. This is a timer-activated slot."""
|
1238
1245
|
if SHARED.hasProject and self.docEditor.docChanged:
|
1239
|
-
logger.debug("
|
1246
|
+
logger.debug("Auto-saving document")
|
1240
1247
|
self.saveDocument()
|
1241
1248
|
return
|
1242
1249
|
|
@@ -1395,10 +1402,7 @@ class GuiMain(QMainWindow):
|
|
1395
1402
|
|
1396
1403
|
def _updateWindowTitle(self, projName: str | None = None) -> None:
|
1397
1404
|
"""Set the window title and add the project's name."""
|
1398
|
-
|
1399
|
-
if projName is not None:
|
1400
|
-
winTitle += " - %s" % projName
|
1401
|
-
self.setWindowTitle(winTitle)
|
1405
|
+
self.setWindowTitle(" - ".join(filter(None, [projName, CONFIG.appName])))
|
1402
1406
|
return
|
1403
1407
|
|
1404
1408
|
def _getTagSource(self, tag: str) -> tuple[str | None, str | None]:
|
@@ -1416,5 +1420,3 @@ class GuiMain(QMainWindow):
|
|
1416
1420
|
))
|
1417
1421
|
return None, None
|
1418
1422
|
return tHandle, sTitle
|
1419
|
-
|
1420
|
-
# END Class GuiMain
|