novelWriter 2.5rc1__py3-none-any.whl → 2.5.2__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 (41) hide show
  1. {novelWriter-2.5rc1.dist-info → novelWriter-2.5.2.dist-info}/METADATA +1 -1
  2. {novelWriter-2.5rc1.dist-info → novelWriter-2.5.2.dist-info}/RECORD +41 -39
  3. {novelWriter-2.5rc1.dist-info → novelWriter-2.5.2.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +3 -3
  5. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  6. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  7. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  8. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  9. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  10. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  11. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  12. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  13. novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  16. novelwriter/assets/i18n/project_pl_PL.json +116 -0
  17. novelwriter/assets/manual.pdf +0 -0
  18. novelwriter/assets/sample.zip +0 -0
  19. novelwriter/assets/text/credits_en.htm +52 -44
  20. novelwriter/common.py +10 -0
  21. novelwriter/core/project.py +15 -4
  22. novelwriter/core/status.py +4 -1
  23. novelwriter/core/storage.py +6 -1
  24. novelwriter/core/tokenizer.py +17 -11
  25. novelwriter/core/toqdoc.py +13 -13
  26. novelwriter/dialogs/preferences.py +14 -27
  27. novelwriter/dialogs/projectsettings.py +6 -10
  28. novelwriter/extensions/configlayout.py +18 -3
  29. novelwriter/extensions/statusled.py +12 -2
  30. novelwriter/gui/doceditor.py +3 -3
  31. novelwriter/gui/docviewer.py +5 -5
  32. novelwriter/gui/docviewerpanel.py +7 -0
  33. novelwriter/gui/outline.py +1 -0
  34. novelwriter/gui/projtree.py +66 -49
  35. novelwriter/guimain.py +50 -42
  36. novelwriter/shared.py +9 -0
  37. novelwriter/tools/manuscript.py +1 -0
  38. novelwriter/tools/welcome.py +9 -0
  39. {novelWriter-2.5rc1.dist-info → novelWriter-2.5.2.dist-info}/LICENSE.md +0 -0
  40. {novelWriter-2.5rc1.dist-info → novelWriter-2.5.2.dist-info}/entry_points.txt +0 -0
  41. {novelWriter-2.5rc1.dist-info → novelWriter-2.5.2.dist-info}/top_level.txt +0 -0
@@ -166,6 +166,7 @@ class GuiProjectView(QWidget):
166
166
 
167
167
  def openProjectTasks(self) -> None:
168
168
  """Run open project tasks."""
169
+ self.populateTree()
169
170
  self.projBar.buildQuickLinksMenu()
170
171
  self.projBar.setEnabled(True)
171
172
  return
@@ -213,7 +214,8 @@ class GuiProjectView(QWidget):
213
214
  @pyqtSlot(str)
214
215
  def updateItemValues(self, tHandle: str) -> None:
215
216
  """Update tree item."""
216
- self.projTree.setTreeItemValues(tHandle)
217
+ if nwItem := SHARED.project.tree[tHandle]:
218
+ self.projTree.setTreeItemValues(nwItem)
217
219
  return
218
220
 
219
221
  @pyqtSlot(str)
@@ -242,6 +244,12 @@ class GuiProjectView(QWidget):
242
244
  self.projTree.createNewNote(tag, itemClass)
243
245
  return
244
246
 
247
+ @pyqtSlot(str)
248
+ def refreshUserLabels(self, kind: str) -> None:
249
+ """Refresh status or importance labels."""
250
+ self.projTree.refreshUserLabels(kind)
251
+ return
252
+
245
253
 
246
254
  class GuiProjectToolBar(QWidget):
247
255
 
@@ -792,11 +800,11 @@ class GuiProjectTree(QTreeWidget):
792
800
 
793
801
  def renameTreeItem(self, tHandle: str, name: str = "") -> None:
794
802
  """Open a dialog to edit the label of an item."""
795
- if tItem := SHARED.project.tree[tHandle]:
796
- newLabel, dlgOk = GuiEditLabel.getLabel(self, text=name or tItem.itemName)
803
+ if nwItem := SHARED.project.tree[tHandle]:
804
+ newLabel, dlgOk = GuiEditLabel.getLabel(self, text=name or nwItem.itemName)
797
805
  if dlgOk:
798
- tItem.setName(newLabel)
799
- self.setTreeItemValues(tHandle)
806
+ nwItem.setName(newLabel)
807
+ self.setTreeItemValues(nwItem)
800
808
  self._alertTreeChange(tHandle, flush=False)
801
809
  return
802
810
 
@@ -1010,44 +1018,52 @@ class GuiProjectTree(QTreeWidget):
1010
1018
 
1011
1019
  return True
1012
1020
 
1013
- def setTreeItemValues(self, tHandle: str) -> None:
1014
- """Set the name and flag values for a tree item from a handle in
1015
- the project tree. Does not trigger a tree change as the data is
1016
- already coming from the project tree.
1021
+ def refreshUserLabels(self, kind: str) -> None:
1022
+ """Refresh status or importance labels."""
1023
+ if kind == "s":
1024
+ for nwItem in SHARED.project.tree:
1025
+ if nwItem.isNovelLike():
1026
+ self.setTreeItemValues(nwItem)
1027
+ elif kind == "i":
1028
+ for nwItem in SHARED.project.tree:
1029
+ if not nwItem.isNovelLike():
1030
+ self.setTreeItemValues(nwItem)
1031
+ return
1032
+
1033
+ def setTreeItemValues(self, nwItem: NWItem | None) -> None:
1034
+ """Set the name and flag values for a tree item in the project
1035
+ tree. Does not trigger a tree change as the data is already
1036
+ coming from project data.
1017
1037
  """
1018
- trItem = self._getTreeItem(tHandle)
1019
- nwItem = SHARED.project.tree[tHandle]
1020
- if trItem is None or nwItem is None:
1021
- return
1022
-
1023
- itemStatus, statusIcon = nwItem.getImportStatus()
1024
- hLevel = nwItem.mainHeading
1025
- itemIcon = SHARED.theme.getItemIcon(
1026
- nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
1027
- )
1038
+ if isinstance(nwItem, NWItem) and (trItem := self._getTreeItem(nwItem.itemHandle)):
1039
+ itemStatus, statusIcon = nwItem.getImportStatus()
1040
+ hLevel = nwItem.mainHeading
1041
+ itemIcon = SHARED.theme.getItemIcon(
1042
+ nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
1043
+ )
1028
1044
 
1029
- trItem.setIcon(self.C_NAME, itemIcon)
1030
- trItem.setText(self.C_NAME, nwItem.itemName)
1031
- trItem.setIcon(self.C_STATUS, statusIcon)
1032
- trItem.setToolTip(self.C_STATUS, itemStatus)
1045
+ trItem.setIcon(self.C_NAME, itemIcon)
1046
+ trItem.setText(self.C_NAME, nwItem.itemName)
1047
+ trItem.setIcon(self.C_STATUS, statusIcon)
1048
+ trItem.setToolTip(self.C_STATUS, itemStatus)
1033
1049
 
1034
- if nwItem.isFileType():
1035
- iconName = "checked" if nwItem.isActive else "unchecked"
1036
- toolTip = self.trActive if nwItem.isActive else self.trInactive
1037
- trItem.setToolTip(self.C_ACTIVE, toolTip)
1038
- else:
1039
- iconName = "noncheckable"
1050
+ if nwItem.isFileType():
1051
+ iconName = "checked" if nwItem.isActive else "unchecked"
1052
+ toolTip = self.trActive if nwItem.isActive else self.trInactive
1053
+ trItem.setToolTip(self.C_ACTIVE, toolTip)
1054
+ else:
1055
+ iconName = "noncheckable"
1040
1056
 
1041
- trItem.setIcon(self.C_ACTIVE, SHARED.theme.getIcon(iconName))
1057
+ trItem.setIcon(self.C_ACTIVE, SHARED.theme.getIcon(iconName))
1042
1058
 
1043
- if CONFIG.emphLabels and nwItem.isDocumentLayout():
1044
- trFont = trItem.font(self.C_NAME)
1045
- trFont.setBold(hLevel == "H1" or hLevel == "H2")
1046
- trFont.setUnderline(hLevel == "H1")
1047
- trItem.setFont(self.C_NAME, trFont)
1059
+ if CONFIG.emphLabels and nwItem.isDocumentLayout():
1060
+ trFont = trItem.font(self.C_NAME)
1061
+ trFont.setBold(hLevel == "H1" or hLevel == "H2")
1062
+ trFont.setUnderline(hLevel == "H1")
1063
+ trItem.setFont(self.C_NAME, trFont)
1048
1064
 
1049
- # Emit Refresh Signal
1050
- self.itemRefreshed.emit(tHandle, nwItem, itemIcon)
1065
+ # Emit Refresh Signal
1066
+ self.itemRefreshed.emit(nwItem.itemHandle, nwItem, itemIcon)
1051
1067
 
1052
1068
  return
1053
1069
 
@@ -1353,7 +1369,8 @@ class GuiProjectTree(QTreeWidget):
1353
1369
  SHARED.project.index.deleteHandle(mHandle)
1354
1370
  else:
1355
1371
  SHARED.project.index.reIndexHandle(mHandle)
1356
- self.setTreeItemValues(mHandle)
1372
+ if mItem := SHARED.project.tree[mHandle]:
1373
+ self.setTreeItemValues(mItem)
1357
1374
 
1358
1375
  # Update word count
1359
1376
  self.propagateCount(tHandle, nwItemS.wordCount, countChildren=True)
@@ -1594,7 +1611,7 @@ class GuiProjectTree(QTreeWidget):
1594
1611
 
1595
1612
  self._treeMap[tHandle] = newItem
1596
1613
  self.propagateCount(tHandle, nwItem.wordCount, countChildren=True)
1597
- self.setTreeItemValues(tHandle)
1614
+ self.setTreeItemValues(nwItem)
1598
1615
  newItem.setExpanded(nwItem.isExpanded)
1599
1616
 
1600
1617
  return newItem
@@ -1971,7 +1988,7 @@ class _TreeContextMenu(QMenu):
1971
1988
  def _toggleItemActive(self) -> None:
1972
1989
  """Toggle the active status of an item."""
1973
1990
  self._item.setActive(not self._item.isActive)
1974
- self.projTree.setTreeItemValues(self._handle)
1991
+ self.projTree.setTreeItemValues(self._item)
1975
1992
  self.projTree._alertTreeChange(self._handle, flush=False)
1976
1993
  return
1977
1994
 
@@ -1984,14 +2001,14 @@ class _TreeContextMenu(QMenu):
1984
2001
  for tItem in self._items:
1985
2002
  if tItem and tItem.isFileType():
1986
2003
  tItem.setActive(isActive)
1987
- self.projTree.setTreeItemValues(tItem.itemHandle)
2004
+ self.projTree.setTreeItemValues(tItem)
1988
2005
  self.projTree._alertTreeChange(tItem.itemHandle, flush=False)
1989
2006
  return
1990
2007
 
1991
2008
  def _changeItemStatus(self, key: str) -> None:
1992
2009
  """Set a new status value of an item."""
1993
2010
  self._item.setStatus(key)
1994
- self.projTree.setTreeItemValues(self._handle)
2011
+ self.projTree.setTreeItemValues(self._item)
1995
2012
  self.projTree._alertTreeChange(self._handle, flush=False)
1996
2013
  return
1997
2014
 
@@ -2000,14 +2017,14 @@ class _TreeContextMenu(QMenu):
2000
2017
  for tItem in self._items:
2001
2018
  if tItem and tItem.isNovelLike():
2002
2019
  tItem.setStatus(key)
2003
- self.projTree.setTreeItemValues(tItem.itemHandle)
2020
+ self.projTree.setTreeItemValues(tItem)
2004
2021
  self.projTree._alertTreeChange(tItem.itemHandle, flush=False)
2005
2022
  return
2006
2023
 
2007
2024
  def _changeItemImport(self, key: str) -> None:
2008
2025
  """Set a new importance value of an item."""
2009
2026
  self._item.setImport(key)
2010
- self.projTree.setTreeItemValues(self._handle)
2027
+ self.projTree.setTreeItemValues(self._item)
2011
2028
  self.projTree._alertTreeChange(self._handle, flush=False)
2012
2029
  return
2013
2030
 
@@ -2016,7 +2033,7 @@ class _TreeContextMenu(QMenu):
2016
2033
  for tItem in self._items:
2017
2034
  if tItem and not tItem.isNovelLike():
2018
2035
  tItem.setImport(key)
2019
- self.projTree.setTreeItemValues(tItem.itemHandle)
2036
+ self.projTree.setTreeItemValues(tItem)
2020
2037
  self.projTree._alertTreeChange(tItem.itemHandle, flush=False)
2021
2038
  return
2022
2039
 
@@ -2024,11 +2041,11 @@ class _TreeContextMenu(QMenu):
2024
2041
  """Set a new item layout value of an item."""
2025
2042
  if itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed():
2026
2043
  self._item.setLayout(nwItemLayout.DOCUMENT)
2027
- self.projTree.setTreeItemValues(self._handle)
2044
+ self.projTree.setTreeItemValues(self._item)
2028
2045
  self.projTree._alertTreeChange(self._handle, flush=False)
2029
2046
  elif itemLayout == nwItemLayout.NOTE:
2030
2047
  self._item.setLayout(nwItemLayout.NOTE)
2031
- self.projTree.setTreeItemValues(self._handle)
2048
+ self.projTree.setTreeItemValues(self._item)
2032
2049
  self.projTree._alertTreeChange(self._handle, flush=False)
2033
2050
  return
2034
2051
 
@@ -2042,12 +2059,12 @@ class _TreeContextMenu(QMenu):
2042
2059
  if msgYes and itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed():
2043
2060
  self._item.setType(nwItemType.FILE)
2044
2061
  self._item.setLayout(nwItemLayout.DOCUMENT)
2045
- self.projTree.setTreeItemValues(self._handle)
2062
+ self.projTree.setTreeItemValues(self._item)
2046
2063
  self.projTree._alertTreeChange(self._handle, flush=False)
2047
2064
  elif msgYes and itemLayout == nwItemLayout.NOTE:
2048
2065
  self._item.setType(nwItemType.FILE)
2049
2066
  self._item.setLayout(nwItemLayout.NOTE)
2050
- self.projTree.setTreeItemValues(self._handle)
2067
+ self.projTree.setTreeItemValues(self._item)
2051
2068
  self.projTree._alertTreeChange(self._handle, flush=False)
2052
2069
  else:
2053
2070
  logger.info("Folder conversion cancelled")
novelwriter/guimain.py CHANGED
@@ -189,9 +189,6 @@ class GuiMain(QMainWindow):
189
189
  self.splitView.setVisible(False)
190
190
  self.docEditor.closeSearch()
191
191
 
192
- # Initialise the Project Tree
193
- self.rebuildTrees()
194
-
195
192
  # Assemble Main Window Elements
196
193
  self.mainBox = QHBoxLayout()
197
194
  self.mainBox.addWidget(self.sideBar)
@@ -222,6 +219,8 @@ class GuiMain(QMainWindow):
222
219
  SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
223
220
  SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
224
221
  SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
222
+ SHARED.statusLabelsChanged.connect(self.docViewerPanel.updateStatusLabels)
223
+ SHARED.statusLabelsChanged.connect(self.projView.refreshUserLabels)
225
224
 
226
225
  self.mainMenu.requestDocAction.connect(self._passDocumentAction)
227
226
  self.mainMenu.requestDocInsert.connect(self._passDocumentInsert)
@@ -461,7 +460,6 @@ class GuiMain(QMainWindow):
461
460
 
462
461
  # Update GUI
463
462
  self._updateWindowTitle(SHARED.project.data.name)
464
- self.rebuildTrees()
465
463
  self.docEditor.toggleSpellCheck(SHARED.project.data.spellCheck)
466
464
  self.mainStatus.setRefTime(SHARED.project.projOpened)
467
465
  self.projView.openProjectTasks()
@@ -526,8 +524,14 @@ class GuiMain(QMainWindow):
526
524
  self.novelView.setActiveHandle(None)
527
525
  return
528
526
 
529
- def openDocument(self, tHandle: str | None, tLine: int | None = None,
530
- changeFocus: bool = True, doScroll: bool = False) -> bool:
527
+ def openDocument(
528
+ self,
529
+ tHandle: str | None,
530
+ tLine: int | None = None,
531
+ sTitle: str | None = None,
532
+ changeFocus: bool = True,
533
+ doScroll: bool = False
534
+ ) -> bool:
531
535
  """Open a specific document, optionally at a given line."""
532
536
  if not SHARED.hasProject:
533
537
  logger.error("No project open")
@@ -537,9 +541,12 @@ class GuiMain(QMainWindow):
537
541
  logger.debug("Requested item '%s' is not a document", tHandle)
538
542
  return False
539
543
 
544
+ if sTitle and tLine is None:
545
+ if hItem := SHARED.project.index.getItemHeading(tHandle, sTitle):
546
+ tLine = hItem.line
547
+
540
548
  self._changeView(nwView.EDITOR)
541
- cHandle = self.docEditor.docHandle
542
- if cHandle == tHandle:
549
+ if tHandle == self.docEditor.docHandle:
543
550
  self.docEditor.setCursorLine(tLine)
544
551
  if changeFocus:
545
552
  self.docEditor.setFocus()
@@ -711,7 +718,6 @@ class GuiMain(QMainWindow):
711
718
  if SHARED.hasProject:
712
719
  tHandle = None
713
720
  sTitle = None
714
- tLine = None
715
721
  if self.projView.treeHasFocus():
716
722
  tHandle = self.projView.getSelectedHandle()
717
723
  elif self.novelView.treeHasFocus():
@@ -722,17 +728,9 @@ class GuiMain(QMainWindow):
722
728
  logger.warning("No item selected")
723
729
  return
724
730
 
725
- if tHandle and sTitle:
726
- if hItem := SHARED.project.index.getItemHeading(tHandle, sTitle):
727
- tLine = hItem.line
728
731
  if tHandle:
729
- self.openDocument(tHandle, tLine=tLine, changeFocus=False, doScroll=False)
730
-
731
- return
732
+ self.openDocument(tHandle, sTitle=sTitle, changeFocus=False, doScroll=False)
732
733
 
733
- def rebuildTrees(self) -> None:
734
- """Rebuild the project tree."""
735
- self.projView.populateTree()
736
734
  return
737
735
 
738
736
  def rebuildIndex(self, beQuiet: bool = False) -> None:
@@ -1006,32 +1004,48 @@ class GuiMain(QMainWindow):
1006
1004
  def _switchFocus(self, paneNo: nwFocus) -> None:
1007
1005
  """Switch focus between main GUI views."""
1008
1006
  if paneNo == nwFocus.TREE:
1009
- if self.projStack.currentWidget() is self.projView:
1010
- if self.projView.treeHasFocus():
1011
- self._changeView(nwView.NOVEL)
1012
- self.novelView.setTreeFocus()
1013
- else:
1014
- self.projView.setTreeFocus()
1015
- elif self.projStack.currentWidget() is self.novelView:
1016
- if self.novelView.treeHasFocus():
1017
- self._changeView(nwView.PROJECT)
1018
- self.projView.setTreeFocus()
1019
- else:
1020
- self.novelView.setTreeFocus()
1007
+ # Decision Matrix
1008
+ # vM | vP | fP | vN | fN | Focus
1009
+ # ----|----|----|----|----|---------
1010
+ # T | T | T | F | F | Novel
1011
+ # T | T | F | F | F | Project
1012
+ # T | F | F | T | T | Project
1013
+ # T | F | F | T | F | Novel
1014
+ # T | F | F | F | F | Project
1015
+ # F | T | T | F | F | Project
1016
+ # F | T | F | F | F | Project
1017
+ # F | F | F | T | T | Novel
1018
+ # F | F | F | T | F | Novel
1019
+ # F | F | F | F | F | Project
1020
+
1021
+ vM = self.mainStack.currentWidget() is self.splitMain
1022
+ vP = self.projStack.currentWidget() is self.projView
1023
+ vN = self.projStack.currentWidget() is self.novelView
1024
+ fP = self.projView.treeHasFocus()
1025
+ fN = self.novelView.treeHasFocus()
1026
+
1027
+ self._changeView(nwView.EDITOR)
1028
+ if (vM and (vP and fP or vN and not fN)) or (not vM and vN):
1029
+ self._changeView(nwView.NOVEL)
1030
+ self.novelView.setTreeFocus()
1021
1031
  else:
1022
1032
  self._changeView(nwView.PROJECT)
1023
1033
  self.projView.setTreeFocus()
1034
+
1024
1035
  elif paneNo == nwFocus.DOCUMENT:
1025
1036
  self._changeView(nwView.EDITOR)
1026
- if self.docEditor.anyFocus():
1037
+ hasViewer = self.splitView.isVisible()
1038
+ if hasViewer and self.docEditor.anyFocus():
1027
1039
  self.docViewer.setFocus()
1028
- elif self.docViewer.anyFocus():
1040
+ elif hasViewer and self.docViewer.anyFocus():
1029
1041
  self.docEditor.setFocus()
1030
1042
  else:
1031
1043
  self.docEditor.setFocus()
1044
+
1032
1045
  elif paneNo == nwFocus.OUTLINE:
1033
1046
  self._changeView(nwView.OUTLINE)
1034
1047
  self.outlineView.setTreeFocus()
1048
+
1035
1049
  return
1036
1050
 
1037
1051
  @pyqtSlot(bool, bool, bool, bool)
@@ -1077,15 +1091,13 @@ class GuiMain(QMainWindow):
1077
1091
 
1078
1092
  return
1079
1093
 
1080
- @pyqtSlot(bool)
1081
- def _processProjectSettingsChanges(self, rebuildTrees: bool) -> None:
1094
+ @pyqtSlot()
1095
+ def _processProjectSettingsChanges(self) -> None:
1082
1096
  """Refresh data dependent on project settings."""
1083
1097
  logger.debug("Applying new project settings")
1084
1098
  SHARED.updateSpellCheckLanguage()
1085
1099
  self.itemDetails.refreshDetails()
1086
1100
  self._updateWindowTitle(SHARED.project.data.name)
1087
- if rebuildTrees:
1088
- self.rebuildTrees()
1089
1101
  return
1090
1102
 
1091
1103
  @pyqtSlot()
@@ -1102,7 +1114,7 @@ class GuiMain(QMainWindow):
1102
1114
  tHandle, sTitle = self._getTagSource(tag)
1103
1115
  if tHandle is not None:
1104
1116
  if mode == nwDocMode.EDIT:
1105
- self.openDocument(tHandle)
1117
+ self.openDocument(tHandle, sTitle=sTitle)
1106
1118
  elif mode == nwDocMode.VIEW:
1107
1119
  self.viewDocument(tHandle=tHandle, sTitle=sTitle)
1108
1120
  return
@@ -1121,11 +1133,7 @@ class GuiMain(QMainWindow):
1121
1133
  """Handle an open document request."""
1122
1134
  if tHandle is not None:
1123
1135
  if mode == nwDocMode.EDIT:
1124
- tLine = None
1125
- hItem = SHARED.project.index.getItemHeading(tHandle, sTitle)
1126
- if hItem is not None:
1127
- tLine = hItem.line
1128
- self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
1136
+ self.openDocument(tHandle, sTitle=sTitle, changeFocus=setFocus)
1129
1137
  elif mode == nwDocMode.VIEW:
1130
1138
  self.viewDocument(tHandle=tHandle, sTitle=sTitle)
1131
1139
  return
novelwriter/shared.py CHANGED
@@ -64,6 +64,7 @@ class SharedData(QObject):
64
64
  indexCleared = pyqtSignal()
65
65
  indexAvailable = pyqtSignal()
66
66
  mainClockTick = pyqtSignal()
67
+ statusLabelsChanged = pyqtSignal(str)
67
68
 
68
69
  def __init__(self) -> None:
69
70
  super().__init__()
@@ -309,6 +310,14 @@ class SharedData(QObject):
309
310
  self.indexAvailable.emit()
310
311
  return
311
312
 
313
+ def projectSingalProxy(self, data: dict) -> None:
314
+ """Emit signals on project data change."""
315
+ event = data.get("event")
316
+ logger.debug("Received '%s' event from project data", event)
317
+ if event == "statusLabels":
318
+ self.statusLabelsChanged.emit(data.get("kind", ""))
319
+ return
320
+
312
321
  ##
313
322
  # Alert Boxes
314
323
  ##
@@ -823,6 +823,7 @@ class _PreviewWidget(QTextBrowser):
823
823
 
824
824
  document.setDocumentMargin(CONFIG.getTextMargin())
825
825
  self.setDocument(document)
826
+ self.setTabStopDistance(CONFIG.getTabWidth())
826
827
 
827
828
  self._docTime = int(time())
828
829
  self._updateBuildAge()
@@ -208,6 +208,7 @@ class GuiWelcome(NDialog):
208
208
  """Show the create new project page."""
209
209
  self.mainStack.setCurrentWidget(self.tabNew)
210
210
  self._setButtonVisibility()
211
+ self.tabNew.enterForm()
211
212
  return
212
213
 
213
214
  @pyqtSlot()
@@ -503,6 +504,8 @@ class _NewProjectPage(QWidget):
503
504
  self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
504
505
  self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
505
506
 
507
+ self.enterForm = self.projectForm.enterForm
508
+
506
509
  # Assemble
507
510
  # ========
508
511
 
@@ -696,6 +699,12 @@ class _NewProjectForm(QWidget):
696
699
 
697
700
  return
698
701
 
702
+ def enterForm(self) -> None:
703
+ """Focus the project name field when entering the form."""
704
+ self.projName.setFocus()
705
+ self.projName.selectAll()
706
+ return
707
+
699
708
  def getProjectData(self) -> dict:
700
709
  """Collect form data and return it as a dictionary."""
701
710
  roots = []