novelWriter 2.3.1__py3-none-any.whl → 2.4b1__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.3.1.dist-info → novelWriter-2.4b1.dist-info}/METADATA +1 -1
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/RECORD +81 -70
- novelwriter/__init__.py +5 -5
- novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
- novelwriter/assets/icons/typicons_light/icons.conf +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
- 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 +25 -23
- novelwriter/common.py +1 -1
- novelwriter/config.py +35 -12
- novelwriter/constants.py +5 -6
- novelwriter/core/buildsettings.py +60 -40
- novelwriter/core/coretools.py +98 -13
- novelwriter/core/docbuild.py +74 -7
- novelwriter/core/document.py +24 -3
- novelwriter/core/index.py +31 -112
- novelwriter/core/project.py +10 -15
- novelwriter/core/sessions.py +2 -2
- novelwriter/core/status.py +4 -4
- novelwriter/core/storage.py +8 -2
- novelwriter/core/tohtml.py +22 -25
- novelwriter/core/tokenizer.py +416 -232
- novelwriter/core/tomd.py +17 -8
- novelwriter/core/toodt.py +65 -7
- novelwriter/core/tree.py +8 -8
- novelwriter/dialogs/docsplit.py +7 -8
- novelwriter/dialogs/preferences.py +3 -6
- novelwriter/enum.py +17 -14
- novelwriter/extensions/modified.py +20 -2
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/gui/doceditor.py +257 -279
- novelwriter/gui/dochighlight.py +29 -25
- novelwriter/gui/docviewer.py +139 -148
- novelwriter/gui/docviewerpanel.py +4 -24
- novelwriter/gui/editordocument.py +12 -1
- novelwriter/gui/itemdetails.py +6 -6
- novelwriter/gui/mainmenu.py +37 -16
- novelwriter/gui/noveltree.py +11 -19
- novelwriter/gui/outline.py +43 -20
- novelwriter/gui/projtree.py +35 -43
- novelwriter/gui/search.py +316 -0
- novelwriter/gui/sidebar.py +25 -30
- novelwriter/gui/theme.py +59 -6
- novelwriter/guimain.py +176 -173
- novelwriter/shared.py +26 -1
- novelwriter/text/__init__.py +3 -0
- novelwriter/text/counting.py +137 -0
- novelwriter/tools/manuscript.py +344 -55
- novelwriter/tools/manussettings.py +213 -71
- novelwriter/tools/welcome.py +1 -1
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/WHEEL +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/top_level.txt +0 -0
novelwriter/guimain.py
CHANGED
@@ -38,33 +38,31 @@ from PyQt5.QtWidgets import (
|
|
38
38
|
)
|
39
39
|
|
40
40
|
from novelwriter import CONFIG, SHARED, __hexversion__, __version__
|
41
|
+
from novelwriter.common import formatFileFilter, formatVersion, hexToInt
|
41
42
|
from novelwriter.constants import nwConst
|
42
|
-
from novelwriter.
|
43
|
-
from novelwriter.
|
44
|
-
from novelwriter.
|
45
|
-
from novelwriter.
|
46
|
-
from novelwriter.
|
43
|
+
from novelwriter.dialogs.about import GuiAbout
|
44
|
+
from novelwriter.dialogs.preferences import GuiPreferences
|
45
|
+
from novelwriter.dialogs.projectsettings import GuiProjectSettings
|
46
|
+
from novelwriter.dialogs.wordlist import GuiWordList
|
47
|
+
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemType, nwWidget, nwView
|
47
48
|
from novelwriter.gui.doceditor import GuiDocEditor
|
48
49
|
from novelwriter.gui.docviewer import GuiDocViewer
|
50
|
+
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
|
51
|
+
from novelwriter.gui.itemdetails import GuiItemDetails
|
52
|
+
from novelwriter.gui.mainmenu import GuiMainMenu
|
49
53
|
from novelwriter.gui.noveltree import GuiNovelView
|
54
|
+
from novelwriter.gui.outline import GuiOutlineView
|
55
|
+
from novelwriter.gui.projtree import GuiProjectView
|
56
|
+
from novelwriter.gui.search import GuiProjectSearch
|
57
|
+
from novelwriter.gui.sidebar import GuiSideBar
|
50
58
|
from novelwriter.gui.statusbar import GuiMainStatus
|
51
|
-
from novelwriter.gui.
|
52
|
-
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
|
53
|
-
from novelwriter.dialogs.about import GuiAbout
|
54
|
-
from novelwriter.dialogs.wordlist import GuiWordList
|
55
|
-
from novelwriter.dialogs.preferences import GuiPreferences
|
56
|
-
from novelwriter.dialogs.projectsettings import GuiProjectSettings
|
57
|
-
from novelwriter.tools.welcome import GuiWelcome
|
58
|
-
from novelwriter.tools.manuscript import GuiManuscript
|
59
|
+
from novelwriter.gui.theme import GuiTheme
|
59
60
|
from novelwriter.tools.dictionaries import GuiDictionaries
|
61
|
+
from novelwriter.tools.manuscript import GuiManuscript
|
60
62
|
from novelwriter.tools.noveldetails import GuiNovelDetails
|
63
|
+
from novelwriter.tools.welcome import GuiWelcome
|
61
64
|
from novelwriter.tools.writingstats import GuiWritingStats
|
62
65
|
|
63
|
-
from novelwriter.enum import (
|
64
|
-
nwDocAction, nwDocInsert, nwDocMode, nwItemType, nwWidget, nwView
|
65
|
-
)
|
66
|
-
from novelwriter.common import formatFileFilter, formatVersion, hexToInt
|
67
|
-
|
68
66
|
logger = logging.getLogger(__name__)
|
69
67
|
|
70
68
|
|
@@ -104,9 +102,6 @@ class GuiMain(QMainWindow):
|
|
104
102
|
# Initialise UserData Instance
|
105
103
|
SHARED.initSharedData(self, GuiTheme())
|
106
104
|
|
107
|
-
# Core Settings
|
108
|
-
self.isFocusMode = False
|
109
|
-
|
110
105
|
# Prepare Main Window
|
111
106
|
self.resize(*CONFIG.mainWinSize)
|
112
107
|
self._updateWindowTitle()
|
@@ -126,6 +121,7 @@ class GuiMain(QMainWindow):
|
|
126
121
|
# Main GUI Elements
|
127
122
|
self.mainStatus = GuiMainStatus(self)
|
128
123
|
self.projView = GuiProjectView(self)
|
124
|
+
self.projSearch = GuiProjectSearch(self)
|
129
125
|
self.novelView = GuiNovelView(self)
|
130
126
|
self.docEditor = GuiDocEditor(self)
|
131
127
|
self.docViewer = GuiDocViewer(self)
|
@@ -139,6 +135,7 @@ class GuiMain(QMainWindow):
|
|
139
135
|
self.projStack = QStackedWidget(self)
|
140
136
|
self.projStack.addWidget(self.projView)
|
141
137
|
self.projStack.addWidget(self.novelView)
|
138
|
+
self.projStack.addWidget(self.projSearch)
|
142
139
|
self.projStack.currentChanged.connect(self._projStackChanged)
|
143
140
|
|
144
141
|
# Project Tree View
|
@@ -157,6 +154,8 @@ class GuiMain(QMainWindow):
|
|
157
154
|
self.splitView.setHandleWidth(hWd)
|
158
155
|
self.splitView.setOpaqueResize(False)
|
159
156
|
self.splitView.setSizes(CONFIG.viewPanePos)
|
157
|
+
self.splitView.setCollapsible(0, False)
|
158
|
+
self.splitView.setCollapsible(1, False)
|
160
159
|
|
161
160
|
# Splitter : Document Editor / Document Viewer
|
162
161
|
self.splitDocs = QSplitter(Qt.Horizontal, self)
|
@@ -164,6 +163,8 @@ class GuiMain(QMainWindow):
|
|
164
163
|
self.splitDocs.addWidget(self.splitView)
|
165
164
|
self.splitDocs.setOpaqueResize(False)
|
166
165
|
self.splitDocs.setHandleWidth(hWd)
|
166
|
+
self.splitDocs.setCollapsible(0, False)
|
167
|
+
self.splitDocs.setCollapsible(1, False)
|
167
168
|
|
168
169
|
# Splitter : Project Tree / Document Area
|
169
170
|
self.splitMain = QSplitter(Qt.Horizontal)
|
@@ -173,6 +174,10 @@ class GuiMain(QMainWindow):
|
|
173
174
|
self.splitMain.setOpaqueResize(False)
|
174
175
|
self.splitMain.setHandleWidth(hWd)
|
175
176
|
self.splitMain.setSizes(CONFIG.mainPanePos)
|
177
|
+
self.splitMain.setCollapsible(0, False)
|
178
|
+
self.splitMain.setCollapsible(0, False)
|
179
|
+
self.splitMain.setStretchFactor(1, 0)
|
180
|
+
self.splitMain.setStretchFactor(1, 1)
|
176
181
|
|
177
182
|
# Main Stack : Editor / Outline
|
178
183
|
self.mainStack = QStackedWidget(self)
|
@@ -180,31 +185,6 @@ class GuiMain(QMainWindow):
|
|
180
185
|
self.mainStack.addWidget(self.outlineView)
|
181
186
|
self.mainStack.currentChanged.connect(self._mainStackChanged)
|
182
187
|
|
183
|
-
# Indices of Splitter Widgets
|
184
|
-
self.idxTree = self.splitMain.indexOf(self.treePane)
|
185
|
-
self.idxMain = self.splitMain.indexOf(self.splitDocs)
|
186
|
-
self.idxEditor = self.splitDocs.indexOf(self.docEditor)
|
187
|
-
self.idxViewer = self.splitDocs.indexOf(self.splitView)
|
188
|
-
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
|
189
|
-
self.idxViewDocPanel = self.splitView.indexOf(self.docViewerPanel)
|
190
|
-
|
191
|
-
# Indices of Stack Widgets
|
192
|
-
self.idxEditorView = self.mainStack.indexOf(self.splitMain)
|
193
|
-
self.idxOutlineView = self.mainStack.indexOf(self.outlineView)
|
194
|
-
self.idxProjView = self.projStack.indexOf(self.projView)
|
195
|
-
self.idxNovelView = self.projStack.indexOf(self.novelView)
|
196
|
-
|
197
|
-
# Splitter Behaviour
|
198
|
-
self.splitMain.setCollapsible(self.idxTree, False)
|
199
|
-
self.splitMain.setCollapsible(self.idxMain, False)
|
200
|
-
self.splitDocs.setCollapsible(self.idxEditor, False)
|
201
|
-
self.splitDocs.setCollapsible(self.idxViewer, False)
|
202
|
-
self.splitView.setCollapsible(self.idxViewDoc, False)
|
203
|
-
self.splitView.setCollapsible(self.idxViewDocPanel, False)
|
204
|
-
|
205
|
-
self.splitMain.setStretchFactor(self.idxTree, 0)
|
206
|
-
self.splitMain.setStretchFactor(self.idxMain, 1)
|
207
|
-
|
208
188
|
# Editor / Viewer Default State
|
209
189
|
self.splitView.setVisible(False)
|
210
190
|
self.docEditor.closeSearch()
|
@@ -233,20 +213,23 @@ class GuiMain(QMainWindow):
|
|
233
213
|
SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
|
234
214
|
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
|
235
215
|
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
|
216
|
+
SHARED.focusModeChanged.connect(self._focusModeChanged)
|
236
217
|
SHARED.indexChangedTags.connect(self.docViewerPanel.updateChangedTags)
|
237
218
|
SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged)
|
238
219
|
SHARED.indexScannedText.connect(self.projView.updateItemValues)
|
239
220
|
SHARED.indexScannedText.connect(self.itemDetails.updateViewBox)
|
240
221
|
SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared)
|
241
222
|
SHARED.indexAvailable.connect(self.docViewerPanel.indexHasAppeared)
|
223
|
+
SHARED.mainClockTick.connect(self._timeTick)
|
242
224
|
|
243
225
|
self.mainMenu.requestDocAction.connect(self._passDocumentAction)
|
244
226
|
self.mainMenu.requestDocInsert.connect(self._passDocumentInsert)
|
245
227
|
self.mainMenu.requestDocInsertText.connect(self._passDocumentInsert)
|
246
228
|
self.mainMenu.requestDocKeyWordInsert.connect(self.docEditor.insertKeyWord)
|
247
229
|
self.mainMenu.requestFocusChange.connect(self.switchFocus)
|
230
|
+
self.mainMenu.requestViewChange.connect(self._changeView)
|
248
231
|
|
249
|
-
self.sideBar.
|
232
|
+
self.sideBar.requestViewChange.connect(self._changeView)
|
250
233
|
|
251
234
|
self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
252
235
|
self.projView.openDocumentRequest.connect(self._openDocument)
|
@@ -263,6 +246,9 @@ class GuiMain(QMainWindow):
|
|
263
246
|
self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
264
247
|
self.novelView.openDocumentRequest.connect(self._openDocument)
|
265
248
|
|
249
|
+
self.projSearch.openDocumentSelectRequest.connect(self._openDocumentSelection)
|
250
|
+
self.projSearch.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
251
|
+
|
266
252
|
self.docEditor.editedStatusChanged.connect(self.mainStatus.updateDocumentStatus)
|
267
253
|
self.docEditor.docCountsChanged.connect(self.itemDetails.updateCounts)
|
268
254
|
self.docEditor.docCountsChanged.connect(self.projView.updateCounts)
|
@@ -275,9 +261,12 @@ class GuiMain(QMainWindow):
|
|
275
261
|
self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode)
|
276
262
|
self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
277
263
|
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
|
264
|
+
self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote)
|
278
265
|
|
279
266
|
self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
|
280
267
|
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
|
268
|
+
self.docViewer.closeDocumentRequest.connect(self.closeDocViewer)
|
269
|
+
self.docViewer.reloadDocumentRequest.connect(self._reloadViewer)
|
281
270
|
self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility)
|
282
271
|
self.docViewer.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
283
272
|
|
@@ -298,12 +287,6 @@ class GuiMain(QMainWindow):
|
|
298
287
|
self.asDocTimer = QTimer(self)
|
299
288
|
self.asDocTimer.timeout.connect(self._autoSaveDocument)
|
300
289
|
|
301
|
-
# Main Clock
|
302
|
-
self.mainTimer = QTimer(self)
|
303
|
-
self.mainTimer.setInterval(1000)
|
304
|
-
self.mainTimer.timeout.connect(self._timeTick)
|
305
|
-
self.mainTimer.start()
|
306
|
-
|
307
290
|
# Shortcuts and Actions
|
308
291
|
self._connectMenuActions()
|
309
292
|
|
@@ -401,12 +384,13 @@ class GuiMain(QMainWindow):
|
|
401
384
|
if saveOK:
|
402
385
|
self.closeDocument()
|
403
386
|
self.docViewer.clearNavHistory()
|
404
|
-
self.
|
387
|
+
self.closeViewerPanel(byUser=False)
|
405
388
|
|
406
389
|
self.docViewerPanel.closeProjectTasks()
|
407
390
|
self.outlineView.closeProjectTasks()
|
408
391
|
self.novelView.closeProjectTasks()
|
409
392
|
self.projView.closeProjectTasks()
|
393
|
+
self.projSearch.closeProjectTasks()
|
410
394
|
self.itemDetails.clearDetails()
|
411
395
|
self.mainStatus.clearStatus()
|
412
396
|
|
@@ -457,7 +441,7 @@ class GuiMain(QMainWindow):
|
|
457
441
|
"'{0}' ({1} {2}), last active on {3}."
|
458
442
|
).format(
|
459
443
|
lockStatus[0], lockStatus[1], lockStatus[2],
|
460
|
-
datetime.fromtimestamp(int(lockStatus[3]))
|
444
|
+
CONFIG.localDateTime(datetime.fromtimestamp(int(lockStatus[3])))
|
461
445
|
)
|
462
446
|
except Exception:
|
463
447
|
lockDetails = ""
|
@@ -523,24 +507,19 @@ class GuiMain(QMainWindow):
|
|
523
507
|
# Document Actions
|
524
508
|
##
|
525
509
|
|
526
|
-
def closeDocument(self, beforeOpen: bool = False) ->
|
510
|
+
def closeDocument(self, beforeOpen: bool = False) -> None:
|
527
511
|
"""Close the document and clear the editor and title field."""
|
528
|
-
if
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
self.docEditor.clearEditor()
|
540
|
-
if not beforeOpen:
|
541
|
-
self.novelView.setActiveHandle(None)
|
542
|
-
|
543
|
-
return True
|
512
|
+
if SHARED.hasProject:
|
513
|
+
# Disable focus mode if it is active
|
514
|
+
if SHARED.focusMode:
|
515
|
+
SHARED.setFocusMode(False)
|
516
|
+
self.docEditor.saveCursorPosition()
|
517
|
+
if self.docEditor.docChanged:
|
518
|
+
self.saveDocument()
|
519
|
+
self.docEditor.clearEditor()
|
520
|
+
if not beforeOpen:
|
521
|
+
self.novelView.setActiveHandle(None)
|
522
|
+
return
|
544
523
|
|
545
524
|
def openDocument(self, tHandle: str | None, tLine: int | None = None,
|
546
525
|
changeFocus: bool = True, doScroll: bool = False) -> bool:
|
@@ -604,13 +583,12 @@ class GuiMain(QMainWindow):
|
|
604
583
|
|
605
584
|
return False
|
606
585
|
|
607
|
-
|
586
|
+
@pyqtSlot()
|
587
|
+
def saveDocument(self) -> None:
|
608
588
|
"""Save the current documents."""
|
609
|
-
if
|
610
|
-
|
611
|
-
|
612
|
-
self.docEditor.saveText()
|
613
|
-
return True
|
589
|
+
if SHARED.hasProject:
|
590
|
+
self.docEditor.saveText()
|
591
|
+
return
|
614
592
|
|
615
593
|
def viewDocument(self, tHandle: str | None = None, sTitle: str | None = None) -> bool:
|
616
594
|
"""Load a document for viewing in the view panel."""
|
@@ -640,7 +618,8 @@ class GuiMain(QMainWindow):
|
|
640
618
|
self._changeView(nwView.EDITOR)
|
641
619
|
|
642
620
|
logger.debug("Viewing document with handle '%s'", tHandle)
|
643
|
-
|
621
|
+
updateHistory = tHandle != self.docViewer.docHandle
|
622
|
+
if self.docViewer.loadText(tHandle, updateHistory=updateHistory):
|
644
623
|
if not self.splitView.isVisible():
|
645
624
|
cursorVisible = self.docEditor.cursorIsVisible()
|
646
625
|
bPos = self.splitMain.sizes()
|
@@ -657,7 +636,7 @@ class GuiMain(QMainWindow):
|
|
657
636
|
self.docEditor.ensureCursorVisibleNoCentre()
|
658
637
|
|
659
638
|
if sTitle:
|
660
|
-
self.docViewer.navigateTo(f"#{sTitle}")
|
639
|
+
self.docViewer.navigateTo(f"#{tHandle}:{sTitle}")
|
661
640
|
|
662
641
|
return True
|
663
642
|
|
@@ -713,80 +692,71 @@ class GuiMain(QMainWindow):
|
|
713
692
|
# Tree Item Actions
|
714
693
|
##
|
715
694
|
|
716
|
-
|
695
|
+
@pyqtSlot()
|
696
|
+
def openSelectedItem(self) -> None:
|
717
697
|
"""Open the selected item from the tree that is currently
|
718
698
|
active. It is not checked that the item is actually a document.
|
719
699
|
That should be handled by the openDocument function.
|
720
700
|
"""
|
721
|
-
if
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
else:
|
735
|
-
logger.warning("No item selected")
|
736
|
-
return False
|
737
|
-
|
738
|
-
if tHandle is not None and sTitle is not None:
|
739
|
-
hItem = SHARED.project.index.getItemHeader(tHandle, sTitle)
|
740
|
-
if hItem is not None:
|
741
|
-
tLine = hItem.line
|
701
|
+
if SHARED.hasProject:
|
702
|
+
tHandle = None
|
703
|
+
sTitle = None
|
704
|
+
tLine = None
|
705
|
+
if self.projView.treeHasFocus():
|
706
|
+
tHandle = self.projView.getSelectedHandle()
|
707
|
+
elif self.novelView.treeHasFocus():
|
708
|
+
tHandle, sTitle = self.novelView.getSelectedHandle()
|
709
|
+
elif self.outlineView.treeHasFocus():
|
710
|
+
tHandle, sTitle = self.outlineView.getSelectedHandle()
|
711
|
+
else:
|
712
|
+
logger.warning("No item selected")
|
713
|
+
return
|
742
714
|
|
743
|
-
|
744
|
-
|
715
|
+
if tHandle and sTitle:
|
716
|
+
if hItem := SHARED.project.index.getItemHeading(tHandle, sTitle):
|
717
|
+
tLine = hItem.line
|
718
|
+
if tHandle:
|
719
|
+
self.openDocument(tHandle, tLine=tLine, changeFocus=False, doScroll=False)
|
745
720
|
|
746
|
-
return
|
721
|
+
return
|
747
722
|
|
748
|
-
def editItemLabel(self, tHandle: str | None = None) ->
|
723
|
+
def editItemLabel(self, tHandle: str | None = None) -> None:
|
749
724
|
"""Open the edit item dialog."""
|
750
|
-
if
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
self.projView.renameTreeItem(tHandle)
|
756
|
-
return True
|
725
|
+
if SHARED.hasProject:
|
726
|
+
if tHandle is None and (self.docEditor.anyFocus() or SHARED.focusMode):
|
727
|
+
tHandle = self.docEditor.docHandle
|
728
|
+
self.projView.renameTreeItem(tHandle)
|
729
|
+
return
|
757
730
|
|
758
731
|
def rebuildTrees(self) -> None:
|
759
732
|
"""Rebuild the project tree."""
|
760
733
|
self.projView.populateTree()
|
761
734
|
return
|
762
735
|
|
763
|
-
def rebuildIndex(self, beQuiet: bool = False) ->
|
736
|
+
def rebuildIndex(self, beQuiet: bool = False) -> None:
|
764
737
|
"""Rebuild the entire index."""
|
765
|
-
if
|
766
|
-
logger.
|
767
|
-
|
768
|
-
|
769
|
-
logger.info("Rebuilding index ...")
|
770
|
-
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
771
|
-
tStart = time()
|
738
|
+
if SHARED.hasProject:
|
739
|
+
logger.info("Rebuilding index ...")
|
740
|
+
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
741
|
+
tStart = time()
|
772
742
|
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
743
|
+
self.projView.saveProjectTasks()
|
744
|
+
SHARED.project.index.rebuildIndex()
|
745
|
+
self.projView.populateTree()
|
746
|
+
self.novelView.refreshTree()
|
777
747
|
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
748
|
+
tEnd = time()
|
749
|
+
self.mainStatus.setStatusMessage(
|
750
|
+
self.tr("Indexing completed in {0} ms").format(f"{(tEnd - tStart)*1000.0:.1f}")
|
751
|
+
)
|
752
|
+
self.docEditor.updateTagHighLighting()
|
753
|
+
self._updateStatusWordCount()
|
754
|
+
qApp.restoreOverrideCursor()
|
785
755
|
|
786
|
-
|
787
|
-
|
756
|
+
if not beQuiet:
|
757
|
+
SHARED.info(self.tr("The project index has been successfully rebuilt."))
|
788
758
|
|
789
|
-
return
|
759
|
+
return
|
790
760
|
|
791
761
|
##
|
792
762
|
# Main Dialogs
|
@@ -896,15 +866,14 @@ class GuiMain(QMainWindow):
|
|
896
866
|
SHARED.error(self.tr("Could not initialise the dialog."))
|
897
867
|
return
|
898
868
|
|
899
|
-
def reportConfErr(self) ->
|
869
|
+
def reportConfErr(self) -> None:
|
900
870
|
"""Checks if the Config module has any errors to report, and let
|
901
871
|
the user know if this is the case. The Config module caches
|
902
872
|
errors since it is initialised before the GUI itself.
|
903
873
|
"""
|
904
874
|
if CONFIG.hasError:
|
905
875
|
SHARED.error(CONFIG.errorText())
|
906
|
-
|
907
|
-
return False
|
876
|
+
return
|
908
877
|
|
909
878
|
##
|
910
879
|
# Main Window Actions
|
@@ -922,7 +891,7 @@ class GuiMain(QMainWindow):
|
|
922
891
|
|
923
892
|
logger.info("Exiting novelWriter")
|
924
893
|
|
925
|
-
if not
|
894
|
+
if not SHARED.focusMode:
|
926
895
|
CONFIG.setMainPanePos(self.splitMain.sizes())
|
927
896
|
CONFIG.setOutlinePanePos(self.outlineView.splitSizes())
|
928
897
|
if self.docViewerPanel.isVisible():
|
@@ -943,7 +912,7 @@ class GuiMain(QMainWindow):
|
|
943
912
|
|
944
913
|
return True
|
945
914
|
|
946
|
-
def
|
915
|
+
def closeViewerPanel(self, byUser: bool = True) -> bool:
|
947
916
|
"""Close the document view panel."""
|
948
917
|
self.docViewer.clearViewer()
|
949
918
|
if byUser:
|
@@ -991,32 +960,40 @@ class GuiMain(QMainWindow):
|
|
991
960
|
SHARED.project.data.setLastHandle(None, "editor")
|
992
961
|
return
|
993
962
|
|
963
|
+
@pyqtSlot()
|
964
|
+
def closeDocViewer(self) -> None:
|
965
|
+
"""Close the document viewer."""
|
966
|
+
self.closeViewerPanel()
|
967
|
+
SHARED.project.data.setLastHandle(None, "viewer")
|
968
|
+
return
|
969
|
+
|
994
970
|
@pyqtSlot()
|
995
971
|
def toggleFocusMode(self) -> None:
|
996
|
-
"""
|
972
|
+
"""Toggle focus mode."""
|
973
|
+
if self.docEditor.docHandle:
|
974
|
+
SHARED.setFocusMode(not SHARED.focusMode)
|
975
|
+
return
|
976
|
+
|
977
|
+
@pyqtSlot(bool)
|
978
|
+
def _focusModeChanged(self, focusMode: bool) -> None:
|
979
|
+
"""Handle change of focus mode. The Main GUI Focus Mode hides tree,
|
997
980
|
view, statusbar and menu.
|
998
981
|
"""
|
999
|
-
if
|
1000
|
-
logger.error("No document open, so not activating Focus Mode")
|
1001
|
-
return
|
1002
|
-
|
1003
|
-
self.isFocusMode = not self.isFocusMode
|
1004
|
-
if self.isFocusMode:
|
982
|
+
if focusMode:
|
1005
983
|
logger.debug("Activating Focus Mode")
|
1006
984
|
self.switchFocus(nwWidget.EDITOR)
|
1007
985
|
else:
|
1008
986
|
logger.debug("Deactivating Focus Mode")
|
1009
987
|
|
1010
988
|
cursorVisible = self.docEditor.cursorIsVisible()
|
1011
|
-
isVisible = not
|
989
|
+
isVisible = not focusMode
|
1012
990
|
self.treePane.setVisible(isVisible)
|
1013
991
|
self.mainStatus.setVisible(isVisible)
|
1014
992
|
self.mainMenu.setVisible(isVisible)
|
1015
993
|
self.sideBar.setVisible(isVisible)
|
1016
994
|
|
1017
|
-
hideDocFooter =
|
995
|
+
hideDocFooter = focusMode and CONFIG.hideFocusFooter
|
1018
996
|
self.docEditor.docFooter.setVisible(not hideDocFooter)
|
1019
|
-
self.docEditor.docHeader.updateFocusMode()
|
1020
997
|
|
1021
998
|
if self.splitView.isVisible():
|
1022
999
|
self.splitView.setVisible(False)
|
@@ -1025,7 +1002,6 @@ class GuiMain(QMainWindow):
|
|
1025
1002
|
|
1026
1003
|
if cursorVisible:
|
1027
1004
|
self.docEditor.ensureCursorVisibleNoCentre()
|
1028
|
-
|
1029
1005
|
return
|
1030
1006
|
|
1031
1007
|
@pyqtSlot(nwWidget)
|
@@ -1038,12 +1014,15 @@ class GuiMain(QMainWindow):
|
|
1038
1014
|
self.novelView.setTreeFocus()
|
1039
1015
|
else:
|
1040
1016
|
self.projView.setTreeFocus()
|
1041
|
-
|
1017
|
+
elif self.projStack.currentWidget() is self.novelView:
|
1042
1018
|
if self.novelView.treeHasFocus():
|
1043
1019
|
self._changeView(nwView.PROJECT)
|
1044
1020
|
self.projView.setTreeFocus()
|
1045
1021
|
else:
|
1046
1022
|
self.novelView.setTreeFocus()
|
1023
|
+
else:
|
1024
|
+
self._changeView(nwView.PROJECT)
|
1025
|
+
self.projView.setTreeFocus()
|
1047
1026
|
elif paneNo == nwWidget.EDITOR:
|
1048
1027
|
self._changeView(nwView.EDITOR)
|
1049
1028
|
self.docEditor.setFocus()
|
@@ -1084,6 +1063,7 @@ class GuiMain(QMainWindow):
|
|
1084
1063
|
self.sideBar.updateTheme()
|
1085
1064
|
self.projView.updateTheme()
|
1086
1065
|
self.novelView.updateTheme()
|
1066
|
+
self.projSearch.updateTheme()
|
1087
1067
|
self.outlineView.updateTheme()
|
1088
1068
|
self.itemDetails.updateTheme()
|
1089
1069
|
self.mainStatus.updateTheme()
|
@@ -1146,7 +1126,7 @@ class GuiMain(QMainWindow):
|
|
1146
1126
|
if tHandle is not None:
|
1147
1127
|
if mode == nwDocMode.EDIT:
|
1148
1128
|
tLine = None
|
1149
|
-
hItem = SHARED.project.index.
|
1129
|
+
hItem = SHARED.project.index.getItemHeading(tHandle, sTitle)
|
1150
1130
|
if hItem is not None:
|
1151
1131
|
tLine = hItem.line
|
1152
1132
|
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
@@ -1154,6 +1134,24 @@ class GuiMain(QMainWindow):
|
|
1154
1134
|
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
1155
1135
|
return
|
1156
1136
|
|
1137
|
+
@pyqtSlot(str, int, int, bool)
|
1138
|
+
def _openDocumentSelection(
|
1139
|
+
self, tHandle: str, selStart: int, selLength: int, changeFocus: bool
|
1140
|
+
) -> None:
|
1141
|
+
"""Open a document and select a section of the text."""
|
1142
|
+
if self.openDocument(tHandle, changeFocus=changeFocus):
|
1143
|
+
self.docEditor.setCursorSelection(selStart, selLength)
|
1144
|
+
return
|
1145
|
+
|
1146
|
+
@pyqtSlot()
|
1147
|
+
def _reloadViewer(self) -> None:
|
1148
|
+
"""Reload the document in the viewer."""
|
1149
|
+
if self.docEditor.docChanged and self.docEditor.docHandle == self.docViewer.docHandle:
|
1150
|
+
# If the two panels have the same document, save any changes in the editor
|
1151
|
+
self.saveDocument()
|
1152
|
+
self.docViewer.reloadText()
|
1153
|
+
return
|
1154
|
+
|
1157
1155
|
@pyqtSlot(nwView)
|
1158
1156
|
def _changeView(self, view: nwView) -> None:
|
1159
1157
|
"""Handle the requested change of view from the GuiViewBar."""
|
@@ -1166,6 +1164,10 @@ class GuiMain(QMainWindow):
|
|
1166
1164
|
elif view == nwView.NOVEL:
|
1167
1165
|
self.mainStack.setCurrentWidget(self.splitMain)
|
1168
1166
|
self.projStack.setCurrentWidget(self.novelView)
|
1167
|
+
elif view == nwView.SEARCH:
|
1168
|
+
self.mainStack.setCurrentWidget(self.splitMain)
|
1169
|
+
self.projStack.setCurrentWidget(self.projSearch)
|
1170
|
+
self.projSearch.beginSearch()
|
1169
1171
|
elif view == nwView.OUTLINE:
|
1170
1172
|
self.mainStack.setCurrentWidget(self.outlineView)
|
1171
1173
|
return
|
@@ -1204,16 +1206,15 @@ class GuiMain(QMainWindow):
|
|
1204
1206
|
@pyqtSlot()
|
1205
1207
|
def _timeTick(self) -> None:
|
1206
1208
|
"""Process time tick of the main timer."""
|
1207
|
-
if
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
self.mainStatus.memInfo()
|
1209
|
+
if SHARED.hasProject:
|
1210
|
+
currTime = time()
|
1211
|
+
editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime
|
1212
|
+
userIdle = qApp.applicationState() != Qt.ApplicationActive
|
1213
|
+
self.mainStatus.setUserIdle(editIdle or userIdle)
|
1214
|
+
SHARED.updateIdleTime(currTime, editIdle or userIdle)
|
1215
|
+
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
|
1216
|
+
if CONFIG.memInfo and int(currTime) % 5 == 0: # pragma: no cover
|
1217
|
+
self.mainStatus.memInfo()
|
1217
1218
|
return
|
1218
1219
|
|
1219
1220
|
@pyqtSlot()
|
@@ -1255,25 +1256,26 @@ class GuiMain(QMainWindow):
|
|
1255
1256
|
|
1256
1257
|
@pyqtSlot()
|
1257
1258
|
def _keyPressReturn(self) -> None:
|
1258
|
-
"""
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1259
|
+
"""Process a return or enter keypress in the main window."""
|
1260
|
+
if self.projStack.currentWidget() == self.projSearch:
|
1261
|
+
self.projSearch.processReturn()
|
1262
|
+
else:
|
1263
|
+
self.openSelectedItem()
|
1262
1264
|
return
|
1263
1265
|
|
1264
1266
|
@pyqtSlot()
|
1265
1267
|
def _keyPressEscape(self) -> None:
|
1266
|
-
"""Process escape keypress in the main window."""
|
1268
|
+
"""Process an escape keypress in the main window."""
|
1267
1269
|
if self.docEditor.docSearch.isVisible():
|
1268
1270
|
self.docEditor.closeSearch()
|
1269
|
-
elif
|
1270
|
-
|
1271
|
+
elif SHARED.focusMode:
|
1272
|
+
SHARED.setFocusMode(False)
|
1271
1273
|
return
|
1272
1274
|
|
1273
1275
|
@pyqtSlot(int)
|
1274
1276
|
def _mainStackChanged(self, index: int) -> None:
|
1275
1277
|
"""Process main window tab change."""
|
1276
|
-
if index == self.
|
1278
|
+
if self.mainStack.widget(index) == self.outlineView:
|
1277
1279
|
if SHARED.hasProject:
|
1278
1280
|
self.outlineView.refreshTree()
|
1279
1281
|
return
|
@@ -1282,9 +1284,10 @@ class GuiMain(QMainWindow):
|
|
1282
1284
|
def _projStackChanged(self, index: int) -> None:
|
1283
1285
|
"""Process project view tab change."""
|
1284
1286
|
sHandle = None
|
1285
|
-
|
1287
|
+
widget = self.projStack.widget(index)
|
1288
|
+
if widget == self.projView:
|
1286
1289
|
sHandle = self.projView.getSelectedHandle()
|
1287
|
-
elif
|
1290
|
+
elif widget == self.novelView:
|
1288
1291
|
sHandle, _ = self.novelView.getSelectedHandle()
|
1289
1292
|
self.itemDetails.updateViewBox(sHandle)
|
1290
1293
|
return
|