novelWriter 2.6b1__py3-none-any.whl → 2.6rc1__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 (114) hide show
  1. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/METADATA +4 -4
  2. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/RECORD +114 -98
  3. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +50 -11
  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_ru_RU.qm +0 -0
  16. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  17. novelwriter/assets/i18n/project_de_DE.json +2 -2
  18. novelwriter/assets/i18n/project_ru_RU.json +11 -0
  19. novelwriter/assets/icons/typicons_dark/icons.conf +7 -0
  20. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
  21. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
  22. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
  23. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
  24. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
  25. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
  26. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
  27. novelwriter/assets/icons/typicons_light/icons.conf +7 -0
  28. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
  29. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
  30. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
  31. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
  32. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
  33. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
  34. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
  35. novelwriter/assets/manual.pdf +0 -0
  36. novelwriter/assets/sample.zip +0 -0
  37. novelwriter/assets/text/credits_en.htm +1 -0
  38. novelwriter/common.py +38 -3
  39. novelwriter/config.py +19 -13
  40. novelwriter/constants.py +60 -45
  41. novelwriter/core/buildsettings.py +1 -1
  42. novelwriter/core/coretools.py +112 -126
  43. novelwriter/core/docbuild.py +4 -3
  44. novelwriter/core/document.py +1 -1
  45. novelwriter/core/index.py +10 -20
  46. novelwriter/core/item.py +40 -7
  47. novelwriter/core/itemmodel.py +518 -0
  48. novelwriter/core/options.py +1 -1
  49. novelwriter/core/project.py +68 -90
  50. novelwriter/core/projectdata.py +8 -2
  51. novelwriter/core/projectxml.py +1 -1
  52. novelwriter/core/sessions.py +1 -1
  53. novelwriter/core/spellcheck.py +1 -1
  54. novelwriter/core/status.py +24 -8
  55. novelwriter/core/storage.py +1 -1
  56. novelwriter/core/tree.py +269 -288
  57. novelwriter/dialogs/about.py +1 -1
  58. novelwriter/dialogs/docmerge.py +8 -18
  59. novelwriter/dialogs/docsplit.py +1 -1
  60. novelwriter/dialogs/editlabel.py +1 -1
  61. novelwriter/dialogs/preferences.py +4 -4
  62. novelwriter/dialogs/projectsettings.py +148 -98
  63. novelwriter/dialogs/quotes.py +1 -1
  64. novelwriter/dialogs/wordlist.py +11 -10
  65. novelwriter/enum.py +8 -1
  66. novelwriter/error.py +2 -2
  67. novelwriter/extensions/configlayout.py +7 -5
  68. novelwriter/extensions/eventfilters.py +1 -1
  69. novelwriter/extensions/modified.py +17 -5
  70. novelwriter/extensions/novelselector.py +1 -1
  71. novelwriter/extensions/pagedsidebar.py +4 -4
  72. novelwriter/extensions/progressbars.py +4 -4
  73. novelwriter/extensions/statusled.py +3 -3
  74. novelwriter/extensions/switch.py +3 -3
  75. novelwriter/extensions/switchbox.py +1 -1
  76. novelwriter/extensions/versioninfo.py +1 -1
  77. novelwriter/formats/shared.py +1 -1
  78. novelwriter/formats/todocx.py +35 -39
  79. novelwriter/formats/tohtml.py +15 -16
  80. novelwriter/formats/tokenizer.py +26 -22
  81. novelwriter/formats/tomarkdown.py +1 -1
  82. novelwriter/formats/toodt.py +54 -125
  83. novelwriter/formats/toqdoc.py +93 -45
  84. novelwriter/formats/toraw.py +1 -1
  85. novelwriter/gui/doceditor.py +233 -220
  86. novelwriter/gui/dochighlight.py +1 -1
  87. novelwriter/gui/docviewer.py +39 -10
  88. novelwriter/gui/docviewerpanel.py +15 -23
  89. novelwriter/gui/editordocument.py +1 -1
  90. novelwriter/gui/itemdetails.py +20 -27
  91. novelwriter/gui/mainmenu.py +14 -9
  92. novelwriter/gui/noveltree.py +13 -13
  93. novelwriter/gui/outline.py +18 -20
  94. novelwriter/gui/projtree.py +545 -1201
  95. novelwriter/gui/search.py +11 -19
  96. novelwriter/gui/sidebar.py +1 -1
  97. novelwriter/gui/statusbar.py +20 -3
  98. novelwriter/gui/theme.py +8 -4
  99. novelwriter/guimain.py +60 -48
  100. novelwriter/shared.py +53 -24
  101. novelwriter/text/counting.py +1 -1
  102. novelwriter/text/patterns.py +18 -6
  103. novelwriter/tools/dictionaries.py +1 -1
  104. novelwriter/tools/lipsum.py +1 -1
  105. novelwriter/tools/manusbuild.py +14 -12
  106. novelwriter/tools/manuscript.py +7 -7
  107. novelwriter/tools/manussettings.py +43 -53
  108. novelwriter/tools/noveldetails.py +1 -1
  109. novelwriter/tools/welcome.py +1 -1
  110. novelwriter/tools/writingstats.py +1 -1
  111. novelwriter/types.py +9 -3
  112. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/LICENSE.md +0 -0
  113. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/entry_points.txt +0 -0
  114. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/top_level.txt +0 -0
@@ -9,7 +9,7 @@ Created: 2022-11-03 [2.0rc2] ProjectBuilder
9
9
  Created: 2023-07-20 [2.1b1] DocDuplicator
10
10
 
11
11
  This file is a part of novelWriter
12
- Copyright 2018–2024, Veronica Berglyd Olsen
12
+ Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
13
13
 
14
14
  This program is free software: you can redistribute it and/or modify
15
15
  it under the terms of the GNU General Public License as published by
@@ -56,10 +56,17 @@ class DocMerger:
56
56
  def __init__(self, project: NWProject) -> None:
57
57
  self._project = project
58
58
  self._error = ""
59
- self._targetDoc = None
60
- self._targetText = []
59
+ self._target = None
60
+ self._text = []
61
61
  return
62
62
 
63
+ @property
64
+ def targetHandle(self) -> str | None:
65
+ """Get the handle of the target document."""
66
+ if self._target:
67
+ return self._target.itemHandle
68
+ return None
69
+
63
70
  ##
64
71
  # Methods
65
72
  ##
@@ -72,63 +79,56 @@ class DocMerger:
72
79
  """Set the target document for the merging. Calling this
73
80
  function resets the class.
74
81
  """
75
- self._targetDoc = tHandle
76
- self._targetText = []
82
+ self._target = self._project.tree[tHandle]
83
+ self._text = []
77
84
  return
78
85
 
79
- def newTargetDoc(self, srcHandle: str, docLabel: str) -> str | None:
86
+ def newTargetDoc(self, sHandle: str, label: str) -> None:
80
87
  """Create a brand new target document based on a source handle
81
88
  and a new doc label. Calling this function resets the class.
82
89
  """
83
- srcItem = self._project.tree[srcHandle]
84
- if srcItem is None or srcItem.itemParent is None:
85
- return None
86
-
87
- newHandle = self._project.newFile(docLabel, srcItem.itemParent)
88
- newItem = self._project.tree[newHandle]
89
- if isinstance(newItem, NWItem):
90
- newItem.setLayout(srcItem.itemLayout)
91
- newItem.setStatus(srcItem.itemStatus)
92
- newItem.setImport(srcItem.itemImport)
93
-
94
- self._targetDoc = newHandle
95
- self._targetText = []
96
-
97
- return newHandle
90
+ sItem = self._project.tree[sHandle]
91
+ if sItem and sItem.itemParent:
92
+ tHandle = self._project.newFile(label, sItem.itemParent)
93
+ if nwItem := self._project.tree[tHandle]:
94
+ nwItem.setLayout(sItem.itemLayout)
95
+ nwItem.setStatus(sItem.itemStatus)
96
+ nwItem.setImport(sItem.itemImport)
97
+ nwItem.notifyToRefresh()
98
+ self._target = nwItem
99
+ self._text = []
100
+ return
98
101
 
99
- def appendText(self, srcHandle: str, addComment: bool, cmtPrefix: str) -> bool:
102
+ def appendText(self, sHandle: str, addComment: bool, cmtPrefix: str) -> None:
100
103
  """Append text from an existing document to the text buffer."""
101
- srcItem = self._project.tree[srcHandle]
102
- if srcItem is None:
103
- return False
104
-
105
- docText = self._project.storage.getDocumentText(srcHandle).rstrip("\n")
106
- if addComment:
107
- docInfo = srcItem.describeMe()
108
- docSt, _ = srcItem.getImportStatus()
109
- cmtLine = f"% {cmtPrefix} {docInfo}: {srcItem.itemName} [{docSt}]\n\n"
110
- docText = cmtLine + docText
111
-
112
- self._targetText.append(docText)
113
-
114
- return True
104
+ if item := self._project.tree[sHandle]:
105
+ text = self._project.storage.getDocumentText(sHandle).rstrip("\n")
106
+ if addComment:
107
+ info = item.describeMe()
108
+ status, _ = item.getImportStatus()
109
+ text = f"% {cmtPrefix} {info}: {item.itemName} [{status}]\n\n{text}"
110
+ self._text.append(text)
111
+ return
115
112
 
116
113
  def writeTargetDoc(self) -> bool:
117
114
  """Write the accumulated text into the designated target
118
115
  document, appending any existing text.
119
116
  """
120
- if self._targetDoc is None:
121
- return False
117
+ if self._target:
118
+ outDoc = self._project.storage.getDocument(self._target.itemHandle)
119
+ if text := (outDoc.readDocument() or "").rstrip("\n"):
120
+ self._text.insert(0, text)
122
121
 
123
- outDoc = self._project.storage.getDocument(self._targetDoc)
124
- if text := (outDoc.readDocument() or "").rstrip("\n"):
125
- self._targetText.insert(0, text)
122
+ status = outDoc.writeDocument("\n\n".join(self._text) + "\n\n")
123
+ if not status:
124
+ self._error = outDoc.getError()
126
125
 
127
- status = outDoc.writeDocument("\n\n".join(self._targetText) + "\n\n")
128
- if not status:
129
- self._error = outDoc.getError()
126
+ self._project.index.reIndexHandle(self._target.itemHandle)
127
+ self._target.notifyToRefresh()
130
128
 
131
- return status
129
+ return status
130
+
131
+ return False
132
132
 
133
133
 
134
134
  class DocSplitter:
@@ -172,23 +172,19 @@ class DocSplitter:
172
172
  self._inFolder = False
173
173
  return
174
174
 
175
- def newParentFolder(self, pHandle: str, folderLabel: str) -> str | None:
175
+ def newParentFolder(self, pHandle: str, folderLabel: str) -> None:
176
176
  """Create a new folder that will be the top level parent item
177
177
  for the new documents.
178
178
  """
179
- if self._srcItem is None:
180
- return None
181
-
182
- newHandle = self._project.newFolder(folderLabel, pHandle)
183
- newItem = self._project.tree[newHandle]
184
- if isinstance(newItem, NWItem):
185
- newItem.setStatus(self._srcItem.itemStatus)
186
- newItem.setImport(self._srcItem.itemImport)
187
-
188
- self._parHandle = newHandle
189
- self._inFolder = True
190
-
191
- return newHandle
179
+ if self._srcItem:
180
+ nHandle = self._project.newFolder(folderLabel, pHandle)
181
+ if nwItem := self._project.tree[nHandle]:
182
+ nwItem.setStatus(self._srcItem.itemStatus)
183
+ nwItem.setImport(self._srcItem.itemImport)
184
+ nwItem.notifyToRefresh()
185
+ self._parHandle = nHandle
186
+ self._inFolder = True
187
+ return
192
188
 
193
189
  def splitDocument(self, splitData: list, splitText: list[str]) -> None:
194
190
  """Loop through the split data record and perform the split job
@@ -202,58 +198,50 @@ class DocSplitter:
202
198
  self._rawData.insert(0, (chunk, hLevel, hLabel))
203
199
  return
204
200
 
205
- def writeDocuments(self, docHierarchy: bool) -> Iterable[tuple[bool, str | None, str | None]]:
201
+ def writeDocuments(self, docHierarchy: bool) -> Iterable[bool]:
206
202
  """An iterator that will write each document in the buffer, and
207
203
  return its new handle, parent handle, and sibling handle.
208
204
  """
209
- if self._srcHandle is None or self._srcItem is None or self._parHandle is None:
210
- return
211
-
212
- pHandle = self._parHandle
213
- nHandle = self._parHandle if self._inFolder else self._srcHandle
214
- hHandle = [self._parHandle, None, None, None, None]
215
-
216
- pLevel = 0
217
- for docText, hLevel, docLabel in self._rawData:
218
-
219
- hLevel = minmax(hLevel, 1, 4)
220
- if pLevel == 0:
221
- pLevel = hLevel
222
-
223
- if docHierarchy:
224
- if hLevel == 1:
225
- pHandle = self._parHandle
226
- elif hLevel == 2:
227
- pHandle = hHandle[1] or hHandle[0]
228
- elif hLevel == 3:
229
- pHandle = hHandle[2] or hHandle[1] or hHandle[0]
230
- elif hLevel == 4:
231
- pHandle = hHandle[3] or hHandle[2] or hHandle[1] or hHandle[0]
232
-
233
- if hLevel < pLevel:
234
- nHandle = hHandle[hLevel] or hHandle[0]
235
- elif hLevel > pLevel:
236
- nHandle = pHandle
237
-
238
- dHandle = self._project.newFile(docLabel, pHandle)
239
- hHandle[hLevel] = dHandle
240
-
241
- newItem = self._project.tree[dHandle]
242
- if isinstance(newItem, NWItem):
243
- newItem.setStatus(self._srcItem.itemStatus)
244
- newItem.setImport(self._srcItem.itemImport)
245
-
246
- outDoc = self._project.storage.getDocument(dHandle)
247
- status = outDoc.writeDocument("\n".join(docText))
248
- if not status:
249
- self._error = outDoc.getError()
250
-
251
- yield status, dHandle, nHandle
252
-
253
- hHandle[hLevel] = dHandle
254
- nHandle = dHandle
255
- pLevel = hLevel
256
-
205
+ if self._srcHandle and self._srcItem and self._parHandle:
206
+ pHandle = self._parHandle
207
+ hHandle = [self._parHandle, None, None, None, None]
208
+ pLevel = 0
209
+ for docText, hLevel, docLabel in self._rawData:
210
+
211
+ hLevel = minmax(hLevel, 1, 4)
212
+ if pLevel == 0:
213
+ pLevel = hLevel
214
+
215
+ if docHierarchy:
216
+ if hLevel == 1:
217
+ pHandle = self._parHandle
218
+ elif hLevel == 2:
219
+ pHandle = hHandle[1] or hHandle[0]
220
+ elif hLevel == 3:
221
+ pHandle = hHandle[2] or hHandle[1] or hHandle[0]
222
+ elif hLevel == 4:
223
+ pHandle = hHandle[3] or hHandle[2] or hHandle[1] or hHandle[0]
224
+
225
+ if (
226
+ (dHandle := self._project.newFile(docLabel, pHandle))
227
+ and (nwItem := self._project.tree[dHandle])
228
+ ):
229
+ hHandle[hLevel] = dHandle
230
+ nwItem.setStatus(self._srcItem.itemStatus)
231
+ nwItem.setImport(self._srcItem.itemImport)
232
+
233
+ outDoc = self._project.storage.getDocument(dHandle)
234
+ status = outDoc.writeDocument("\n".join(docText))
235
+ if not status:
236
+ self._error = outDoc.getError()
237
+
238
+ self._project.index.reIndexHandle(dHandle)
239
+ nwItem.notifyToRefresh()
240
+
241
+ yield status
242
+
243
+ hHandle[hLevel] = dHandle
244
+ pLevel = hLevel
257
245
  return
258
246
 
259
247
 
@@ -270,29 +258,27 @@ class DocDuplicator:
270
258
  # Methods
271
259
  ##
272
260
 
273
- def duplicate(self, items: list[str]) -> Iterable[tuple[str, str | None]]:
261
+ def duplicate(self, items: list[str]) -> list[str]:
274
262
  """Run through a list of items, duplicate them, and copy the
275
263
  text content if they are documents.
276
264
  """
265
+ result = []
266
+ after = True
277
267
  if items:
278
- nHandle = items[0]
279
268
  hMap: dict[str, str | None] = {t: None for t in items}
280
269
  for tHandle in items:
281
- newItem = self._project.tree.duplicate(tHandle)
282
- if newItem is None:
283
- return
284
- hMap[tHandle] = newItem.itemHandle
285
- if newItem.itemParent in hMap:
286
- newItem.setParent(hMap[newItem.itemParent])
287
- self._project.tree.updateItemData(newItem.itemHandle)
288
- if newItem.isFileType():
289
- newDoc = self._project.storage.getDocument(newItem.itemHandle)
290
- if newDoc.fileExists():
291
- return
292
- newDoc.writeDocument(self._project.storage.getDocumentText(tHandle))
293
- yield newItem.itemHandle, nHandle
294
- nHandle = None
295
- return
270
+ if oldItem := self._project.tree[tHandle]:
271
+ pHandle = hMap.get(oldItem.itemParent or "") or oldItem.itemParent
272
+ if newItem := self._project.tree.duplicate(tHandle, pHandle, after):
273
+ hMap[tHandle] = newItem.itemHandle
274
+ if newItem.isFileType():
275
+ self._project.copyFileContent(newItem.itemHandle, tHandle)
276
+ newItem.notifyToRefresh()
277
+ result.append(newItem.itemHandle)
278
+ after = False
279
+ else:
280
+ break
281
+ return result
296
282
 
297
283
 
298
284
  class DocSearch:
@@ -523,7 +509,7 @@ class ProjectBuilder:
523
509
 
524
510
  # Also add the archive and trash folders
525
511
  project.newRoot(nwItemClass.ARCHIVE)
526
- project.trashFolder()
512
+ project.tree.trash # Triggers the creation of Trash
527
513
 
528
514
  project.saveProject()
529
515
  project.closeProject()
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2022-12-01 [2.1b1] NWBuildDocument
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
10
10
 
11
11
  This program is free software: you can redistribute it and/or modify
12
12
  it under the terms of the GNU General Public License as published by
@@ -176,8 +176,9 @@ class NWBuildDocument:
176
176
 
177
177
  elif bFormat == nwBuildFmt.PDF:
178
178
  makeObj = ToQTextDocument(self._project)
179
+ makeObj.disableAnchors()
179
180
  filtered = self._setupBuild(makeObj)
180
- makeObj.initDocument()
181
+ makeObj.initDocument(pdf=True)
181
182
  yield from self._iterBuild(makeObj, filtered)
182
183
  makeObj.closeDocument()
183
184
 
@@ -217,7 +218,7 @@ class NWBuildDocument:
217
218
  textFont = QFont(CONFIG.textFont)
218
219
  textFont.fromString(self._build.getStr("format.textFont"))
219
220
 
220
- bldObj.setFont(textFont)
221
+ bldObj.setTextFont(textFont)
221
222
  bldObj.setLanguage(self._project.data.language)
222
223
 
223
224
  bldObj.setPartitionFormat(
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2018-09-29 [0.0.1]
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
10
10
 
11
11
  This program is free software: you can redistribute it and/or modify
12
12
  it under the terms of the GNU General Public License as published by
novelwriter/core/index.py CHANGED
@@ -10,7 +10,7 @@ Created: 2022-05-29 [2.0rc1] TagsIndex
10
10
  Created: 2022-05-29 [2.0rc1] ItemIndex
11
11
 
12
12
  This file is a part of novelWriter
13
- Copyright 2018–2024, Veronica Berglyd Olsen
13
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
14
14
 
15
15
  This program is free software: you can redistribute it and/or modify
16
16
  it under the terms of the GNU General Public License as published by
@@ -116,24 +116,24 @@ class NWIndex:
116
116
  # Public Methods
117
117
  ##
118
118
 
119
- def clearIndex(self) -> None:
119
+ def clear(self) -> None:
120
120
  """Clear the index dictionaries and time stamps."""
121
121
  self._tagsIndex.clear()
122
122
  self._itemIndex.clear()
123
123
  self._indexChange = 0.0
124
124
  self._rootChange = {}
125
- SHARED.indexSignalProxy({"event": "clearIndex"})
125
+ SHARED.emitIndexCleared(self._project)
126
126
  return
127
127
 
128
- def rebuildIndex(self) -> None:
128
+ def rebuild(self) -> None:
129
129
  """Rebuild the entire index from scratch."""
130
- self.clearIndex()
130
+ self.clear()
131
131
  for nwItem in self._project.tree:
132
132
  if nwItem.isFileType():
133
133
  text = self._project.storage.getDocumentText(nwItem.itemHandle)
134
134
  self.scanText(nwItem.itemHandle, text, blockSignal=True)
135
135
  self._indexBroken = False
136
- SHARED.indexSignalProxy({"event": "buildIndex"})
136
+ SHARED.emitIndexAvailable(self._project)
137
137
  return
138
138
 
139
139
  def deleteHandle(self, tHandle: str) -> None:
@@ -143,10 +143,7 @@ class NWIndex:
143
143
  for tTag in delTags:
144
144
  del self._tagsIndex[tTag]
145
145
  del self._itemIndex[tHandle]
146
- SHARED.indexSignalProxy({
147
- "event": "updateTags",
148
- "deleted": delTags,
149
- })
146
+ SHARED.emitIndexChangedTags(self._project, [], delTags)
150
147
  return
151
148
 
152
149
  def reIndexHandle(self, tHandle: str | None) -> None:
@@ -212,7 +209,7 @@ class NWIndex:
212
209
  self.reIndexHandle(fHandle)
213
210
 
214
211
  self._indexChange = time()
215
- SHARED.indexSignalProxy({"event": "buildIndex"})
212
+ SHARED.emitIndexAvailable(self._project)
216
213
 
217
214
  logger.debug("Index loaded in %.3f ms", (time() - tStart)*1000)
218
215
 
@@ -296,10 +293,7 @@ class NWIndex:
296
293
  self._indexChange = nowTime
297
294
  self._rootChange[tItem.itemRoot] = nowTime
298
295
  if not blockSignal:
299
- SHARED.indexSignalProxy({
300
- "event": "scanText",
301
- "handle": tHandle,
302
- })
296
+ tItem.notifyToRefresh()
303
297
 
304
298
  return True
305
299
 
@@ -370,11 +364,7 @@ class NWIndex:
370
364
  del self._tagsIndex[tTag]
371
365
  deleted.append(tTag)
372
366
  if updated or deleted:
373
- SHARED.indexSignalProxy({
374
- "event": "updateTags",
375
- "updated": updated,
376
- "deleted": deleted,
377
- })
367
+ SHARED.emitIndexChangedTags(self._project, updated, deleted)
378
368
 
379
369
  return
380
370
 
novelwriter/core/item.py CHANGED
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2018-10-27 [0.0.1] NWItem
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
10
10
 
11
11
  This program is free software: you can redistribute it and/or modify
12
12
  it under the terms of the GNU General Public License as published by
@@ -27,8 +27,9 @@ import logging
27
27
 
28
28
  from typing import TYPE_CHECKING, Any
29
29
 
30
- from PyQt5.QtGui import QIcon
30
+ from PyQt5.QtGui import QFont, QIcon
31
31
 
32
+ from novelwriter import CONFIG, SHARED
32
33
  from novelwriter.common import (
33
34
  checkInt, isHandle, isItemClass, isItemLayout, isItemType, simplified,
34
35
  yesNo
@@ -256,6 +257,8 @@ class NWItem:
256
257
  self._paraCount = 0
257
258
  self._cursorPos = 0
258
259
 
260
+ self._initCount = self._wordCount
261
+
259
262
  return True
260
263
 
261
264
  @classmethod
@@ -281,6 +284,15 @@ class NWItem:
281
284
  cls._initCount = source._initCount
282
285
  return cls
283
286
 
287
+ ##
288
+ # Action Methods
289
+ ##
290
+
291
+ def notifyToRefresh(self) -> None:
292
+ """Notify GUI that item info needs to be refreshed."""
293
+ self._project.tree.refreshItems([self._handle])
294
+ return
295
+
284
296
  ##
285
297
  # Lookup Methods
286
298
  ##
@@ -309,6 +321,19 @@ class NWItem:
309
321
 
310
322
  return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, ""))
311
323
 
324
+ def getMainIcon(self) -> QIcon:
325
+ """Get the main item icon."""
326
+ return SHARED.theme.getItemIcon(self._type, self._class, self._layout, self._heading)
327
+
328
+ def getMainFont(self) -> QFont:
329
+ """Get the main item icon."""
330
+ if CONFIG.emphLabels and self._layout == nwItemLayout.DOCUMENT:
331
+ if self._heading == "H1":
332
+ return SHARED.theme.guiFontBU
333
+ elif self._heading == "H2":
334
+ return SHARED.theme.guiFontB
335
+ return SHARED.theme.guiFont
336
+
312
337
  def getImportStatus(self) -> tuple[str, QIcon]:
313
338
  """Return the relevant importance or status label and icon for
314
339
  the current item based on its class.
@@ -319,6 +344,19 @@ class NWItem:
319
344
  entry = self._project.data.itemImport[self._import]
320
345
  return entry.name, entry.icon
321
346
 
347
+ def getActiveStatus(self) -> tuple[str, QIcon]:
348
+ """Return the relevant active status label and icon for
349
+ the current item based on its type.
350
+ """
351
+ if self.isFileType():
352
+ key = "checked" if self._active else "unchecked"
353
+ text = trConst(nwLabels.ACTIVE_NAME[key])
354
+ icon = SHARED.theme.getIcon(key)
355
+ else:
356
+ text = ""
357
+ icon = SHARED.theme.getIcon("noncheckable")
358
+ return text, icon
359
+
322
360
  ##
323
361
  # Checker Methods
324
362
  ##
@@ -553,8 +591,3 @@ class NWItem:
553
591
  else:
554
592
  self._cursorPos = 0
555
593
  return
556
-
557
- def saveInitialCount(self) -> None:
558
- """Save the initial word count."""
559
- self._initCount = self._wordCount
560
- return