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.
Files changed (109) hide show
  1. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/METADATA +3 -3
  2. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/RECORD +105 -76
  3. novelwriter/__init__.py +6 -24
  4. novelwriter/assets/i18n/project_de_DE.json +10 -0
  5. novelwriter/assets/i18n/project_en_GB.json +11 -0
  6. novelwriter/assets/i18n/project_en_US.json +10 -0
  7. novelwriter/assets/i18n/project_ja_JP.json +11 -1
  8. novelwriter/assets/i18n/project_nb_NO.json +10 -0
  9. novelwriter/assets/i18n/project_nn_NO.json +10 -0
  10. novelwriter/assets/icons/novelwriter.ico +0 -0
  11. novelwriter/assets/icons/novelwriter.svg +8 -183
  12. novelwriter/assets/icons/typicons_dark/icons.conf +17 -2
  13. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
  14. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
  15. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
  16. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
  17. novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
  18. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +4 -0
  19. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +4 -0
  20. novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +8 -0
  21. novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +8 -0
  22. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +4 -0
  23. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +5 -0
  24. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +5 -0
  25. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +5 -0
  26. novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
  27. novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +4 -0
  28. novelwriter/assets/icons/typicons_light/icons.conf +17 -2
  29. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
  30. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
  31. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
  32. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
  33. novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
  34. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +4 -0
  35. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +4 -0
  36. novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +8 -0
  37. novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +8 -0
  38. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +4 -0
  39. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +5 -0
  40. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +5 -0
  41. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +5 -0
  42. novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
  43. novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +4 -0
  44. novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
  45. novelwriter/assets/icons/x-novelwriter-project.svg +7 -206
  46. novelwriter/assets/manual.pdf +0 -0
  47. novelwriter/assets/sample.zip +0 -0
  48. novelwriter/assets/syntax/default_dark.conf +1 -0
  49. novelwriter/assets/syntax/default_light.conf +1 -0
  50. novelwriter/assets/syntax/grey_dark.conf +1 -0
  51. novelwriter/assets/syntax/grey_light.conf +1 -0
  52. novelwriter/assets/syntax/light_owl.conf +1 -0
  53. novelwriter/assets/syntax/night_owl.conf +1 -0
  54. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  55. novelwriter/assets/syntax/solarized_light.conf +1 -0
  56. novelwriter/assets/syntax/tomorrow.conf +1 -0
  57. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  58. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  59. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  60. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  61. novelwriter/assets/text/credits_en.htm +7 -0
  62. novelwriter/assets/text/release_notes.htm +7 -37
  63. novelwriter/common.py +22 -1
  64. novelwriter/config.py +27 -42
  65. novelwriter/constants.py +45 -7
  66. novelwriter/core/buildsettings.py +40 -24
  67. novelwriter/core/coretools.py +8 -1
  68. novelwriter/core/docbuild.py +2 -6
  69. novelwriter/core/index.py +264 -175
  70. novelwriter/core/options.py +8 -3
  71. novelwriter/core/project.py +2 -2
  72. novelwriter/core/projectdata.py +3 -3
  73. novelwriter/core/tohtml.py +60 -59
  74. novelwriter/core/tokenizer.py +110 -70
  75. novelwriter/core/tomd.py +51 -38
  76. novelwriter/core/toodt.py +184 -147
  77. novelwriter/dialogs/preferences.py +75 -106
  78. novelwriter/dialogs/projsettings.py +101 -110
  79. novelwriter/dialogs/updates.py +25 -14
  80. novelwriter/enum.py +28 -3
  81. novelwriter/extensions/novelselector.py +1 -1
  82. novelwriter/gui/doceditor.py +1345 -1235
  83. novelwriter/gui/dochighlight.py +98 -62
  84. novelwriter/gui/docviewer.py +151 -340
  85. novelwriter/gui/docviewerpanel.py +457 -0
  86. novelwriter/gui/editordocument.py +126 -0
  87. novelwriter/gui/mainmenu.py +350 -300
  88. novelwriter/gui/noveltree.py +101 -125
  89. novelwriter/gui/outline.py +154 -171
  90. novelwriter/gui/projtree.py +480 -380
  91. novelwriter/gui/sidebar.py +106 -75
  92. novelwriter/gui/statusbar.py +1 -1
  93. novelwriter/gui/theme.py +114 -75
  94. novelwriter/guimain.py +353 -254
  95. novelwriter/shared.py +36 -3
  96. novelwriter/tools/dictionaries.py +268 -0
  97. novelwriter/tools/manusbuild.py +17 -6
  98. novelwriter/tools/manuscript.py +11 -3
  99. novelwriter/tools/manussettings.py +0 -14
  100. novelwriter/tools/projwizard.py +16 -2
  101. novelwriter/tools/writingstats.py +1 -1
  102. novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
  103. novelwriter/assets/icons/typicons_dark/typ_th-menu.svg +0 -4
  104. novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
  105. novelwriter/assets/icons/typicons_light/typ_th-menu.svg +0 -4
  106. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/LICENSE.md +0 -0
  107. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/WHEEL +0 -0
  108. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/entry_points.txt +0 -0
  109. {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, QThreadPool, pyqtSlot
34
- from PyQt5.QtGui import QCloseEvent, QCursor, QIcon, QKeySequence
33
+ from PyQt5.QtCore import Qt, QTimer, pyqtSlot
34
+ from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
35
35
  from PyQt5.QtWidgets import (
36
- qApp, QDialog, QFileDialog, QMainWindow, QMessageBox, QShortcut, QSplitter,
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 GuiDocViewDetails, GuiDocViewer
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 = GuiMainStatus(self)
138
- self.projView = GuiProjectView(self)
139
- self.novelView = GuiNovelView(self)
140
- self.docEditor = GuiDocEditor(self)
141
- self.viewMeta = GuiDocViewDetails(self)
142
- self.docViewer = GuiDocViewer(self)
143
- self.itemDetails = GuiItemDetails(self)
144
- self.outlineView = GuiOutlineView(self)
145
- self.mainMenu = GuiMainMenu(self)
146
- self.viewsBar = GuiSideBar(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.viewMeta)
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 = self.splitMain.indexOf(self.treePane)
195
- self.idxMain = self.splitMain.indexOf(self.splitDocs)
196
- self.idxEditor = self.splitDocs.indexOf(self.docEditor)
197
- self.idxViewer = self.splitDocs.indexOf(self.splitView)
198
- self.idxViewDoc = self.splitView.indexOf(self.docViewer)
199
- self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
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.idxViewMeta, False)
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
- # Set Main Window Elements
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.mainStack)
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.viewsBar.viewChangeRequested.connect(self._changeView)
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(QKeySequence(Qt.Key_Return))
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(QKeySequence(Qt.Key_Enter))
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(QKeySequence(Qt.Key_Escape))
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 logger.getEffectiveLevel() > logging.DEBUG:
315
- SHARED.warn(self.tr(
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 a live project "
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=0, doScroll=True)
651
+ self.openDocument(nHandle, tLine=1, doScroll=True)
614
652
  return True
615
653
  elif wrapAround:
616
- self.openDocument(fHandle, tLine=0, doScroll=True)
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.viewMeta.setVisible(CONFIG.showRefPanel)
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.viewsBar.updateTheme()
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.viewMeta.isVisible():
1117
+ if self.docViewerPanel.isVisible():
1075
1118
  CONFIG.setViewPanePos(self.splitView.sizes())
1076
1119
 
1077
- CONFIG.showRefPanel = self.viewMeta.isVisible()
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 toggleFocusMode(self) -> bool:
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 False
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.viewsBar.setVisible(isVisible)
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
- return True
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
- def toggleFullScreenMode(self) -> None:
1164
- """Toggle full screen mode"""
1165
- self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
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