novelWriter 2.4b1__py3-none-any.whl → 2.4rc1__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 (72) hide show
  1. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/METADATA +5 -6
  2. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/RECORD +62 -66
  3. novelwriter/__init__.py +5 -5
  4. novelwriter/assets/icons/none.svg +4 -0
  5. novelwriter/assets/icons/typicons_dark/icons.conf +2 -2
  6. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  7. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  8. novelwriter/assets/icons/typicons_light/icons.conf +2 -2
  9. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  10. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  11. novelwriter/assets/manual.pdf +0 -0
  12. novelwriter/assets/sample.zip +0 -0
  13. novelwriter/common.py +6 -1
  14. novelwriter/config.py +8 -4
  15. novelwriter/core/coretools.py +21 -22
  16. novelwriter/core/status.py +3 -2
  17. novelwriter/core/toodt.py +332 -355
  18. novelwriter/dialogs/about.py +9 -11
  19. novelwriter/dialogs/docmerge.py +17 -14
  20. novelwriter/dialogs/docsplit.py +14 -12
  21. novelwriter/dialogs/editlabel.py +5 -4
  22. novelwriter/dialogs/preferences.py +28 -33
  23. novelwriter/dialogs/projectsettings.py +29 -26
  24. novelwriter/dialogs/quotes.py +10 -9
  25. novelwriter/dialogs/wordlist.py +15 -12
  26. novelwriter/error.py +13 -11
  27. novelwriter/extensions/circularprogress.py +12 -8
  28. novelwriter/extensions/configlayout.py +1 -3
  29. novelwriter/extensions/modified.py +33 -2
  30. novelwriter/extensions/pagedsidebar.py +16 -14
  31. novelwriter/extensions/simpleprogress.py +3 -1
  32. novelwriter/extensions/statusled.py +3 -1
  33. novelwriter/extensions/switch.py +10 -9
  34. novelwriter/extensions/switchbox.py +14 -13
  35. novelwriter/gui/doceditor.py +182 -225
  36. novelwriter/gui/dochighlight.py +4 -4
  37. novelwriter/gui/docviewer.py +53 -57
  38. novelwriter/gui/docviewerpanel.py +16 -13
  39. novelwriter/gui/editordocument.py +4 -4
  40. novelwriter/gui/itemdetails.py +45 -48
  41. novelwriter/gui/noveltree.py +22 -20
  42. novelwriter/gui/outline.py +87 -88
  43. novelwriter/gui/projtree.py +31 -29
  44. novelwriter/gui/search.py +75 -29
  45. novelwriter/gui/sidebar.py +24 -28
  46. novelwriter/gui/statusbar.py +14 -14
  47. novelwriter/gui/theme.py +47 -35
  48. novelwriter/guimain.py +35 -31
  49. novelwriter/shared.py +5 -5
  50. novelwriter/tools/dictionaries.py +13 -12
  51. novelwriter/tools/lipsum.py +20 -17
  52. novelwriter/tools/manusbuild.py +35 -27
  53. novelwriter/tools/manuscript.py +68 -73
  54. novelwriter/tools/manussettings.py +68 -73
  55. novelwriter/tools/noveldetails.py +20 -18
  56. novelwriter/tools/welcome.py +47 -43
  57. novelwriter/tools/writingstats.py +61 -55
  58. novelwriter/types.py +90 -0
  59. novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +0 -4
  60. novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +0 -4
  61. novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +0 -4
  62. novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +0 -4
  63. novelwriter/core/__init__.py +0 -3
  64. novelwriter/dialogs/__init__.py +0 -3
  65. novelwriter/extensions/__init__.py +0 -3
  66. novelwriter/gui/__init__.py +0 -3
  67. novelwriter/text/__init__.py +0 -3
  68. novelwriter/tools/__init__.py +0 -3
  69. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/LICENSE.md +0 -0
  70. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/WHEEL +0 -0
  71. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/entry_points.txt +0 -0
  72. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.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.QtGui import QCloseEvent, QCursor, QIcon
34
33
  from PyQt5.QtCore import Qt, QTimer, pyqtSlot
34
+ from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
35
35
  from PyQt5.QtWidgets import (
36
- QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter,
37
- QStackedWidget, QVBoxLayout, QWidget, qApp
36
+ QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter,
37
+ QStackedWidget, QVBoxLayout, QWidget
38
38
  )
39
39
 
40
40
  from novelwriter import CONFIG, SHARED, __hexversion__, __version__
@@ -109,7 +109,7 @@ class GuiMain(QMainWindow):
109
109
  nwIcon = CONFIG.assetPath("icons") / "novelwriter.svg"
110
110
  self.nwIcon = QIcon(str(nwIcon)) if nwIcon.is_file() else QIcon()
111
111
  self.setWindowIcon(self.nwIcon)
112
- qApp.setWindowIcon(self.nwIcon)
112
+ QApplication.setWindowIcon(self.nwIcon)
113
113
 
114
114
  # Build the GUI
115
115
  # =============
@@ -148,7 +148,7 @@ class GuiMain(QMainWindow):
148
148
  self.treePane.setLayout(self.treeBox)
149
149
 
150
150
  # Splitter : Document Viewer / Document Meta
151
- self.splitView = QSplitter(Qt.Vertical, self)
151
+ self.splitView = QSplitter(Qt.Orientation.Vertical, self)
152
152
  self.splitView.addWidget(self.docViewer)
153
153
  self.splitView.addWidget(self.docViewerPanel)
154
154
  self.splitView.setHandleWidth(hWd)
@@ -158,7 +158,7 @@ class GuiMain(QMainWindow):
158
158
  self.splitView.setCollapsible(1, False)
159
159
 
160
160
  # Splitter : Document Editor / Document Viewer
161
- self.splitDocs = QSplitter(Qt.Horizontal, self)
161
+ self.splitDocs = QSplitter(Qt.Orientation.Horizontal, self)
162
162
  self.splitDocs.addWidget(self.docEditor)
163
163
  self.splitDocs.addWidget(self.splitView)
164
164
  self.splitDocs.setOpaqueResize(False)
@@ -167,7 +167,7 @@ class GuiMain(QMainWindow):
167
167
  self.splitDocs.setCollapsible(1, False)
168
168
 
169
169
  # Splitter : Project Tree / Document Area
170
- self.splitMain = QSplitter(Qt.Horizontal)
170
+ self.splitMain = QSplitter(Qt.Orientation.Horizontal)
171
171
  self.splitMain.setContentsMargins(0, 0, 0, 0)
172
172
  self.splitMain.addWidget(self.treePane)
173
173
  self.splitMain.addWidget(self.splitDocs)
@@ -205,7 +205,7 @@ class GuiMain(QMainWindow):
205
205
  self.setMenuBar(self.mainMenu)
206
206
  self.setCentralWidget(self.mainWidget)
207
207
  self.setStatusBar(self.mainStatus)
208
- self.setContextMenuPolicy(Qt.NoContextMenu) # Issue #1147
208
+ self.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu) # Issue #1147
209
209
 
210
210
  # Connect Signals
211
211
  # ===============
@@ -262,6 +262,7 @@ class GuiMain(QMainWindow):
262
262
  self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
263
263
  self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
264
264
  self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote)
265
+ self.docEditor.docTextChanged.connect(self.projSearch.textChanged)
265
266
 
266
267
  self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
267
268
  self.docViewer.loadDocumentTagRequest.connect(self._followTag)
@@ -327,7 +328,7 @@ class GuiMain(QMainWindow):
327
328
  def postLaunchTasks(self, cmdOpen: str | None) -> None:
328
329
  """Process tasks after the main window has been created."""
329
330
  if cmdOpen:
330
- qApp.processEvents()
331
+ QApplication.processEvents()
331
332
  logger.info("Command line path: %s", cmdOpen)
332
333
  self.openProject(cmdOpen)
333
334
 
@@ -473,12 +474,12 @@ class GuiMain(QMainWindow):
473
474
  break
474
475
 
475
476
  if lastEdited is not None:
476
- qApp.processEvents()
477
+ QApplication.processEvents()
477
478
  self.openDocument(lastEdited, doScroll=True)
478
479
 
479
480
  lastViewed = SHARED.project.data.getLastHandle("viewer")
480
481
  if lastViewed is not None:
481
- qApp.processEvents()
482
+ QApplication.processEvents()
482
483
  self.viewDocument(lastViewed)
483
484
 
484
485
  # Check if we need to rebuild the index
@@ -487,7 +488,7 @@ class GuiMain(QMainWindow):
487
488
  self.rebuildIndex()
488
489
 
489
490
  # Make sure the changed status is set to false on things opened
490
- qApp.processEvents()
491
+ QApplication.processEvents()
491
492
  self.docEditor.setDocumentChanged(False)
492
493
  SHARED.project.setProjectChanged(False)
493
494
 
@@ -737,7 +738,7 @@ class GuiMain(QMainWindow):
737
738
  """Rebuild the entire index."""
738
739
  if SHARED.hasProject:
739
740
  logger.info("Rebuilding index ...")
740
- qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
741
+ QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
741
742
  tStart = time()
742
743
 
743
744
  self.projView.saveProjectTasks()
@@ -751,7 +752,7 @@ class GuiMain(QMainWindow):
751
752
  )
752
753
  self.docEditor.updateTagHighLighting()
753
754
  self._updateStatusWordCount()
754
- qApp.restoreOverrideCursor()
755
+ QApplication.restoreOverrideCursor()
755
756
 
756
757
  if not beQuiet:
757
758
  SHARED.info(self.tr("The project index has been successfully rebuilt."))
@@ -767,7 +768,7 @@ class GuiMain(QMainWindow):
767
768
  """Open the welcome dialog."""
768
769
  dialog = GuiWelcome(self)
769
770
  dialog.openProjectRequest.connect(self._openProjectFromWelcome)
770
- dialog.exec_()
771
+ dialog.exec()
771
772
  return
772
773
 
773
774
  @pyqtSlot()
@@ -775,7 +776,7 @@ class GuiMain(QMainWindow):
775
776
  """Open the preferences dialog."""
776
777
  dialog = GuiPreferences(self)
777
778
  dialog.newPreferencesReady.connect(self._processConfigChanges)
778
- dialog.exec_()
779
+ dialog.exec()
779
780
  return
780
781
 
781
782
  @pyqtSlot()
@@ -785,7 +786,7 @@ class GuiMain(QMainWindow):
785
786
  if SHARED.hasProject:
786
787
  dialog = GuiProjectSettings(self, gotoPage=focusTab)
787
788
  dialog.newProjectSettingsReady.connect(self._processProjectSettingsChanges)
788
- dialog.exec_()
789
+ dialog.exec()
789
790
  return
790
791
 
791
792
  @pyqtSlot()
@@ -796,7 +797,7 @@ class GuiMain(QMainWindow):
796
797
  dialog.setModal(True)
797
798
  dialog.show()
798
799
  dialog.raise_()
799
- qApp.processEvents()
800
+ QApplication.processEvents()
800
801
  dialog.updateValues()
801
802
  return
802
803
 
@@ -809,7 +810,7 @@ class GuiMain(QMainWindow):
809
810
  dialog.setModal(False)
810
811
  dialog.show()
811
812
  dialog.raise_()
812
- qApp.processEvents()
813
+ QApplication.processEvents()
813
814
  dialog.loadContent()
814
815
  return
815
816
 
@@ -819,7 +820,7 @@ class GuiMain(QMainWindow):
819
820
  if SHARED.hasProject:
820
821
  dialog = GuiWordList(self)
821
822
  dialog.newWordListReady.connect(self._processWordListChanges)
822
- dialog.exec_()
823
+ dialog.exec()
823
824
  return
824
825
 
825
826
  @pyqtSlot()
@@ -831,7 +832,7 @@ class GuiMain(QMainWindow):
831
832
  dialog.setModal(False)
832
833
  dialog.show()
833
834
  dialog.raise_()
834
- qApp.processEvents()
835
+ QApplication.processEvents()
835
836
  dialog.populateGUI()
836
837
  return
837
838
 
@@ -842,7 +843,7 @@ class GuiMain(QMainWindow):
842
843
  dialog.setModal(True)
843
844
  dialog.show()
844
845
  dialog.raise_()
845
- qApp.processEvents()
846
+ QApplication.processEvents()
846
847
  dialog.populateGUI()
847
848
  return
848
849
 
@@ -860,7 +861,7 @@ class GuiMain(QMainWindow):
860
861
  dialog.setModal(True)
861
862
  dialog.show()
862
863
  dialog.raise_()
863
- qApp.processEvents()
864
+ QApplication.processEvents()
864
865
  if not dialog.initDialog():
865
866
  dialog.close()
866
867
  SHARED.error(self.tr("Could not initialise the dialog."))
@@ -898,7 +899,8 @@ class GuiMain(QMainWindow):
898
899
  CONFIG.setViewPanePos(self.splitView.sizes())
899
900
 
900
901
  CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
901
- if self.windowState() & Qt.WindowFullScreen != Qt.WindowFullScreen:
902
+ wFull = Qt.WindowState.WindowFullScreen
903
+ if self.windowState() & wFull != wFull:
902
904
  # Ignore window size if in full screen mode
903
905
  CONFIG.setMainWinSize(self.width(), self.height())
904
906
 
@@ -908,7 +910,7 @@ class GuiMain(QMainWindow):
908
910
  CONFIG.saveConfig()
909
911
  self.reportConfErr()
910
912
 
911
- qApp.quit()
913
+ QApplication.quit()
912
914
 
913
915
  return True
914
916
 
@@ -935,7 +937,7 @@ class GuiMain(QMainWindow):
935
937
 
936
938
  def toggleFullScreenMode(self) -> None:
937
939
  """Toggle full screen mode"""
938
- self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
940
+ self.setWindowState(self.windowState() ^ Qt.WindowState.WindowFullScreen)
939
941
  return
940
942
 
941
943
  ##
@@ -1055,7 +1057,7 @@ class GuiMain(QMainWindow):
1055
1057
 
1056
1058
  if theme:
1057
1059
  # We are doing this manually instead of connecting to
1058
- # qApp.paletteChanged since the processing order matters
1060
+ # paletteChanged since the processing order matters
1059
1061
  SHARED.theme.loadTheme()
1060
1062
  self.docEditor.updateTheme()
1061
1063
  self.docViewer.updateTheme()
@@ -1114,7 +1116,7 @@ class GuiMain(QMainWindow):
1114
1116
  @pyqtSlot(Path)
1115
1117
  def _openProjectFromWelcome(self, path: Path) -> None:
1116
1118
  """Handle an open project request from the welcome dialog."""
1117
- qApp.processEvents()
1119
+ QApplication.processEvents()
1118
1120
  self.openProject(path)
1119
1121
  if not SHARED.hasProject:
1120
1122
  self.showWelcomeDialog()
@@ -1167,7 +1169,9 @@ class GuiMain(QMainWindow):
1167
1169
  elif view == nwView.SEARCH:
1168
1170
  self.mainStack.setCurrentWidget(self.splitMain)
1169
1171
  self.projStack.setCurrentWidget(self.projSearch)
1170
- self.projSearch.beginSearch()
1172
+ self.projSearch.beginSearch(
1173
+ self.docEditor.getSelectedText() if self.docEditor.anyFocus() else ""
1174
+ )
1171
1175
  elif view == nwView.OUTLINE:
1172
1176
  self.mainStack.setCurrentWidget(self.outlineView)
1173
1177
  return
@@ -1209,7 +1213,7 @@ class GuiMain(QMainWindow):
1209
1213
  if SHARED.hasProject:
1210
1214
  currTime = time()
1211
1215
  editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime
1212
- userIdle = qApp.applicationState() != Qt.ApplicationActive
1216
+ userIdle = QApplication.applicationState() != Qt.ApplicationState.ApplicationActive
1213
1217
  self.mainStatus.setUserIdle(editIdle or userIdle)
1214
1218
  SHARED.updateIdleTime(currTime, editIdle or userIdle)
1215
1219
  self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
@@ -1266,7 +1270,7 @@ class GuiMain(QMainWindow):
1266
1270
  @pyqtSlot()
1267
1271
  def _keyPressEscape(self) -> None:
1268
1272
  """Process an escape keypress in the main window."""
1269
- if self.docEditor.docSearch.isVisible():
1273
+ if self.docEditor.searchVisible():
1270
1274
  self.docEditor.closeSearch()
1271
1275
  elif SHARED.focusMode:
1272
1276
  SHARED.setFocusMode(False)
novelwriter/shared.py CHANGED
@@ -292,7 +292,7 @@ class SharedData(QObject):
292
292
  self._lastAlert = alert.logMessage
293
293
  if log:
294
294
  logger.info(self._lastAlert, stacklevel=2)
295
- alert.exec_()
295
+ alert.exec()
296
296
  alert.deleteLater()
297
297
  return
298
298
 
@@ -304,7 +304,7 @@ class SharedData(QObject):
304
304
  self._lastAlert = alert.logMessage
305
305
  if log:
306
306
  logger.warning(self._lastAlert, stacklevel=2)
307
- alert.exec_()
307
+ alert.exec()
308
308
  alert.deleteLater()
309
309
  return
310
310
 
@@ -319,7 +319,7 @@ class SharedData(QObject):
319
319
  self._lastAlert = alert.logMessage
320
320
  if log:
321
321
  logger.error(self._lastAlert, stacklevel=2)
322
- alert.exec_()
322
+ alert.exec()
323
323
  alert.deleteLater()
324
324
  return
325
325
 
@@ -329,7 +329,7 @@ class SharedData(QObject):
329
329
  alert.setMessage(text, info, details)
330
330
  alert.setAlertType(_GuiAlert.WARN if warn else _GuiAlert.ASK, True)
331
331
  self._lastAlert = alert.logMessage
332
- alert.exec_()
332
+ alert.exec()
333
333
  isYes = alert.result() == QMessageBox.StandardButton.Yes
334
334
  alert.deleteLater()
335
335
  return isYes
@@ -404,7 +404,7 @@ class _GuiAlert(QMessageBox):
404
404
  self.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
405
405
  else:
406
406
  self.setStandardButtons(QMessageBox.Ok)
407
- pSz = 2*self._theme.baseIconSize
407
+ pSz = 2*self._theme.baseIconHeight
408
408
  if level == self.INFO:
409
409
  self.setIconPixmap(self._theme.getPixmap("alert_info", (pSz, pSz)))
410
410
  self.setWindowTitle(self.tr("Information"))
@@ -28,16 +28,18 @@ import logging
28
28
  from pathlib import Path
29
29
  from zipfile import ZipFile
30
30
 
31
- from PyQt5.QtGui import QCloseEvent, QTextCursor
32
31
  from PyQt5.QtCore import pyqtSlot
32
+ from PyQt5.QtGui import QCloseEvent, QTextCursor
33
33
  from PyQt5.QtWidgets import (
34
- QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, QLabel,
35
- QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget, qApp
34
+ QApplication, QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout,
35
+ QLabel, QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
36
36
  )
37
37
 
38
38
  from novelwriter import CONFIG, SHARED
39
- from novelwriter.error import formatException
40
39
  from novelwriter.common import formatFileFilter, openExternalPath, formatInt, getFileSize
40
+ from novelwriter.error import formatException
41
+ from novelwriter.extensions.modified import NIconToolButton
42
+ from novelwriter.types import QtDialogClose
41
43
 
42
44
  logger = logging.getLogger(__name__)
43
45
 
@@ -54,6 +56,7 @@ class GuiDictionaries(QDialog):
54
56
  self._installPath = None
55
57
  self._currDicts = set()
56
58
 
59
+ iSz = SHARED.theme.baseIconSize
57
60
  iPx = CONFIG.pxInt(4)
58
61
  mPx = CONFIG.pxInt(8)
59
62
  sPx = CONFIG.pxInt(16)
@@ -68,12 +71,11 @@ class GuiDictionaries(QDialog):
68
71
  self.tr("Download a dictionary from one of the links, and add it below."),
69
72
  f"&nbsp;\u203a <a href='{foUrl}'>{foUrl}</a>",
70
73
  f"&nbsp;\u203a <a href='{loUrl}'>{loUrl}</a>",
71
- ]))
74
+ ]), self)
72
75
  self.huInfo.setOpenExternalLinks(True)
73
76
  self.huInfo.setWordWrap(True)
74
77
  self.huInput = QLineEdit(self)
75
- self.huBrowse = QPushButton(self)
76
- self.huBrowse.setIcon(SHARED.theme.getIcon("browse"))
78
+ self.huBrowse = NIconToolButton(self, iSz, "browse")
77
79
  self.huBrowse.clicked.connect(self._doBrowseHunspell)
78
80
  self.huImport = QPushButton(self.tr("Add Dictionary"), self)
79
81
  self.huImport.setIcon(SHARED.theme.getIcon("add"))
@@ -88,11 +90,10 @@ class GuiDictionaries(QDialog):
88
90
  self.huAddBox.addWidget(self.huImport)
89
91
 
90
92
  # Install Path
91
- self.inInfo = QLabel(self.tr("Dictionary install location"))
93
+ self.inInfo = QLabel(self.tr("Dictionary install location"), self)
92
94
  self.inPath = QLineEdit(self)
93
95
  self.inPath.setReadOnly(True)
94
- self.inBrowse = QPushButton(self)
95
- self.inBrowse.setIcon(SHARED.theme.getIcon("browse"))
96
+ self.inBrowse = NIconToolButton(self, iSz, "browse")
96
97
  self.inBrowse.clicked.connect(self._doOpenInstallLocation)
97
98
 
98
99
  self.inBox = QHBoxLayout()
@@ -107,7 +108,7 @@ class GuiDictionaries(QDialog):
107
108
  self.infoBox.setFrameStyle(QFrame.Shape.NoFrame)
108
109
 
109
110
  # Buttons
110
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
111
+ self.buttonBox = QDialogButtonBox(QtDialogClose, self)
111
112
  self.buttonBox.rejected.connect(self._doClose)
112
113
 
113
114
  # Assemble
@@ -158,7 +159,7 @@ class GuiDictionaries(QDialog):
158
159
  "Additional dictionaries found: {0}"
159
160
  ).format(len(self._currDicts)))
160
161
 
161
- qApp.processEvents()
162
+ QApplication.processEvents()
162
163
  self.adjustSize()
163
164
 
164
165
  return True
@@ -35,6 +35,7 @@ from PyQt5.QtWidgets import (
35
35
  from novelwriter import CONFIG, SHARED
36
36
  from novelwriter.common import readTextFile
37
37
  from novelwriter.extensions.switch import NSwitch
38
+ from novelwriter.types import QtAlignLeft, QtAlignRight, QtRoleAction, QtDialogClose
38
39
 
39
40
  logger = logging.getLogger(__name__)
40
41
 
@@ -53,13 +54,14 @@ class GuiLipsum(QDialog):
53
54
 
54
55
  self.setWindowTitle(self.tr("Insert Placeholder Text"))
55
56
 
57
+ vSp = CONFIG.pxInt(4)
58
+ nPx = CONFIG.pxInt(64)
59
+
56
60
  self.innerBox = QHBoxLayout()
57
61
  self.innerBox.setSpacing(CONFIG.pxInt(16))
58
62
 
59
63
  # Icon
60
- nPx = CONFIG.pxInt(64)
61
- vSp = CONFIG.pxInt(4)
62
- self.docIcon = QLabel()
64
+ self.docIcon = QLabel(self)
63
65
  self.docIcon.setPixmap(SHARED.theme.getPixmap("proj_document", (nPx, nPx)))
64
66
 
65
67
  self.leftBox = QVBoxLayout()
@@ -69,35 +71,36 @@ class GuiLipsum(QDialog):
69
71
  self.innerBox.addLayout(self.leftBox)
70
72
 
71
73
  # Form
72
- self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Insert Lorem Ipsum Text")))
74
+ self.headLabel = QLabel(self.tr("Insert Lorem Ipsum Text"))
75
+ self.headLabel.setFont(SHARED.theme.guiFontB)
73
76
 
74
- self.paraLabel = QLabel(self.tr("Number of paragraphs"))
75
- self.paraCount = QSpinBox()
77
+ self.paraLabel = QLabel(self.tr("Number of paragraphs"), self)
78
+ self.paraCount = QSpinBox(self)
76
79
  self.paraCount.setMinimum(1)
77
80
  self.paraCount.setMaximum(100)
78
81
  self.paraCount.setValue(5)
79
82
 
80
- self.randLabel = QLabel(self.tr("Randomise order"))
81
- self.randSwitch = NSwitch()
83
+ self.randLabel = QLabel(self.tr("Randomise order"), self)
84
+ self.randSwitch = NSwitch(self)
82
85
 
83
86
  self.formBox = QGridLayout()
84
- self.formBox.addWidget(self.headLabel, 0, 0, 1, 2, Qt.AlignLeft)
85
- self.formBox.addWidget(self.paraLabel, 1, 0, 1, 1, Qt.AlignLeft)
86
- self.formBox.addWidget(self.paraCount, 1, 1, 1, 1, Qt.AlignRight)
87
- self.formBox.addWidget(self.randLabel, 2, 0, 1, 1, Qt.AlignLeft)
88
- self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1, Qt.AlignRight)
87
+ self.formBox.addWidget(self.headLabel, 0, 0, 1, 2, QtAlignLeft)
88
+ self.formBox.addWidget(self.paraLabel, 1, 0, 1, 1, QtAlignLeft)
89
+ self.formBox.addWidget(self.paraCount, 1, 1, 1, 1, QtAlignRight)
90
+ self.formBox.addWidget(self.randLabel, 2, 0, 1, 1, QtAlignLeft)
91
+ self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1, QtAlignRight)
89
92
  self.formBox.setVerticalSpacing(vSp)
90
93
  self.formBox.setRowStretch(3, 1)
91
94
  self.innerBox.addLayout(self.formBox)
92
95
 
93
96
  # Buttons
94
- self.buttonBox = QDialogButtonBox()
97
+ self.buttonBox = QDialogButtonBox(self)
95
98
  self.buttonBox.rejected.connect(self.close)
96
99
 
97
- self.btnClose = self.buttonBox.addButton(QDialogButtonBox.Close)
100
+ self.btnClose = self.buttonBox.addButton(QtDialogClose)
98
101
  self.btnClose.setAutoDefault(False)
99
102
 
100
- self.btnInsert = self.buttonBox.addButton(self.tr("Insert"), QDialogButtonBox.ActionRole)
103
+ self.btnInsert = self.buttonBox.addButton(self.tr("Insert"), QtRoleAction)
101
104
  self.btnInsert.clicked.connect(self._doInsert)
102
105
  self.btnInsert.setAutoDefault(False)
103
106
 
@@ -127,7 +130,7 @@ class GuiLipsum(QDialog):
127
130
  def getLipsum(cls, parent: QWidget) -> str:
128
131
  """Pop the dialog and return the lipsum text."""
129
132
  cls = GuiLipsum(parent)
130
- cls.exec_()
133
+ cls.exec()
131
134
  text = cls.lipsumText
132
135
  cls.deleteLater()
133
136
  return text
@@ -27,8 +27,8 @@ import logging
27
27
 
28
28
  from pathlib import Path
29
29
 
30
+ from PyQt5.QtCore import QTimer, pyqtSlot
30
31
  from PyQt5.QtGui import QCloseEvent
31
- from PyQt5.QtCore import QSize, QTimer, Qt, pyqtSlot
32
32
  from PyQt5.QtWidgets import (
33
33
  QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox, QFileDialog,
34
34
  QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
@@ -36,13 +36,17 @@ from PyQt5.QtWidgets import (
36
36
  )
37
37
 
38
38
  from novelwriter import CONFIG, SHARED
39
- from novelwriter.enum import nwBuildFmt
40
39
  from novelwriter.common import makeFileNameSafe, openExternalPath
41
40
  from novelwriter.constants import nwLabels
42
- from novelwriter.core.item import NWItem
43
- from novelwriter.core.docbuild import NWBuildDocument
44
41
  from novelwriter.core.buildsettings import BuildSettings
42
+ from novelwriter.core.docbuild import NWBuildDocument
43
+ from novelwriter.core.item import NWItem
44
+ from novelwriter.enum import nwBuildFmt
45
+ from novelwriter.extensions.modified import NIconToolButton
45
46
  from novelwriter.extensions.simpleprogress import NProgressSimple
47
+ from novelwriter.types import (
48
+ QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole
49
+ )
46
50
 
47
51
  logger = logging.getLogger(__name__)
48
52
 
@@ -54,7 +58,7 @@ class GuiManuscriptBuild(QDialog):
54
58
  independently of the Manuscript Build Tool.
55
59
  """
56
60
 
57
- D_KEY = Qt.ItemDataRole.UserRole
61
+ D_KEY = QtUserRole
58
62
 
59
63
  def __init__(self, parent: QWidget, build: BuildSettings):
60
64
  super().__init__(parent=parent)
@@ -69,7 +73,8 @@ class GuiManuscriptBuild(QDialog):
69
73
  self.setMinimumWidth(CONFIG.pxInt(500))
70
74
  self.setMinimumHeight(CONFIG.pxInt(300))
71
75
 
72
- iPx = SHARED.theme.baseIconSize
76
+ iSz = SHARED.theme.baseIconSize
77
+ bSz = SHARED.theme.buttonIconSize
73
78
  sp4 = CONFIG.pxInt(4)
74
79
  sp8 = CONFIG.pxInt(8)
75
80
  sp16 = CONFIG.pxInt(16)
@@ -85,9 +90,9 @@ class GuiManuscriptBuild(QDialog):
85
90
  # Output Format
86
91
  # =============
87
92
 
88
- self.lblFormat = QLabel(self.tr("Output Format"))
89
- self.listFormats = QListWidget()
90
- self.listFormats.setIconSize(QSize(iPx, iPx))
93
+ self.lblFormat = QLabel(self.tr("Output Format"), self)
94
+ self.listFormats = QListWidget(self)
95
+ self.listFormats.setIconSize(iSz)
91
96
  current = None
92
97
  for key in nwBuildFmt:
93
98
  item = QListWidgetItem()
@@ -104,17 +109,17 @@ class GuiManuscriptBuild(QDialog):
104
109
  self.formatBox.addWidget(self.listFormats, 1)
105
110
  self.formatBox.setContentsMargins(0, 0, 0, 0)
106
111
 
107
- self.formatWidget = QWidget()
112
+ self.formatWidget = QWidget(self)
108
113
  self.formatWidget.setLayout(self.formatBox)
109
114
  self.formatWidget.setContentsMargins(0, 0, 0, 0)
110
115
 
111
116
  # Table of Contents
112
117
  # =================
113
118
 
114
- self.lblContent = QLabel(self.tr("Table of Contents"))
119
+ self.lblContent = QLabel(self.tr("Table of Contents"), self)
115
120
 
116
121
  self.listContent = QListWidget(self)
117
- self.listContent.setIconSize(QSize(iPx, iPx))
122
+ self.listContent.setIconSize(iSz)
118
123
  self.listContent.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
119
124
 
120
125
  self.contentBox = QVBoxLayout()
@@ -122,7 +127,7 @@ class GuiManuscriptBuild(QDialog):
122
127
  self.contentBox.addWidget(self.listContent, 0)
123
128
  self.contentBox.setContentsMargins(0, 0, 0, 0)
124
129
 
125
- self.contentWidget = QWidget()
130
+ self.contentWidget = QWidget(self)
126
131
  self.contentWidget.setLayout(self.contentBox)
127
132
  self.contentWidget.setContentsMargins(0, 0, 0, 0)
128
133
 
@@ -134,14 +139,14 @@ class GuiManuscriptBuild(QDialog):
134
139
  font.setUnderline(True)
135
140
  font.setPointSizeF(1.5*font.pointSizeF())
136
141
 
137
- self.lblMain = QLabel(self._build.name)
142
+ self.lblMain = QLabel(self._build.name, self)
138
143
  self.lblMain.setWordWrap(True)
139
144
  self.lblMain.setFont(font)
140
145
 
141
146
  # Build Path
142
- self.lblPath = QLabel(self.tr("Path"))
147
+ self.lblPath = QLabel(self.tr("Path"), self)
143
148
  self.buildPath = QLineEdit(self)
144
- self.btnBrowse = QPushButton(SHARED.theme.getIcon("browse"), "")
149
+ self.btnBrowse = NIconToolButton(self, iSz, "browse")
145
150
 
146
151
  self.pathBox = QHBoxLayout()
147
152
  self.pathBox.addWidget(self.buildPath)
@@ -149,9 +154,9 @@ class GuiManuscriptBuild(QDialog):
149
154
  self.pathBox.setSpacing(sp8)
150
155
 
151
156
  # Build Name
152
- self.lblName = QLabel(self.tr("File Name"))
157
+ self.lblName = QLabel(self.tr("File Name"), self)
153
158
  self.buildName = QLineEdit(self)
154
- self.btnReset = QPushButton(SHARED.theme.getIcon("revert"), "")
159
+ self.btnReset = NIconToolButton(self, iSz, "revert")
155
160
  self.btnReset.setToolTip(self.tr("Reset file name to default"))
156
161
 
157
162
  self.nameBox = QHBoxLayout()
@@ -176,16 +181,19 @@ class GuiManuscriptBuild(QDialog):
176
181
  self.buildBox.setVerticalSpacing(sp4)
177
182
 
178
183
  # Dialog Buttons
179
- self.btnOpen = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Open Folder"))
180
- self.btnBuild = QPushButton(SHARED.theme.getIcon("export"), self.tr("&Build"))
181
- self.dlgButtons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
182
- self.dlgButtons.addButton(self.btnOpen, QDialogButtonBox.ButtonRole.ActionRole)
183
- self.dlgButtons.addButton(self.btnBuild, QDialogButtonBox.ButtonRole.ActionRole)
184
+ self.btnOpen = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Open Folder"), self)
185
+ self.btnOpen.setIconSize(bSz)
186
+ self.btnBuild = QPushButton(SHARED.theme.getIcon("export"), self.tr("&Build"), self)
187
+ self.btnBuild.setIconSize(bSz)
188
+
189
+ self.dlgButtons = QDialogButtonBox(QtDialogClose, self)
190
+ self.dlgButtons.addButton(self.btnOpen, QtRoleAction)
191
+ self.dlgButtons.addButton(self.btnBuild, QtRoleAction)
184
192
 
185
193
  # Assemble GUI
186
194
  # ============
187
195
 
188
- self.mainSplit = QSplitter()
196
+ self.mainSplit = QSplitter(self)
189
197
  self.mainSplit.addWidget(self.formatWidget)
190
198
  self.mainSplit.addWidget(self.contentWidget)
191
199
  self.mainSplit.setHandleWidth(sp16)
@@ -199,7 +207,7 @@ class GuiManuscriptBuild(QDialog):
199
207
  ])
200
208
 
201
209
  self.outerBox = QVBoxLayout()
202
- self.outerBox.addWidget(self.lblMain, 0, Qt.AlignCenter)
210
+ self.outerBox.addWidget(self.lblMain, 0, QtAlignCenter)
203
211
  self.outerBox.addSpacing(sp16)
204
212
  self.outerBox.addWidget(self.mainSplit, 1)
205
213
  self.outerBox.addSpacing(sp4)
@@ -255,12 +263,12 @@ class GuiManuscriptBuild(QDialog):
255
263
  def _dialogButtonClicked(self, button: QAbstractButton):
256
264
  """Handle button clicks from the dialog button box."""
257
265
  role = self.dlgButtons.buttonRole(button)
258
- if role == QDialogButtonBox.ActionRole:
266
+ if role == QtRoleAction:
259
267
  if button == self.btnBuild:
260
268
  self._runBuild()
261
269
  elif button == self.btnOpen:
262
270
  self._openOutputFolder()
263
- elif role == QDialogButtonBox.RejectRole:
271
+ elif role == QtRoleReject:
264
272
  self.close()
265
273
  return
266
274