novelWriter 2.5b1__py3-none-any.whl → 2.5.1__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.5b1.dist-info → novelWriter-2.5.1.dist-info}/METADATA +1 -1
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/RECORD +77 -75
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +3 -3
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_pl_PL.json +116 -0
- novelwriter/assets/i18n/project_pt_BR.json +74 -74
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/credits_en.htm +52 -44
- novelwriter/assets/themes/cyberpunk_night.conf +1 -0
- novelwriter/assets/themes/default_dark.conf +1 -0
- novelwriter/assets/themes/default_light.conf +1 -0
- novelwriter/assets/themes/dracula.conf +1 -0
- novelwriter/assets/themes/solarized_dark.conf +1 -0
- novelwriter/assets/themes/solarized_light.conf +1 -0
- novelwriter/common.py +12 -3
- novelwriter/config.py +67 -15
- novelwriter/constants.py +8 -10
- novelwriter/core/buildsettings.py +5 -3
- novelwriter/core/coretools.py +3 -1
- novelwriter/core/docbuild.py +1 -0
- novelwriter/core/project.py +15 -4
- novelwriter/core/status.py +4 -1
- novelwriter/core/storage.py +6 -1
- novelwriter/core/tohtml.py +69 -29
- novelwriter/core/tokenizer.py +83 -14
- novelwriter/core/toodt.py +48 -21
- novelwriter/core/toqdoc.py +37 -21
- novelwriter/dialogs/about.py +10 -15
- novelwriter/dialogs/docmerge.py +16 -16
- novelwriter/dialogs/docsplit.py +16 -16
- novelwriter/dialogs/editlabel.py +6 -8
- novelwriter/dialogs/preferences.py +106 -93
- novelwriter/dialogs/projectsettings.py +16 -20
- novelwriter/dialogs/quotes.py +9 -5
- novelwriter/dialogs/wordlist.py +6 -6
- novelwriter/enum.py +4 -5
- novelwriter/extensions/configlayout.py +38 -4
- novelwriter/extensions/modified.py +22 -3
- novelwriter/extensions/{circularprogress.py → progressbars.py} +26 -3
- novelwriter/extensions/statusled.py +39 -23
- novelwriter/gui/doceditor.py +22 -13
- novelwriter/gui/dochighlight.py +30 -39
- novelwriter/gui/docviewer.py +24 -15
- novelwriter/gui/docviewerpanel.py +7 -0
- novelwriter/gui/mainmenu.py +11 -11
- novelwriter/gui/outline.py +4 -3
- novelwriter/gui/projtree.py +85 -77
- novelwriter/gui/search.py +10 -1
- novelwriter/gui/statusbar.py +25 -29
- novelwriter/gui/theme.py +3 -0
- novelwriter/guimain.py +139 -124
- novelwriter/shared.py +19 -8
- novelwriter/text/patterns.py +113 -0
- novelwriter/tools/dictionaries.py +2 -8
- novelwriter/tools/lipsum.py +8 -12
- novelwriter/tools/manusbuild.py +9 -9
- novelwriter/tools/manuscript.py +10 -5
- novelwriter/tools/manussettings.py +7 -3
- novelwriter/tools/noveldetails.py +10 -10
- novelwriter/tools/welcome.py +19 -10
- novelwriter/tools/writingstats.py +3 -3
- novelwriter/types.py +5 -2
- novelwriter/extensions/simpleprogress.py +0 -53
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/top_level.txt +0 -0
novelwriter/gui/dochighlight.py
CHANGED
@@ -39,6 +39,7 @@ from novelwriter.common import checkInt
|
|
39
39
|
from novelwriter.constants import nwHeaders, nwRegEx, nwUnicode
|
40
40
|
from novelwriter.core.index import processComment
|
41
41
|
from novelwriter.enum import nwComment
|
42
|
+
from novelwriter.text.patterns import REGEX_PATTERNS
|
42
43
|
from novelwriter.types import QRegExUnicode
|
43
44
|
|
44
45
|
logger = logging.getLogger(__name__)
|
@@ -59,8 +60,8 @@ BLOCK_TITLE = 4
|
|
59
60
|
class GuiDocHighlighter(QSyntaxHighlighter):
|
60
61
|
|
61
62
|
__slots__ = (
|
62
|
-
"_tHandle", "
|
63
|
-
"_txtRules", "_cmnRules",
|
63
|
+
"_tHandle", "_isNovel", "_isInactive", "_spellCheck", "_spellErr",
|
64
|
+
"_hStyles", "_minRules", "_txtRules", "_cmnRules",
|
64
65
|
)
|
65
66
|
|
66
67
|
def __init__(self, document: QTextDocument) -> None:
|
@@ -69,11 +70,13 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
69
70
|
logger.debug("Create: GuiDocHighlighter")
|
70
71
|
|
71
72
|
self._tHandle = None
|
73
|
+
self._isNovel = False
|
72
74
|
self._isInactive = False
|
73
75
|
self._spellCheck = False
|
74
76
|
self._spellErr = QTextCharFormat()
|
75
77
|
|
76
78
|
self._hStyles: dict[str, QTextCharFormat] = {}
|
79
|
+
self._minRules: list[tuple[QRegularExpression, dict[int, QTextCharFormat]]] = []
|
77
80
|
self._txtRules: list[tuple[QRegularExpression, dict[int, QTextCharFormat]]] = []
|
78
81
|
self._cmnRules: list[tuple[QRegularExpression, dict[int, QTextCharFormat]]] = []
|
79
82
|
|
@@ -137,6 +140,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
137
140
|
hlRule = {
|
138
141
|
0: self._hStyles["mspaces"],
|
139
142
|
}
|
143
|
+
self._minRules.append((rxRule, hlRule))
|
140
144
|
self._txtRules.append((rxRule, hlRule))
|
141
145
|
self._cmnRules.append((rxRule, hlRule))
|
142
146
|
|
@@ -146,106 +150,89 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
146
150
|
hlRule = {
|
147
151
|
0: self._hStyles["nobreak"],
|
148
152
|
}
|
153
|
+
self._minRules.append((rxRule, hlRule))
|
149
154
|
self._txtRules.append((rxRule, hlRule))
|
150
155
|
self._cmnRules.append((rxRule, hlRule))
|
151
156
|
|
152
157
|
# Dialogue
|
153
158
|
if CONFIG.dialogStyle > 0:
|
154
|
-
|
155
|
-
symC = ""
|
156
|
-
if CONFIG.dialogStyle in (1, 3):
|
157
|
-
symO += CONFIG.fmtSQuoteOpen
|
158
|
-
symC += CONFIG.fmtSQuoteClose
|
159
|
-
if CONFIG.dialogStyle in (2, 3):
|
160
|
-
symO += CONFIG.fmtDQuoteOpen
|
161
|
-
symC += CONFIG.fmtDQuoteClose
|
162
|
-
|
163
|
-
rxEnd = "|$" if CONFIG.allowOpenDial else ""
|
164
|
-
rxRule = QRegularExpression(f"\\B[{symO}].*?[{symC}]\\B{rxEnd}")
|
165
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
159
|
+
rxRule = REGEX_PATTERNS.dialogStyle
|
166
160
|
hlRule = {
|
167
161
|
0: self._hStyles["dialog"],
|
168
162
|
}
|
169
163
|
self._txtRules.append((rxRule, hlRule))
|
170
164
|
|
171
165
|
if CONFIG.dialogLine:
|
172
|
-
|
173
|
-
rxRule = QRegularExpression(f"^{sym}.*?$")
|
174
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
166
|
+
rxRule = REGEX_PATTERNS.dialogLine
|
175
167
|
hlRule = {
|
176
168
|
0: self._hStyles["dialog"],
|
177
169
|
}
|
178
170
|
self._txtRules.append((rxRule, hlRule))
|
179
171
|
|
180
172
|
if CONFIG.narratorBreak:
|
181
|
-
|
182
|
-
rxRule = QRegularExpression(f"({sym}\\b)(.*?)(\\b{sym})")
|
183
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
173
|
+
rxRule = REGEX_PATTERNS.narratorBreak
|
184
174
|
hlRule = {
|
185
175
|
0: self._hStyles["text"],
|
186
176
|
}
|
187
177
|
self._txtRules.append((rxRule, hlRule))
|
188
178
|
|
189
179
|
if CONFIG.altDialogOpen and CONFIG.altDialogClose:
|
190
|
-
|
191
|
-
symC = QRegularExpression.escape(CONFIG.altDialogClose)
|
192
|
-
rxRule = QRegularExpression(f"\\B{symO}.*?{symC}\\B")
|
193
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
180
|
+
rxRule = REGEX_PATTERNS.altDialogStyle
|
194
181
|
hlRule = {
|
195
182
|
0: self._hStyles["altdialog"],
|
196
183
|
}
|
197
184
|
self._txtRules.append((rxRule, hlRule))
|
198
185
|
|
199
186
|
# Markdown Italic
|
200
|
-
rxRule =
|
201
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
187
|
+
rxRule = REGEX_PATTERNS.markdownItalic
|
202
188
|
hlRule = {
|
203
189
|
1: self._hStyles["markup"],
|
204
190
|
2: self._hStyles["italic"],
|
205
191
|
3: self._hStyles["markup"],
|
206
192
|
}
|
193
|
+
self._minRules.append((rxRule, hlRule))
|
207
194
|
self._txtRules.append((rxRule, hlRule))
|
208
195
|
self._cmnRules.append((rxRule, hlRule))
|
209
196
|
|
210
197
|
# Markdown Bold
|
211
|
-
rxRule =
|
212
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
198
|
+
rxRule = REGEX_PATTERNS.markdownBold
|
213
199
|
hlRule = {
|
214
200
|
1: self._hStyles["markup"],
|
215
201
|
2: self._hStyles["bold"],
|
216
202
|
3: self._hStyles["markup"],
|
217
203
|
}
|
204
|
+
self._minRules.append((rxRule, hlRule))
|
218
205
|
self._txtRules.append((rxRule, hlRule))
|
219
206
|
self._cmnRules.append((rxRule, hlRule))
|
220
207
|
|
221
208
|
# Markdown Strikethrough
|
222
|
-
rxRule =
|
223
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
209
|
+
rxRule = REGEX_PATTERNS.markdownStrike
|
224
210
|
hlRule = {
|
225
211
|
1: self._hStyles["markup"],
|
226
212
|
2: self._hStyles["strike"],
|
227
213
|
3: self._hStyles["markup"],
|
228
214
|
}
|
215
|
+
self._minRules.append((rxRule, hlRule))
|
229
216
|
self._txtRules.append((rxRule, hlRule))
|
230
217
|
self._cmnRules.append((rxRule, hlRule))
|
231
218
|
|
232
219
|
# Shortcodes
|
233
|
-
rxRule =
|
234
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
220
|
+
rxRule = REGEX_PATTERNS.shortcodePlain
|
235
221
|
hlRule = {
|
236
222
|
1: self._hStyles["code"],
|
237
223
|
}
|
224
|
+
self._minRules.append((rxRule, hlRule))
|
238
225
|
self._txtRules.append((rxRule, hlRule))
|
239
226
|
self._cmnRules.append((rxRule, hlRule))
|
240
227
|
|
241
228
|
# Shortcodes w/Value
|
242
|
-
rxRule =
|
243
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
229
|
+
rxRule = REGEX_PATTERNS.shortcodeValue
|
244
230
|
hlRule = {
|
245
231
|
1: self._hStyles["code"],
|
246
232
|
2: self._hStyles["value"],
|
247
233
|
3: self._hStyles["code"],
|
248
234
|
}
|
235
|
+
self._minRules.append((rxRule, hlRule))
|
249
236
|
self._txtRules.append((rxRule, hlRule))
|
250
237
|
self._cmnRules.append((rxRule, hlRule))
|
251
238
|
|
@@ -255,6 +242,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
255
242
|
hlRule = {
|
256
243
|
1: self._hStyles["markup"],
|
257
244
|
}
|
245
|
+
self._minRules.append((rxRule, hlRule))
|
258
246
|
self._txtRules.append((rxRule, hlRule))
|
259
247
|
|
260
248
|
# Auto-Replace Tags
|
@@ -263,6 +251,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
263
251
|
hlRule = {
|
264
252
|
0: self._hStyles["replace"],
|
265
253
|
}
|
254
|
+
self._minRules.append((rxRule, hlRule))
|
266
255
|
self._txtRules.append((rxRule, hlRule))
|
267
256
|
self._cmnRules.append((rxRule, hlRule))
|
268
257
|
|
@@ -280,9 +269,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
280
269
|
def setHandle(self, tHandle: str) -> None:
|
281
270
|
"""Set the handle of the currently highlighted document."""
|
282
271
|
self._tHandle = tHandle
|
283
|
-
self.
|
284
|
-
|
285
|
-
|
272
|
+
self._isNovel = False
|
273
|
+
self._isInactive = False
|
274
|
+
if item := SHARED.project.tree[tHandle]:
|
275
|
+
self._isNovel = item.isDocumentLayout()
|
276
|
+
self._isInactive = item.isInactiveClass()
|
286
277
|
logger.debug("Syntax highlighter enabled for item '%s'", tHandle)
|
287
278
|
return
|
288
279
|
|
@@ -397,7 +388,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
397
388
|
|
398
389
|
elif text.startswith("["): # Special Command
|
399
390
|
self.setCurrentBlockState(BLOCK_TEXT)
|
400
|
-
hRules = self._txtRules
|
391
|
+
hRules = self._txtRules if self._isNovel else self._minRules
|
401
392
|
|
402
393
|
sText = text.rstrip().lower()
|
403
394
|
if sText in ("[newpage]", "[new page]", "[vspace]"):
|
@@ -414,7 +405,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
414
405
|
|
415
406
|
else: # Text Paragraph
|
416
407
|
self.setCurrentBlockState(BLOCK_TEXT)
|
417
|
-
hRules = self._txtRules
|
408
|
+
hRules = self._txtRules if self._isNovel else self._minRules
|
418
409
|
|
419
410
|
if hRules:
|
420
411
|
for rX, hRule in hRules:
|
novelwriter/gui/docviewer.py
CHANGED
@@ -33,7 +33,7 @@ from enum import Enum
|
|
33
33
|
from PyQt5.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot
|
34
34
|
from PyQt5.QtGui import QCursor, QMouseEvent, QPalette, QResizeEvent, QTextCursor
|
35
35
|
from PyQt5.QtWidgets import (
|
36
|
-
QAction, QApplication, QFrame, QHBoxLayout,
|
36
|
+
QAction, QApplication, QFrame, QHBoxLayout, QMenu, QTextBrowser,
|
37
37
|
QToolButton, QWidget
|
38
38
|
)
|
39
39
|
|
@@ -42,6 +42,7 @@ from novelwriter.constants import nwHeaders, nwUnicode
|
|
42
42
|
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
|
43
43
|
from novelwriter.enum import nwDocAction, nwDocMode, nwItemType
|
44
44
|
from novelwriter.error import logException
|
45
|
+
from novelwriter.extensions.configlayout import NColourLabel
|
45
46
|
from novelwriter.extensions.eventfilters import WheelEventFilter
|
46
47
|
from novelwriter.extensions.modified import NIconToolButton
|
47
48
|
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
|
@@ -92,6 +93,9 @@ class GuiDocViewer(QTextBrowser):
|
|
92
93
|
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
93
94
|
self.customContextMenuRequested.connect(self._openContextMenu)
|
94
95
|
|
96
|
+
# Function Mapping
|
97
|
+
self.changeFocusState = self.docHeader.changeFocusState
|
98
|
+
|
95
99
|
self.initViewer()
|
96
100
|
|
97
101
|
logger.debug("Ready: GuiDocViewer")
|
@@ -165,6 +169,8 @@ class GuiDocViewer(QTextBrowser):
|
|
165
169
|
self._docTheme.keyword = SHARED.theme.colKey
|
166
170
|
self._docTheme.tag = SHARED.theme.colTag
|
167
171
|
self._docTheme.optional = SHARED.theme.colOpt
|
172
|
+
self._docTheme.dialog = SHARED.theme.colDialN
|
173
|
+
self._docTheme.altdialog = SHARED.theme.colDialA
|
168
174
|
|
169
175
|
# Set default text margins
|
170
176
|
self.document().setDocumentMargin(0)
|
@@ -201,6 +207,7 @@ class GuiDocViewer(QTextBrowser):
|
|
201
207
|
sPos = self.verticalScrollBar().value()
|
202
208
|
qDoc = ToQTextDocument(SHARED.project)
|
203
209
|
qDoc.setJustify(CONFIG.doJustify)
|
210
|
+
qDoc.setDialogueHighlight(True)
|
204
211
|
qDoc.initDocument(CONFIG.textFont, self._docTheme)
|
205
212
|
qDoc.setKeywords(True)
|
206
213
|
qDoc.setComments(CONFIG.viewComments)
|
@@ -245,9 +252,6 @@ class GuiDocViewer(QTextBrowser):
|
|
245
252
|
})
|
246
253
|
self.updateDocMargins()
|
247
254
|
|
248
|
-
# Since we change the content while it may still be rendering, we mark
|
249
|
-
# the document dirty again to make sure it's re-rendered properly.
|
250
|
-
self.redrawText()
|
251
255
|
QApplication.restoreOverrideCursor()
|
252
256
|
self.documentLoaded.emit(tHandle)
|
253
257
|
|
@@ -259,12 +263,6 @@ class GuiDocViewer(QTextBrowser):
|
|
259
263
|
self.loadText(self._docHandle, updateHistory=False)
|
260
264
|
return
|
261
265
|
|
262
|
-
def redrawText(self) -> None:
|
263
|
-
"""Redraw the text by marking the content as "dirty"."""
|
264
|
-
self.document().markContentsDirty(0, self.document().characterCount())
|
265
|
-
self.updateDocMargins()
|
266
|
-
return
|
267
|
-
|
268
266
|
def docAction(self, action: nwDocAction) -> bool:
|
269
267
|
"""Process document actions on the current document."""
|
270
268
|
logger.debug("Requesting action: '%s'", action.name)
|
@@ -284,6 +282,10 @@ class GuiDocViewer(QTextBrowser):
|
|
284
282
|
return False
|
285
283
|
return True
|
286
284
|
|
285
|
+
def anyFocus(self) -> bool:
|
286
|
+
"""Check if any widget or child widget has focus."""
|
287
|
+
return self.hasFocus() or self.isAncestorOf(QApplication.focusWidget())
|
288
|
+
|
287
289
|
def clearNavHistory(self) -> None:
|
288
290
|
"""Clear the navigation history."""
|
289
291
|
self.docHistory.clear()
|
@@ -370,8 +372,10 @@ class GuiDocViewer(QTextBrowser):
|
|
370
372
|
"""Process a clicked link in the document."""
|
371
373
|
if link := url.url():
|
372
374
|
logger.debug("Clicked link: '%s'", link)
|
373
|
-
if (bits := link.partition("_")) and bits[2]:
|
375
|
+
if (bits := link.partition("_")) and bits[0] == "#tag" and bits[2]:
|
374
376
|
self.loadDocumentTagRequest.emit(bits[2], nwDocMode.VIEW)
|
377
|
+
else:
|
378
|
+
self.navigateTo(link)
|
375
379
|
return
|
376
380
|
|
377
381
|
@pyqtSlot("QPoint")
|
@@ -601,9 +605,7 @@ class GuiDocViewHeader(QWidget):
|
|
601
605
|
self.setAutoFillBackground(True)
|
602
606
|
|
603
607
|
# Title Label
|
604
|
-
self.itemTitle =
|
605
|
-
self.itemTitle.setText("")
|
606
|
-
self.itemTitle.setIndent(0)
|
608
|
+
self.itemTitle = NColourLabel("", self, faded=SHARED.theme.fadedText)
|
607
609
|
self.itemTitle.setMargin(0)
|
608
610
|
self.itemTitle.setContentsMargins(0, 0, 0, 0)
|
609
611
|
self.itemTitle.setAutoFillBackground(True)
|
@@ -739,7 +741,14 @@ class GuiDocViewHeader(QWidget):
|
|
739
741
|
palette.setColor(QPalette.ColorRole.WindowText, SHARED.theme.colText)
|
740
742
|
palette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
|
741
743
|
self.setPalette(palette)
|
742
|
-
self.itemTitle.
|
744
|
+
self.itemTitle.setTextColors(
|
745
|
+
color=palette.windowText().color(), faded=SHARED.theme.fadedText
|
746
|
+
)
|
747
|
+
return
|
748
|
+
|
749
|
+
def changeFocusState(self, state: bool) -> None:
|
750
|
+
"""Toggle focus state."""
|
751
|
+
self.itemTitle.setColorState(state)
|
743
752
|
return
|
744
753
|
|
745
754
|
def setHandle(self, tHandle: str) -> None:
|
@@ -189,6 +189,13 @@ class GuiDocViewerPanel(QWidget):
|
|
189
189
|
self._updateTabVisibility()
|
190
190
|
return
|
191
191
|
|
192
|
+
@pyqtSlot(str)
|
193
|
+
def updateStatusLabels(self, kind: str) -> None:
|
194
|
+
"""Update the importance labels."""
|
195
|
+
if kind == "i":
|
196
|
+
self._loadAllTags()
|
197
|
+
return
|
198
|
+
|
192
199
|
##
|
193
200
|
# Private Slots
|
194
201
|
##
|
novelwriter/gui/mainmenu.py
CHANGED
@@ -35,7 +35,7 @@ from PyQt5.QtWidgets import QAction, QMenuBar
|
|
35
35
|
from novelwriter import CONFIG, SHARED
|
36
36
|
from novelwriter.common import openExternalPath
|
37
37
|
from novelwriter.constants import nwConst, nwKeyWords, nwLabels, nwUnicode, trConst
|
38
|
-
from novelwriter.enum import nwDocAction, nwDocInsert,
|
38
|
+
from novelwriter.enum import nwDocAction, nwDocInsert, nwFocus, nwView
|
39
39
|
from novelwriter.extensions.eventfilters import StatusTipFilter
|
40
40
|
|
41
41
|
if TYPE_CHECKING: # pragma: no cover
|
@@ -54,7 +54,7 @@ class GuiMainMenu(QMenuBar):
|
|
54
54
|
requestDocInsert = pyqtSignal(nwDocInsert)
|
55
55
|
requestDocInsertText = pyqtSignal(str)
|
56
56
|
requestDocKeyWordInsert = pyqtSignal(str)
|
57
|
-
requestFocusChange = pyqtSignal(
|
57
|
+
requestFocusChange = pyqtSignal(nwFocus)
|
58
58
|
requestViewChange = pyqtSignal(nwView)
|
59
59
|
|
60
60
|
def __init__(self, mainGui: GuiMain) -> None:
|
@@ -167,7 +167,7 @@ class GuiMainMenu(QMenuBar):
|
|
167
167
|
# Project > Edit
|
168
168
|
self.aEditItem = self.projMenu.addAction(self.tr("Rename Item"))
|
169
169
|
self.aEditItem.setShortcut("F2")
|
170
|
-
self.aEditItem.triggered.connect(lambda: self.mainGui.
|
170
|
+
self.aEditItem.triggered.connect(lambda: self.mainGui.projView.renameTreeItem(None))
|
171
171
|
|
172
172
|
# Project > Delete
|
173
173
|
self.aDeleteItem = self.projMenu.addAction(self.tr("Delete Item"))
|
@@ -303,24 +303,24 @@ class GuiMainMenu(QMenuBar):
|
|
303
303
|
self.viewMenu = self.addMenu(self.tr("&View"))
|
304
304
|
|
305
305
|
# View > TreeView
|
306
|
-
self.aFocusTree = self.viewMenu.addAction(self.tr("Go to
|
306
|
+
self.aFocusTree = self.viewMenu.addAction(self.tr("Go to Tree View"))
|
307
307
|
self.aFocusTree.setShortcut("Ctrl+T")
|
308
308
|
self.aFocusTree.triggered.connect(
|
309
|
-
lambda: self.requestFocusChange.emit(
|
309
|
+
lambda: self.requestFocusChange.emit(nwFocus.TREE)
|
310
310
|
)
|
311
311
|
|
312
312
|
# View > Document Editor
|
313
|
-
self.
|
314
|
-
self.
|
315
|
-
self.
|
316
|
-
lambda: self.requestFocusChange.emit(
|
313
|
+
self.aFocusDocument = self.viewMenu.addAction(self.tr("Go to Document"))
|
314
|
+
self.aFocusDocument.setShortcut("Ctrl+E")
|
315
|
+
self.aFocusDocument.triggered.connect(
|
316
|
+
lambda: self.requestFocusChange.emit(nwFocus.DOCUMENT)
|
317
317
|
)
|
318
318
|
|
319
319
|
# View > Outline
|
320
320
|
self.aFocusOutline = self.viewMenu.addAction(self.tr("Go to Outline"))
|
321
321
|
self.aFocusOutline.setShortcut("Ctrl+Shift+T")
|
322
322
|
self.aFocusOutline.triggered.connect(
|
323
|
-
lambda: self.requestFocusChange.emit(
|
323
|
+
lambda: self.requestFocusChange.emit(nwFocus.OUTLINE)
|
324
324
|
)
|
325
325
|
|
326
326
|
# View > Separator
|
@@ -422,7 +422,7 @@ class GuiMainMenu(QMenuBar):
|
|
422
422
|
self.aInsMSApos = self.mInsQuotes.addAction(self.tr("Alternative Apostrophe"))
|
423
423
|
self.aInsMSApos.setShortcut("Ctrl+K, '")
|
424
424
|
self.aInsMSApos.triggered.connect(
|
425
|
-
lambda: self.requestDocInsertText.emit(nwUnicode.
|
425
|
+
lambda: self.requestDocInsertText.emit(nwUnicode.U_MAPOS)
|
426
426
|
)
|
427
427
|
|
428
428
|
# Insert > Symbols
|
novelwriter/gui/outline.py
CHANGED
@@ -215,7 +215,7 @@ class GuiOutlineToolBar(QToolBar):
|
|
215
215
|
|
216
216
|
# Novel Selector
|
217
217
|
self.novelLabel = NColourLabel(
|
218
|
-
self.tr("Outline of"),
|
218
|
+
self.tr("Outline of"), self, scale=NColourLabel.HEADER_SCALE, bold=True
|
219
219
|
)
|
220
220
|
self.novelLabel.setContentsMargins(0, 0, CONFIG.pxInt(12), 0)
|
221
221
|
|
@@ -268,6 +268,7 @@ class GuiOutlineToolBar(QToolBar):
|
|
268
268
|
self.aExport.setIcon(SHARED.theme.getIcon("export"))
|
269
269
|
self.tbColumns.setIcon(SHARED.theme.getIcon("menu"))
|
270
270
|
self.tbColumns.setStyleSheet("QToolButton::menu-indicator {image: none;}")
|
271
|
+
self.novelLabel.setTextColors(color=self.palette().windowText().color())
|
271
272
|
return
|
272
273
|
|
273
274
|
def populateNovelList(self) -> None:
|
@@ -523,12 +524,12 @@ class GuiOutlineTree(QTreeWidget):
|
|
523
524
|
@pyqtSlot()
|
524
525
|
def exportOutline(self) -> None:
|
525
526
|
"""Export the outline as a CSV file."""
|
526
|
-
path = CONFIG.lastPath() / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
|
527
|
+
path = CONFIG.lastPath("outline") / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
|
527
528
|
path, _ = QFileDialog.getSaveFileName(
|
528
529
|
self, self.tr("Save Outline As"), str(path), formatFileFilter(["*.csv", "*"])
|
529
530
|
)
|
530
531
|
if path:
|
531
|
-
CONFIG.setLastPath(path)
|
532
|
+
CONFIG.setLastPath("outline", path)
|
532
533
|
logger.info("Writing CSV file: %s", path)
|
533
534
|
cols = [col for col in self._treeOrder if not self._colHidden[col]]
|
534
535
|
order = [self._colIdx[col] for col in cols]
|