novelWriter 2.4.3__py3-none-any.whl → 2.5b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelWriter-2.4.3.dist-info → novelWriter-2.5b1.dist-info}/METADATA +4 -5
- {novelWriter-2.4.3.dist-info → novelWriter-2.5b1.dist-info}/RECORD +109 -101
- novelwriter/__init__.py +33 -39
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
- novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +2 -0
- novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
- novelwriter/assets/syntax/default_dark.conf +32 -18
- novelwriter/assets/syntax/default_light.conf +24 -10
- novelwriter/assets/syntax/dracula.conf +44 -0
- novelwriter/assets/syntax/grey_dark.conf +5 -4
- novelwriter/assets/syntax/grey_light.conf +5 -4
- novelwriter/assets/syntax/light_owl.conf +7 -6
- novelwriter/assets/syntax/night_owl.conf +7 -6
- novelwriter/assets/syntax/snazzy.conf +42 -0
- novelwriter/assets/syntax/solarized_dark.conf +4 -3
- novelwriter/assets/syntax/solarized_light.conf +4 -3
- novelwriter/assets/syntax/tango.conf +27 -11
- novelwriter/assets/syntax/tomorrow.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night.conf +7 -6
- novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
- novelwriter/assets/text/credits_en.htm +4 -1
- novelwriter/assets/themes/cyberpunk_night.conf +2 -0
- novelwriter/assets/themes/default_dark.conf +1 -0
- novelwriter/assets/themes/default_light.conf +1 -0
- novelwriter/assets/themes/dracula.conf +47 -0
- novelwriter/assets/themes/solarized_dark.conf +1 -0
- novelwriter/assets/themes/solarized_light.conf +1 -0
- novelwriter/common.py +31 -9
- novelwriter/config.py +118 -84
- novelwriter/constants.py +40 -26
- novelwriter/core/buildsettings.py +63 -66
- novelwriter/core/coretools.py +2 -22
- novelwriter/core/docbuild.py +51 -40
- novelwriter/core/document.py +3 -5
- novelwriter/core/index.py +115 -45
- novelwriter/core/item.py +8 -19
- novelwriter/core/options.py +2 -4
- novelwriter/core/project.py +23 -57
- novelwriter/core/projectdata.py +1 -3
- novelwriter/core/projectxml.py +12 -15
- novelwriter/core/sessions.py +3 -5
- novelwriter/core/spellcheck.py +4 -9
- novelwriter/core/status.py +211 -164
- novelwriter/core/storage.py +0 -8
- novelwriter/core/tohtml.py +94 -100
- novelwriter/core/tokenizer.py +199 -112
- novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
- novelwriter/core/toodt.py +212 -148
- novelwriter/core/toqdoc.py +403 -0
- novelwriter/core/tree.py +5 -7
- novelwriter/dialogs/about.py +3 -5
- novelwriter/dialogs/docmerge.py +1 -3
- novelwriter/dialogs/docsplit.py +1 -3
- novelwriter/dialogs/editlabel.py +0 -2
- novelwriter/dialogs/preferences.py +111 -88
- novelwriter/dialogs/projectsettings.py +216 -180
- novelwriter/dialogs/quotes.py +3 -4
- novelwriter/dialogs/wordlist.py +3 -9
- novelwriter/enum.py +31 -25
- novelwriter/error.py +8 -15
- novelwriter/extensions/circularprogress.py +5 -6
- novelwriter/extensions/configlayout.py +18 -18
- novelwriter/extensions/eventfilters.py +1 -5
- novelwriter/extensions/modified.py +50 -13
- novelwriter/extensions/novelselector.py +1 -3
- novelwriter/extensions/pagedsidebar.py +9 -12
- novelwriter/extensions/simpleprogress.py +1 -3
- novelwriter/extensions/statusled.py +1 -3
- novelwriter/extensions/switch.py +4 -6
- novelwriter/extensions/switchbox.py +7 -6
- novelwriter/extensions/versioninfo.py +3 -9
- novelwriter/gui/doceditor.py +98 -126
- novelwriter/gui/dochighlight.py +237 -183
- novelwriter/gui/docviewer.py +46 -94
- novelwriter/gui/docviewerpanel.py +3 -10
- novelwriter/gui/editordocument.py +1 -3
- novelwriter/gui/itemdetails.py +7 -11
- novelwriter/gui/mainmenu.py +11 -7
- novelwriter/gui/noveltree.py +11 -24
- novelwriter/gui/outline.py +11 -23
- novelwriter/gui/projtree.py +26 -43
- novelwriter/gui/search.py +1 -3
- novelwriter/gui/sidebar.py +2 -6
- novelwriter/gui/statusbar.py +6 -10
- novelwriter/gui/theme.py +23 -48
- novelwriter/guimain.py +50 -71
- novelwriter/shared.py +30 -15
- novelwriter/tools/dictionaries.py +8 -12
- novelwriter/tools/lipsum.py +2 -4
- novelwriter/tools/manusbuild.py +1 -3
- novelwriter/tools/manuscript.py +66 -145
- novelwriter/tools/manussettings.py +67 -73
- novelwriter/tools/noveldetails.py +6 -11
- novelwriter/tools/welcome.py +2 -16
- novelwriter/tools/writingstats.py +6 -9
- novelwriter/types.py +45 -3
- {novelWriter-2.4.3.dist-info → novelWriter-2.5b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.4.3.dist-info → novelWriter-2.5b1.dist-info}/WHEEL +0 -0
- {novelWriter-2.4.3.dist-info → novelWriter-2.5b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.4.3.dist-info → novelWriter-2.5b1.dist-info}/top_level.txt +0 -0
novelwriter/gui/docviewer.py
CHANGED
@@ -31,24 +31,21 @@ import logging
|
|
31
31
|
from enum import Enum
|
32
32
|
|
33
33
|
from PyQt5.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot
|
34
|
-
from PyQt5.QtGui import QCursor, QMouseEvent, QPalette, QResizeEvent, QTextCursor
|
34
|
+
from PyQt5.QtGui import QCursor, QMouseEvent, QPalette, QResizeEvent, QTextCursor
|
35
35
|
from PyQt5.QtWidgets import (
|
36
36
|
QAction, QApplication, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser,
|
37
37
|
QToolButton, QWidget
|
38
38
|
)
|
39
39
|
|
40
40
|
from novelwriter import CONFIG, SHARED
|
41
|
-
from novelwriter.common import cssCol
|
42
41
|
from novelwriter.constants import nwHeaders, nwUnicode
|
43
|
-
from novelwriter.core.
|
42
|
+
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
|
44
43
|
from novelwriter.enum import nwDocAction, nwDocMode, nwItemType
|
45
44
|
from novelwriter.error import logException
|
46
45
|
from novelwriter.extensions.eventfilters import WheelEventFilter
|
47
46
|
from novelwriter.extensions.modified import NIconToolButton
|
48
47
|
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
|
49
|
-
from novelwriter.types import
|
50
|
-
QtAlignCenterTop, QtAlignJustify, QtKeepAnchor, QtMouseLeft, QtMoveAnchor
|
51
|
-
)
|
48
|
+
from novelwriter.types import QtAlignCenterTop, QtKeepAnchor, QtMouseLeft, QtMoveAnchor
|
52
49
|
|
53
50
|
logger = logging.getLogger(__name__)
|
54
51
|
|
@@ -69,6 +66,7 @@ class GuiDocViewer(QTextBrowser):
|
|
69
66
|
|
70
67
|
# Internal Variables
|
71
68
|
self._docHandle = None
|
69
|
+
self._docTheme = TextDocumentTheme()
|
72
70
|
|
73
71
|
# Settings
|
74
72
|
self.setMinimumWidth(CONFIG.pxInt(300))
|
@@ -137,8 +135,10 @@ class GuiDocViewer(QTextBrowser):
|
|
137
135
|
|
138
136
|
def initViewer(self) -> None:
|
139
137
|
"""Set editor settings from main config."""
|
140
|
-
|
141
|
-
self.
|
138
|
+
# Set the font. See issues #1862 and #1875.
|
139
|
+
self.setFont(CONFIG.textFont)
|
140
|
+
self.docHeader.updateFont()
|
141
|
+
self.docFooter.updateFont()
|
142
142
|
|
143
143
|
# Set the widget colours to match syntax theme
|
144
144
|
mainPalette = self.palette()
|
@@ -151,16 +151,23 @@ class GuiDocViewer(QTextBrowser):
|
|
151
151
|
docPalette.setColor(QPalette.ColorRole.Base, SHARED.theme.colBack)
|
152
152
|
docPalette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
|
153
153
|
self.viewport().setPalette(docPalette)
|
154
|
-
|
155
154
|
self.docHeader.matchColours()
|
156
155
|
self.docFooter.matchColours()
|
157
156
|
|
157
|
+
# Update theme colours
|
158
|
+
self._docTheme.text = SHARED.theme.colText
|
159
|
+
self._docTheme.highlight = SHARED.theme.colMark
|
160
|
+
self._docTheme.head = SHARED.theme.colHead
|
161
|
+
self._docTheme.comment = SHARED.theme.colHidden
|
162
|
+
self._docTheme.note = SHARED.theme.colNote
|
163
|
+
self._docTheme.code = SHARED.theme.colCode
|
164
|
+
self._docTheme.modifier = SHARED.theme.colMod
|
165
|
+
self._docTheme.keyword = SHARED.theme.colKey
|
166
|
+
self._docTheme.tag = SHARED.theme.colTag
|
167
|
+
self._docTheme.optional = SHARED.theme.colOpt
|
168
|
+
|
158
169
|
# Set default text margins
|
159
170
|
self.document().setDocumentMargin(0)
|
160
|
-
options = QTextOption()
|
161
|
-
if CONFIG.doJustify:
|
162
|
-
options.setAlignment(QtAlignJustify)
|
163
|
-
self.document().setDefaultTextOption(options)
|
164
171
|
|
165
172
|
# Scroll bars
|
166
173
|
if CONFIG.hideVScroll:
|
@@ -181,22 +188,6 @@ class GuiDocViewer(QTextBrowser):
|
|
181
188
|
|
182
189
|
return
|
183
190
|
|
184
|
-
def initFont(self) -> None:
|
185
|
-
"""Set the font of the main widget and sub-widgets. This needs
|
186
|
-
special attention since there appears to be a bug in Qt 5.15.3.
|
187
|
-
See issues #1862 and #1875.
|
188
|
-
"""
|
189
|
-
font = self.font()
|
190
|
-
font.setFamily(CONFIG.textFont)
|
191
|
-
font.setPointSize(CONFIG.textSize)
|
192
|
-
self.setFont(font)
|
193
|
-
|
194
|
-
# Reset sub-widget font to GUI font
|
195
|
-
self.docHeader.updateFont()
|
196
|
-
self.docFooter.updateFont()
|
197
|
-
|
198
|
-
return
|
199
|
-
|
200
191
|
def loadText(self, tHandle: str, updateHistory: bool = True) -> bool:
|
201
192
|
"""Load text into the viewer from an item handle."""
|
202
193
|
if not SHARED.project.tree.checkType(tHandle, nwItemType.FILE):
|
@@ -208,21 +199,22 @@ class GuiDocViewer(QTextBrowser):
|
|
208
199
|
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
209
200
|
|
210
201
|
sPos = self.verticalScrollBar().value()
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
202
|
+
qDoc = ToQTextDocument(SHARED.project)
|
203
|
+
qDoc.setJustify(CONFIG.doJustify)
|
204
|
+
qDoc.initDocument(CONFIG.textFont, self._docTheme)
|
205
|
+
qDoc.setKeywords(True)
|
206
|
+
qDoc.setComments(CONFIG.viewComments)
|
207
|
+
qDoc.setSynopsis(CONFIG.viewSynopsis)
|
217
208
|
|
218
209
|
# Be extra careful here to prevent crashes when first opening a
|
219
210
|
# project as a crash here leaves no way of recovering.
|
220
211
|
# See issue #298
|
221
212
|
try:
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
213
|
+
qDoc.setText(tHandle)
|
214
|
+
qDoc.doPreProcessing()
|
215
|
+
qDoc.tokenizeText()
|
216
|
+
qDoc.doConvert()
|
217
|
+
qDoc.appendFootnotes()
|
226
218
|
except Exception:
|
227
219
|
logger.error("Failed to generate preview for document with handle '%s'", tHandle)
|
228
220
|
logException()
|
@@ -238,11 +230,7 @@ class GuiDocViewer(QTextBrowser):
|
|
238
230
|
self.docHistory.append(tHandle)
|
239
231
|
|
240
232
|
self.setDocumentTitle(tHandle)
|
241
|
-
|
242
|
-
# Replace tabs before setting the HTML, and then put them back in
|
243
|
-
self.setHtml(aDoc.result.replace("\t", "!!tab!!"))
|
244
|
-
while self.find("!!tab!!"):
|
245
|
-
self.textCursor().insertText("\t")
|
233
|
+
self.setDocument(qDoc.document)
|
246
234
|
|
247
235
|
if self._docHandle == tHandle:
|
248
236
|
# This is a refresh, so we set the scrollbar back to where it was
|
@@ -380,12 +368,10 @@ class GuiDocViewer(QTextBrowser):
|
|
380
368
|
@pyqtSlot("QUrl")
|
381
369
|
def _linkClicked(self, url: QUrl) -> None:
|
382
370
|
"""Process a clicked link in the document."""
|
383
|
-
link
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
if len(bits) == 2:
|
388
|
-
self.loadDocumentTagRequest.emit(bits[1], nwDocMode.VIEW)
|
371
|
+
if link := url.url():
|
372
|
+
logger.debug("Clicked link: '%s'", link)
|
373
|
+
if (bits := link.partition("_")) and bits[2]:
|
374
|
+
self.loadDocumentTagRequest.emit(bits[2], nwDocMode.VIEW)
|
389
375
|
return
|
390
376
|
|
391
377
|
@pyqtSlot("QPoint")
|
@@ -475,34 +461,6 @@ class GuiDocViewer(QTextBrowser):
|
|
475
461
|
self._makeSelection(selType)
|
476
462
|
return
|
477
463
|
|
478
|
-
def _makeStyleSheet(self) -> None:
|
479
|
-
"""Generate an appropriate style sheet for the document viewer,
|
480
|
-
based on the current syntax highlighter theme.
|
481
|
-
"""
|
482
|
-
colText = cssCol(SHARED.theme.colText)
|
483
|
-
colHead = cssCol(SHARED.theme.colHead)
|
484
|
-
colVals = cssCol(SHARED.theme.colVal)
|
485
|
-
colMark = cssCol(SHARED.theme.colMark)
|
486
|
-
colKeys = cssCol(SHARED.theme.colKey)
|
487
|
-
colOpts = cssCol(SHARED.theme.colOpt)
|
488
|
-
colHide = cssCol(SHARED.theme.colHidden)
|
489
|
-
colMods = cssCol(SHARED.theme.colMod)
|
490
|
-
self.document().setDefaultStyleSheet(
|
491
|
-
f"body {{color: {colText};}}\n"
|
492
|
-
f"h1, h2, h3, h4 {{color: {colHead};}}\n"
|
493
|
-
f"a {{color: {colVals};}}\n"
|
494
|
-
f"mark {{background-color: {colMark};}}\n"
|
495
|
-
f".tags {{color: {colKeys};}}\n"
|
496
|
-
f".optional {{color: {colOpts};}}\n"
|
497
|
-
f".comment {{color: {colHide};}}\n"
|
498
|
-
f".synopsis {{color: {colMods};}}\n"
|
499
|
-
".title {text-align: center;}\n"
|
500
|
-
)
|
501
|
-
|
502
|
-
return
|
503
|
-
|
504
|
-
# END Class GuiDocViewer
|
505
|
-
|
506
464
|
|
507
465
|
class GuiDocViewHistory:
|
508
466
|
|
@@ -616,15 +574,13 @@ class GuiDocViewHistory:
|
|
616
574
|
)
|
617
575
|
return
|
618
576
|
|
619
|
-
# END Class GuiDocViewHistory
|
620
|
-
|
621
|
-
|
622
|
-
# =============================================================================================== #
|
623
|
-
# The Embedded Document Header
|
624
|
-
# Only used by DocViewer, and is at a fixed position in the QTextBrowser's viewport
|
625
|
-
# =============================================================================================== #
|
626
577
|
|
627
578
|
class GuiDocViewHeader(QWidget):
|
579
|
+
"""The Embedded Document Header
|
580
|
+
|
581
|
+
Only used by DocViewer, and is at a fixed position in the
|
582
|
+
QTextBrowser's viewport.
|
583
|
+
"""
|
628
584
|
|
629
585
|
def __init__(self, docViewer: GuiDocViewer) -> None:
|
630
586
|
super().__init__(parent=docViewer)
|
@@ -842,15 +798,13 @@ class GuiDocViewHeader(QWidget):
|
|
842
798
|
self.docViewer.requestProjectItemSelected.emit(self._docHandle, True)
|
843
799
|
return
|
844
800
|
|
845
|
-
# END Class GuiDocViewHeader
|
846
|
-
|
847
|
-
|
848
|
-
# =============================================================================================== #
|
849
|
-
# The Embedded Document Footer
|
850
|
-
# Only used by DocViewer, and is at a fixed position in the QTextBrowser's viewport
|
851
|
-
# =============================================================================================== #
|
852
801
|
|
853
802
|
class GuiDocViewFooter(QWidget):
|
803
|
+
"""The Embedded Document Footer
|
804
|
+
|
805
|
+
Only used by DocViewer, and is at a fixed position in the
|
806
|
+
QTextBrowser's viewport.
|
807
|
+
"""
|
854
808
|
|
855
809
|
def __init__(self, docViewer: GuiDocViewer) -> None:
|
856
810
|
super().__init__(parent=docViewer)
|
@@ -976,5 +930,3 @@ class GuiDocViewFooter(QWidget):
|
|
976
930
|
CONFIG.viewSynopsis = state
|
977
931
|
self.docViewer.reloadText()
|
978
932
|
return
|
979
|
-
|
980
|
-
# END Class GuiDocViewFooter
|
@@ -209,9 +209,8 @@ class GuiDocViewerPanel(QWidget):
|
|
209
209
|
|
210
210
|
def _updateTabVisibility(self) -> None:
|
211
211
|
"""Hide class tabs with no content."""
|
212
|
-
|
213
|
-
|
214
|
-
self.mainTabs.setTabVisible(self.idTabs[tClass], cTab.countEntries() > 0)
|
212
|
+
for tClass, cTab in self.kwTabs.items():
|
213
|
+
self.mainTabs.setTabVisible(self.idTabs[tClass], cTab.countEntries() > 0)
|
215
214
|
return
|
216
215
|
|
217
216
|
def _loadAllTags(self) -> None:
|
@@ -222,8 +221,6 @@ class GuiDocViewerPanel(QWidget):
|
|
222
221
|
self.kwTabs[tClass].addUpdateEntry(key, name, iItem, hItem)
|
223
222
|
return
|
224
223
|
|
225
|
-
# END Class GuiDocViewerPanel
|
226
|
-
|
227
224
|
|
228
225
|
class _ViewPanelBackRefs(QTreeWidget):
|
229
226
|
|
@@ -361,8 +358,6 @@ class _ViewPanelBackRefs(QTreeWidget):
|
|
361
358
|
|
362
359
|
return
|
363
360
|
|
364
|
-
# END Class _ViewPanelBackRefs
|
365
|
-
|
366
361
|
|
367
362
|
class _ViewPanelKeyWords(QTreeWidget):
|
368
363
|
|
@@ -450,7 +445,7 @@ class _ViewPanelKeyWords(QTreeWidget):
|
|
450
445
|
nwItem.itemType, nwItem.itemClass,
|
451
446
|
nwItem.itemLayout, nwItem.mainHeading
|
452
447
|
)
|
453
|
-
impLabel, impIcon = nwItem.getImportStatus(
|
448
|
+
impLabel, impIcon = nwItem.getImportStatus()
|
454
449
|
iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5
|
455
450
|
hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel)
|
456
451
|
|
@@ -529,5 +524,3 @@ class _ViewPanelKeyWords(QTreeWidget):
|
|
529
524
|
if index.column() not in (self.C_EDIT, self.C_VIEW):
|
530
525
|
self._parent.loadDocumentTagRequest.emit(tag, nwDocMode.VIEW)
|
531
526
|
return
|
532
|
-
|
533
|
-
# END Class _ViewPanelKeyWords
|
@@ -28,8 +28,8 @@ import logging
|
|
28
28
|
from collections.abc import Iterable
|
29
29
|
from time import time
|
30
30
|
|
31
|
-
from PyQt5.QtGui import QTextBlock, QTextCursor, QTextDocument
|
32
31
|
from PyQt5.QtCore import QObject, pyqtSlot
|
32
|
+
from PyQt5.QtGui import QTextBlock, QTextCursor, QTextDocument
|
33
33
|
from PyQt5.QtWidgets import QApplication, QPlainTextDocumentLayout
|
34
34
|
|
35
35
|
from novelwriter import SHARED
|
@@ -133,5 +133,3 @@ class GuiTextDocument(QTextDocument):
|
|
133
133
|
"""Set the spell check state of the syntax highlighter."""
|
134
134
|
self._syntax.setSpellCheck(state)
|
135
135
|
return
|
136
|
-
|
137
|
-
# END Class GuiTextDocument
|
novelwriter/gui/itemdetails.py
CHANGED
@@ -26,12 +26,14 @@ from __future__ import annotations
|
|
26
26
|
import logging
|
27
27
|
|
28
28
|
from PyQt5.QtCore import pyqtSlot
|
29
|
-
from PyQt5.QtWidgets import
|
29
|
+
from PyQt5.QtWidgets import QGridLayout, QLabel, QWidget
|
30
30
|
|
31
31
|
from novelwriter import CONFIG, SHARED
|
32
|
-
from novelwriter.
|
32
|
+
from novelwriter.common import elide
|
33
|
+
from novelwriter.constants import nwLabels, trConst
|
33
34
|
from novelwriter.types import (
|
34
|
-
QtAlignLeft, QtAlignLeftBase, QtAlignRight, QtAlignRightBase,
|
35
|
+
QtAlignLeft, QtAlignLeftBase, QtAlignRight, QtAlignRightBase,
|
36
|
+
QtAlignRightMiddle
|
35
37
|
)
|
36
38
|
|
37
39
|
logger = logging.getLogger(__name__)
|
@@ -236,10 +238,6 @@ class GuiItemDetails(QWidget):
|
|
236
238
|
# Label
|
237
239
|
# =====
|
238
240
|
|
239
|
-
label = nwItem.itemName
|
240
|
-
if len(label) > 100:
|
241
|
-
label = label[:96].rstrip()+" ..."
|
242
|
-
|
243
241
|
if nwItem.isFileType():
|
244
242
|
if nwItem.isActive:
|
245
243
|
self.labelIcon.setPixmap(SHARED.theme.getPixmap("checked", (iPx, iPx)))
|
@@ -248,12 +246,12 @@ class GuiItemDetails(QWidget):
|
|
248
246
|
else:
|
249
247
|
self.labelIcon.setPixmap(SHARED.theme.getPixmap("noncheckable", (iPx, iPx)))
|
250
248
|
|
251
|
-
self.labelData.setText(
|
249
|
+
self.labelData.setText(elide(nwItem.itemName, 100))
|
252
250
|
|
253
251
|
# Status
|
254
252
|
# ======
|
255
253
|
|
256
|
-
status, icon = nwItem.getImportStatus(
|
254
|
+
status, icon = nwItem.getImportStatus()
|
257
255
|
self.statusIcon.setPixmap(icon.pixmap(iPx, iPx))
|
258
256
|
self.statusData.setText(status)
|
259
257
|
|
@@ -297,5 +295,3 @@ class GuiItemDetails(QWidget):
|
|
297
295
|
self.wCountData.setText(f"{wC:n}")
|
298
296
|
self.pCountData.setText(f"{pC:n}")
|
299
297
|
return
|
300
|
-
|
301
|
-
# END Class GuiItemDetails
|
novelwriter/gui/mainmenu.py
CHANGED
@@ -25,16 +25,16 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
import logging
|
27
27
|
|
28
|
-
from typing import TYPE_CHECKING
|
29
28
|
from pathlib import Path
|
29
|
+
from typing import TYPE_CHECKING
|
30
30
|
|
31
|
-
from PyQt5.QtGui import QDesktopServices
|
32
31
|
from PyQt5.QtCore import QUrl, pyqtSignal, pyqtSlot
|
33
|
-
from PyQt5.
|
32
|
+
from PyQt5.QtGui import QDesktopServices
|
33
|
+
from PyQt5.QtWidgets import QAction, QMenuBar
|
34
34
|
|
35
35
|
from novelwriter import CONFIG, SHARED
|
36
36
|
from novelwriter.common import openExternalPath
|
37
|
-
from novelwriter.constants import nwConst,
|
37
|
+
from novelwriter.constants import nwConst, nwKeyWords, nwLabels, nwUnicode, trConst
|
38
38
|
from novelwriter.enum import nwDocAction, nwDocInsert, nwView, nwWidget
|
39
39
|
from novelwriter.extensions.eventfilters import StatusTipFilter
|
40
40
|
|
@@ -202,7 +202,7 @@ class GuiMainMenu(QMenuBar):
|
|
202
202
|
# Document > Save
|
203
203
|
self.aSaveDoc = self.docuMenu.addAction(self.tr("Save Document"))
|
204
204
|
self.aSaveDoc.setShortcut("Ctrl+S")
|
205
|
-
self.aSaveDoc.triggered.connect(self.mainGui.
|
205
|
+
self.aSaveDoc.triggered.connect(self.mainGui.forceSaveDocument)
|
206
206
|
|
207
207
|
# Document > Close
|
208
208
|
self.aCloseDoc = self.docuMenu.addAction(self.tr("Close Document"))
|
@@ -597,6 +597,12 @@ class GuiMainMenu(QMenuBar):
|
|
597
597
|
lambda: self.requestDocInsert.emit(nwDocInsert.LIPSUM)
|
598
598
|
)
|
599
599
|
|
600
|
+
# Insert > Footnote
|
601
|
+
self.aFootnote = self.insMenu.addAction(self.tr("Footnote"))
|
602
|
+
self.aFootnote.triggered.connect(
|
603
|
+
lambda: self.requestDocInsert.emit(nwDocInsert.FOOTNOTE)
|
604
|
+
)
|
605
|
+
|
600
606
|
return
|
601
607
|
|
602
608
|
def _buildFormatMenu(self) -> None:
|
@@ -985,5 +991,3 @@ class GuiMainMenu(QMenuBar):
|
|
985
991
|
self.aWebsite.triggered.connect(lambda: self._openWebsite(nwConst.URL_WEB))
|
986
992
|
|
987
993
|
return
|
988
|
-
|
989
|
-
# END Class GuiMainMenu
|
novelwriter/gui/noveltree.py
CHANGED
@@ -29,14 +29,13 @@ import logging
|
|
29
29
|
|
30
30
|
from enum import Enum
|
31
31
|
from time import time
|
32
|
-
from typing import TYPE_CHECKING
|
33
32
|
|
34
|
-
from PyQt5.QtCore import QModelIndex, QPoint, Qt,
|
33
|
+
from PyQt5.QtCore import QModelIndex, QPoint, Qt, pyqtSignal, pyqtSlot
|
35
34
|
from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent
|
36
35
|
from PyQt5.QtWidgets import (
|
37
36
|
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView,
|
38
|
-
QInputDialog, QMenu,
|
39
|
-
|
37
|
+
QInputDialog, QMenu, QToolTip, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
38
|
+
QWidget
|
40
39
|
)
|
41
40
|
|
42
41
|
from novelwriter import CONFIG, SHARED
|
@@ -47,10 +46,10 @@ from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
|
|
47
46
|
from novelwriter.extensions.modified import NIconToolButton
|
48
47
|
from novelwriter.extensions.novelselector import NovelSelector
|
49
48
|
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
|
50
|
-
from novelwriter.types import
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
from novelwriter.types import (
|
50
|
+
QtAlignRight, QtDecoration, QtMouseLeft, QtMouseMiddle, QtSizeExpanding,
|
51
|
+
QtUserRole
|
52
|
+
)
|
54
53
|
|
55
54
|
logger = logging.getLogger(__name__)
|
56
55
|
|
@@ -62,8 +61,6 @@ class NovelTreeColumn(Enum):
|
|
62
61
|
FOCUS = 2
|
63
62
|
PLOT = 3
|
64
63
|
|
65
|
-
# END Enum NovelTreeColumn
|
66
|
-
|
67
64
|
|
68
65
|
class GuiNovelView(QWidget):
|
69
66
|
|
@@ -71,10 +68,8 @@ class GuiNovelView(QWidget):
|
|
71
68
|
selectedItemChanged = pyqtSignal(str)
|
72
69
|
openDocumentRequest = pyqtSignal(str, Enum, str, bool)
|
73
70
|
|
74
|
-
def __init__(self,
|
75
|
-
super().__init__(parent=
|
76
|
-
|
77
|
-
self.mainGui = mainGui
|
71
|
+
def __init__(self, parent: QWidget) -> None:
|
72
|
+
super().__init__(parent=parent)
|
78
73
|
|
79
74
|
# Build GUI
|
80
75
|
self.novelTree = GuiNovelTree(self)
|
@@ -188,8 +183,6 @@ class GuiNovelView(QWidget):
|
|
188
183
|
self.novelTree.refreshHandle(tHandle)
|
189
184
|
return
|
190
185
|
|
191
|
-
# END Class GuiNovelView
|
192
|
-
|
193
186
|
|
194
187
|
class GuiNovelToolBar(QWidget):
|
195
188
|
|
@@ -199,7 +192,6 @@ class GuiNovelToolBar(QWidget):
|
|
199
192
|
logger.debug("Create: GuiNovelToolBar")
|
200
193
|
|
201
194
|
self.novelView = novelView
|
202
|
-
self.mainGui = novelView.mainGui
|
203
195
|
|
204
196
|
iSz = SHARED.theme.baseIconSize
|
205
197
|
mPx = CONFIG.pxInt(2)
|
@@ -215,7 +207,7 @@ class GuiNovelToolBar(QWidget):
|
|
215
207
|
self.novelValue.setFont(selFont)
|
216
208
|
self.novelValue.setListFormat(self.tr("Outline of {0}"))
|
217
209
|
self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
|
218
|
-
self.novelValue.setSizePolicy(
|
210
|
+
self.novelValue.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
|
219
211
|
self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot)
|
220
212
|
|
221
213
|
self.tbNovel = NIconToolButton(self, iSz)
|
@@ -353,8 +345,6 @@ class GuiNovelToolBar(QWidget):
|
|
353
345
|
self.aLastCol[colType] = aLast
|
354
346
|
return
|
355
347
|
|
356
|
-
# END Class GuiNovelToolBar
|
357
|
-
|
358
348
|
|
359
349
|
class GuiNovelTree(QTreeWidget):
|
360
350
|
|
@@ -375,7 +365,6 @@ class GuiNovelTree(QTreeWidget):
|
|
375
365
|
logger.debug("Create: GuiNovelTree")
|
376
366
|
|
377
367
|
self.novelView = novelView
|
378
|
-
self.mainGui = novelView.mainGui
|
379
368
|
|
380
369
|
# Internal Variables
|
381
370
|
self._treeMap = {}
|
@@ -490,7 +479,7 @@ class GuiNovelTree(QTreeWidget):
|
|
490
479
|
if rootHandle is None:
|
491
480
|
rootHandle = SHARED.project.tree.findRoot(nwItemClass.NOVEL)
|
492
481
|
|
493
|
-
treeChanged =
|
482
|
+
treeChanged = SHARED.mainGui.projView.changedSince(self._lastBuild)
|
494
483
|
indexChanged = SHARED.project.index.rootChangedSince(rootHandle, self._lastBuild)
|
495
484
|
if not (treeChanged or indexChanged or overRide):
|
496
485
|
logger.debug("No changes have been made to the novel index")
|
@@ -783,5 +772,3 @@ class GuiNovelTree(QTreeWidget):
|
|
783
772
|
if tags:
|
784
773
|
lines.append(f"<b>{trConst(nwLabels.KEY_NAME[key])}</b>: {tags}")
|
785
774
|
return lines
|
786
|
-
|
787
|
-
# END Class GuiNovelTree
|
novelwriter/gui/outline.py
CHANGED
@@ -30,30 +30,28 @@ from __future__ import annotations
|
|
30
30
|
import csv
|
31
31
|
import logging
|
32
32
|
|
33
|
-
from time import time
|
34
33
|
from enum import Enum
|
34
|
+
from time import time
|
35
35
|
|
36
|
-
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
36
|
+
from PyQt5.QtCore import QT_TRANSLATE_NOOP, Qt, pyqtSignal, pyqtSlot
|
37
37
|
from PyQt5.QtWidgets import (
|
38
38
|
QAbstractItemView, QAction, QFileDialog, QFrame, QGridLayout, QGroupBox,
|
39
|
-
QHBoxLayout, QLabel, QMenu, QScrollArea,
|
40
|
-
|
39
|
+
QHBoxLayout, QLabel, QMenu, QScrollArea, QSplitter, QToolBar, QToolButton,
|
40
|
+
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
41
41
|
)
|
42
42
|
|
43
43
|
from novelwriter import CONFIG, SHARED
|
44
|
-
from novelwriter.enum import (
|
45
|
-
nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
|
46
|
-
)
|
47
|
-
from novelwriter.error import logException
|
48
44
|
from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe
|
49
|
-
from novelwriter.constants import nwHeaders,
|
45
|
+
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
|
46
|
+
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
|
47
|
+
from novelwriter.error import logException
|
50
48
|
from novelwriter.extensions.configlayout import NColourLabel
|
51
49
|
from novelwriter.extensions.novelselector import NovelSelector
|
52
50
|
from novelwriter.types import (
|
53
|
-
QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration,
|
51
|
+
QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration,
|
52
|
+
QtSizeExpanding, QtUserRole
|
54
53
|
)
|
55
54
|
|
56
|
-
|
57
55
|
logger = logging.getLogger(__name__)
|
58
56
|
|
59
57
|
|
@@ -196,8 +194,6 @@ class GuiOutlineView(QWidget):
|
|
196
194
|
self.outlineTree.refreshTree(rootHandle=(tHandle or None), overRide=True)
|
197
195
|
return
|
198
196
|
|
199
|
-
# END Class GuiOutlineView
|
200
|
-
|
201
197
|
|
202
198
|
class GuiOutlineToolBar(QToolBar):
|
203
199
|
|
@@ -215,7 +211,7 @@ class GuiOutlineToolBar(QToolBar):
|
|
215
211
|
self.setContentsMargins(0, 0, 0, 0)
|
216
212
|
|
217
213
|
stretch = QWidget(self)
|
218
|
-
stretch.setSizePolicy(
|
214
|
+
stretch.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
|
219
215
|
|
220
216
|
# Novel Selector
|
221
217
|
self.novelLabel = NColourLabel(
|
@@ -311,8 +307,6 @@ class GuiOutlineToolBar(QToolBar):
|
|
311
307
|
self.outlineExportRequest.emit()
|
312
308
|
return
|
313
309
|
|
314
|
-
# END Class GuiOutlineToolBar
|
315
|
-
|
316
310
|
|
317
311
|
class GuiOutlineTree(QTreeWidget):
|
318
312
|
|
@@ -728,8 +722,6 @@ class GuiOutlineTree(QTreeWidget):
|
|
728
722
|
|
729
723
|
return
|
730
724
|
|
731
|
-
# END Class GuiOutlineTree
|
732
|
-
|
733
725
|
|
734
726
|
class GuiOutlineHeaderMenu(QMenu):
|
735
727
|
|
@@ -772,8 +764,6 @@ class GuiOutlineHeaderMenu(QMenu):
|
|
772
764
|
|
773
765
|
return
|
774
766
|
|
775
|
-
# END Class GuiOutlineHeaderMenu
|
776
|
-
|
777
767
|
|
778
768
|
class GuiOutlineDetails(QScrollArea):
|
779
769
|
|
@@ -1048,7 +1038,7 @@ class GuiOutlineDetails(QScrollArea):
|
|
1048
1038
|
self.titleLabel.setText(self.tr(self.LVL_MAP.get(novIdx.level, "H1")))
|
1049
1039
|
self.titleValue.setText(novIdx.title)
|
1050
1040
|
|
1051
|
-
itemStatus, _ = nwItem.getImportStatus(
|
1041
|
+
itemStatus, _ = nwItem.getImportStatus()
|
1052
1042
|
|
1053
1043
|
self.fileValue.setText(nwItem.itemName)
|
1054
1044
|
self.itemValue.setText(itemStatus)
|
@@ -1104,5 +1094,3 @@ class GuiOutlineDetails(QScrollArea):
|
|
1104
1094
|
return ", ".join(
|
1105
1095
|
[f"<a href='{tag}'>{tag}</a>" for tag in refs.get(key, [])]
|
1106
1096
|
)
|
1107
|
-
|
1108
|
-
# END Class GuiOutlineDetails
|