novelWriter 2.2b1__py3-none-any.whl → 2.2rc1__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.2b1.dist-info → novelWriter-2.2rc1.dist-info}/METADATA +3 -3
- {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/RECORD +60 -48
- novelwriter/__init__.py +3 -3
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/icons/novelwriter.ico +0 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +8 -1
- novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +8 -1
- novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
- novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/release_notes.htm +4 -4
- novelwriter/common.py +22 -1
- novelwriter/config.py +12 -27
- novelwriter/constants.py +20 -3
- novelwriter/core/buildsettings.py +1 -1
- novelwriter/core/coretools.py +6 -1
- novelwriter/core/index.py +100 -34
- novelwriter/core/options.py +3 -0
- novelwriter/core/project.py +2 -2
- novelwriter/core/projectdata.py +1 -1
- novelwriter/core/tohtml.py +9 -3
- novelwriter/core/tokenizer.py +27 -20
- novelwriter/core/tomd.py +4 -0
- novelwriter/core/toodt.py +11 -4
- novelwriter/dialogs/preferences.py +80 -82
- novelwriter/dialogs/updates.py +25 -14
- novelwriter/enum.py +14 -4
- novelwriter/gui/doceditor.py +282 -177
- novelwriter/gui/dochighlight.py +7 -9
- novelwriter/gui/docviewer.py +142 -319
- novelwriter/gui/docviewerpanel.py +457 -0
- novelwriter/gui/editordocument.py +1 -1
- novelwriter/gui/mainmenu.py +16 -7
- novelwriter/gui/outline.py +10 -6
- novelwriter/gui/projtree.py +461 -376
- novelwriter/gui/sidebar.py +3 -3
- novelwriter/gui/statusbar.py +1 -1
- novelwriter/gui/theme.py +21 -2
- novelwriter/guimain.py +86 -32
- novelwriter/shared.py +23 -1
- novelwriter/tools/dictionaries.py +268 -0
- novelwriter/tools/manusbuild.py +17 -6
- novelwriter/tools/manuscript.py +1 -1
- novelwriter/tools/writingstats.py +1 -1
- novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
- {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/WHEEL +0 -0
- {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/top_level.txt +0 -0
novelwriter/gui/doceditor.py
CHANGED
@@ -10,6 +10,8 @@ Created: 2020-04-25 [0.4.5] GuiDocEditHeader
|
|
10
10
|
Rewritten: 2020-06-15 [0.9] GuiDocEditSearch
|
11
11
|
Created: 2020-06-27 [0.10] GuiDocEditFooter
|
12
12
|
Rewritten: 2020-10-07 [1.0b3] BackgroundWordCounter
|
13
|
+
Created: 2023-11-06 [2.2b1] MetaCompleter
|
14
|
+
Created: 2023-11-07 [2.2b1] GuiDocToolBar
|
13
15
|
|
14
16
|
This file is a part of novelWriter
|
15
17
|
Copyright 2018–2023, Veronica Berglyd Olsen
|
@@ -46,8 +48,8 @@ from PyQt5.QtGui import (
|
|
46
48
|
)
|
47
49
|
from PyQt5.QtWidgets import (
|
48
50
|
QAction, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu,
|
49
|
-
QPlainTextEdit, QPushButton, QShortcut, QToolBar, QToolButton, QVBoxLayout,
|
50
|
-
qApp
|
51
|
+
QPlainTextEdit, QPushButton, QShortcut, QToolBar, QToolButton, QVBoxLayout,
|
52
|
+
QWidget, qApp
|
51
53
|
)
|
52
54
|
|
53
55
|
from novelwriter import CONFIG, SHARED
|
@@ -67,12 +69,22 @@ if TYPE_CHECKING: # pragma: no cover
|
|
67
69
|
logger = logging.getLogger(__name__)
|
68
70
|
|
69
71
|
|
72
|
+
class _SelectAction(Enum):
|
73
|
+
|
74
|
+
NO_DECISION = 0
|
75
|
+
KEEP_SELECTION = 1
|
76
|
+
KEEP_POSITION = 2
|
77
|
+
MOVE_AFTER = 3
|
78
|
+
|
79
|
+
# END Class _SelectAction
|
80
|
+
|
81
|
+
|
70
82
|
class GuiDocEditor(QPlainTextEdit):
|
71
83
|
"""Gui Widget: Main Document Editor"""
|
72
84
|
|
73
85
|
MOVE_KEYS = (
|
74
|
-
Qt.Key_Left, Qt.Key_Right, Qt.Key_Up, Qt.Key_Down,
|
75
|
-
Qt.Key_PageUp, Qt.Key_PageDown
|
86
|
+
Qt.Key.Key_Left, Qt.Key.Key_Right, Qt.Key.Key_Up, Qt.Key.Key_Down,
|
87
|
+
Qt.Key.Key_PageUp, Qt.Key.Key_PageDown
|
76
88
|
)
|
77
89
|
|
78
90
|
# Custom Signals
|
@@ -85,6 +97,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|
85
97
|
spellCheckStateChanged = pyqtSignal(bool)
|
86
98
|
closeDocumentRequest = pyqtSignal()
|
87
99
|
toggleFocusModeRequest = pyqtSignal()
|
100
|
+
requestProjectItemSelected = pyqtSignal(str, bool)
|
101
|
+
requestProjectItemRenamed = pyqtSignal(str, str)
|
88
102
|
|
89
103
|
def __init__(self, mainGui: GuiMain) -> None:
|
90
104
|
super().__init__(parent=mainGui)
|
@@ -145,29 +159,28 @@ class GuiDocEditor(QPlainTextEdit):
|
|
145
159
|
self.docToolBar.requestDocAction.connect(self.docAction)
|
146
160
|
|
147
161
|
# Context Menu
|
148
|
-
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
162
|
+
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
149
163
|
self.customContextMenuRequested.connect(self._openContextMenu)
|
150
164
|
|
151
165
|
# Editor Settings
|
152
166
|
self.setMinimumWidth(CONFIG.pxInt(300))
|
153
167
|
self.setAutoFillBackground(True)
|
154
|
-
self.setFrameStyle(QFrame.NoFrame)
|
155
|
-
self.setCenterOnScroll(True)
|
168
|
+
self.setFrameStyle(QFrame.Shape.NoFrame)
|
156
169
|
|
157
170
|
# Custom Shortcuts
|
158
171
|
self.keyContext = QShortcut(self)
|
159
172
|
self.keyContext.setKey("Ctrl+.")
|
160
|
-
self.keyContext.setContext(Qt.WidgetShortcut)
|
173
|
+
self.keyContext.setContext(Qt.ShortcutContext.WidgetShortcut)
|
161
174
|
self.keyContext.activated.connect(self._openContextFromCursor)
|
162
175
|
|
163
176
|
self.followTag1 = QShortcut(self)
|
164
|
-
self.followTag1.setKey(Qt.Key_Return | Qt.ControlModifier)
|
165
|
-
self.followTag1.setContext(Qt.WidgetShortcut)
|
177
|
+
self.followTag1.setKey(Qt.Key.Key_Return | Qt.KeyboardModifier.ControlModifier)
|
178
|
+
self.followTag1.setContext(Qt.ShortcutContext.WidgetShortcut)
|
166
179
|
self.followTag1.activated.connect(self._processTag)
|
167
180
|
|
168
181
|
self.followTag2 = QShortcut(self)
|
169
|
-
self.followTag2.setKey(Qt.Key_Enter | Qt.ControlModifier)
|
170
|
-
self.followTag2.setContext(Qt.WidgetShortcut)
|
182
|
+
self.followTag2.setKey(Qt.Key.Key_Enter | Qt.KeyboardModifier.ControlModifier)
|
183
|
+
self.followTag2.setContext(Qt.ShortcutContext.WidgetShortcut)
|
171
184
|
self.followTag2.activated.connect(self._processTag)
|
172
185
|
|
173
186
|
# Set Up Document Word Counter
|
@@ -263,14 +276,14 @@ class GuiDocEditor(QPlainTextEdit):
|
|
263
276
|
def updateSyntaxColours(self) -> None:
|
264
277
|
"""Update the syntax highlighting theme."""
|
265
278
|
mainPalette = self.palette()
|
266
|
-
mainPalette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
267
|
-
mainPalette.setColor(QPalette.Base, QColor(*SHARED.theme.colBack))
|
268
|
-
mainPalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
279
|
+
mainPalette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
280
|
+
mainPalette.setColor(QPalette.ColorRole.Base, QColor(*SHARED.theme.colBack))
|
281
|
+
mainPalette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
269
282
|
self.setPalette(mainPalette)
|
270
283
|
|
271
284
|
docPalette = self.viewport().palette()
|
272
|
-
docPalette.setColor(QPalette.Base, QColor(*SHARED.theme.colBack))
|
273
|
-
docPalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
285
|
+
docPalette.setColor(QPalette.ColorRole.Base, QColor(*SHARED.theme.colBack))
|
286
|
+
docPalette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
274
287
|
self.viewport().setPalette(docPalette)
|
275
288
|
|
276
289
|
self.docHeader.matchColours()
|
@@ -322,24 +335,25 @@ class GuiDocEditor(QPlainTextEdit):
|
|
322
335
|
options = QTextOption()
|
323
336
|
|
324
337
|
if CONFIG.doJustify:
|
325
|
-
options.setAlignment(Qt.AlignJustify)
|
338
|
+
options.setAlignment(Qt.AlignmentFlag.AlignJustify)
|
326
339
|
if CONFIG.showTabsNSpaces:
|
327
|
-
options.setFlags(options.flags() | QTextOption.ShowTabsAndSpaces)
|
340
|
+
options.setFlags(options.flags() | QTextOption.Flag.ShowTabsAndSpaces)
|
328
341
|
if CONFIG.showLineEndings:
|
329
|
-
options.setFlags(options.flags() | QTextOption.ShowLineAndParagraphSeparators)
|
342
|
+
options.setFlags(options.flags() | QTextOption.Flag.ShowLineAndParagraphSeparators)
|
330
343
|
|
331
344
|
self._qDocument.setDefaultTextOption(options)
|
332
345
|
|
333
|
-
#
|
346
|
+
# Scrolling
|
347
|
+
self.setCenterOnScroll(CONFIG.scrollPastEnd)
|
334
348
|
if CONFIG.hideVScroll:
|
335
|
-
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
349
|
+
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
336
350
|
else:
|
337
|
-
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
351
|
+
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
338
352
|
|
339
353
|
if CONFIG.hideHScroll:
|
340
|
-
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
354
|
+
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
341
355
|
else:
|
342
|
-
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
356
|
+
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
343
357
|
|
344
358
|
# Refresh the tab stops
|
345
359
|
self.setTabStopDistance(CONFIG.getTabWidth())
|
@@ -358,7 +372,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
358
372
|
|
359
373
|
return
|
360
374
|
|
361
|
-
def loadText(self, tHandle, tLine=None) -> bool:
|
375
|
+
def loadText(self, tHandle: str, tLine=None) -> bool:
|
362
376
|
"""Load text from a document into the editor. If we have an I/O
|
363
377
|
error, we must handle this and clear the editor so that we don't
|
364
378
|
risk overwriting the file if it exists. This can for instance
|
@@ -376,7 +390,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
376
390
|
self.clearEditor()
|
377
391
|
return False
|
378
392
|
|
379
|
-
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
393
|
+
qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
380
394
|
self._docHandle = tHandle
|
381
395
|
|
382
396
|
self._allowAutoReplace(False)
|
@@ -429,7 +443,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
429
443
|
"""Replace the text of the current document with the provided
|
430
444
|
text. This also clears undo history.
|
431
445
|
"""
|
432
|
-
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
446
|
+
qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
433
447
|
self.setPlainText(text)
|
434
448
|
self.updateDocMargins()
|
435
449
|
self.setDocumentChanged(True)
|
@@ -488,10 +502,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
488
502
|
else:
|
489
503
|
self.novelStructureChanged.emit()
|
490
504
|
|
491
|
-
# ToDo: This should be a signal
|
492
505
|
if oldHeader != newHeader:
|
493
|
-
self.mainGui.projView.setTreeItemValues(tHandle)
|
494
|
-
self.mainGui.itemDetails.updateViewBox(tHandle)
|
495
506
|
self.docFooter.updateInfo()
|
496
507
|
|
497
508
|
# Update the status bar
|
@@ -499,6 +510,33 @@ class GuiDocEditor(QPlainTextEdit):
|
|
499
510
|
|
500
511
|
return True
|
501
512
|
|
513
|
+
def cursorIsVisible(self) -> bool:
|
514
|
+
"""Check if the cursor is visible in the editor."""
|
515
|
+
return (
|
516
|
+
0 < self.cursorRect().top()
|
517
|
+
and self.cursorRect().bottom() < self.viewport().height()
|
518
|
+
)
|
519
|
+
|
520
|
+
def ensureCursorVisibleNoCentre(self) -> None:
|
521
|
+
"""Ensure cursor is visible, but don't force it to centre."""
|
522
|
+
cT = self.cursorRect().top()
|
523
|
+
cB = self.cursorRect().bottom()
|
524
|
+
vH = self.viewport().height()
|
525
|
+
if cT < 0:
|
526
|
+
count = 0
|
527
|
+
vBar = self.verticalScrollBar()
|
528
|
+
while self.cursorRect().top() < 0 and count < 100000:
|
529
|
+
vBar.setValue(vBar.value() - 1)
|
530
|
+
count += 1
|
531
|
+
elif cB > vH:
|
532
|
+
count = 0
|
533
|
+
vBar = self.verticalScrollBar()
|
534
|
+
while self.cursorRect().bottom() > vH and count < 100000:
|
535
|
+
vBar.setValue(vBar.value() + 1)
|
536
|
+
count += 1
|
537
|
+
qApp.processEvents()
|
538
|
+
return
|
539
|
+
|
502
540
|
def updateDocMargins(self) -> None:
|
503
541
|
"""Automatically adjust the margins so the text is centred if
|
504
542
|
we have a text width set or we're in Focus Mode. Otherwise, just
|
@@ -640,7 +678,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
640
678
|
"""
|
641
679
|
logger.debug("Running spell checker")
|
642
680
|
start = time()
|
643
|
-
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
681
|
+
qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
644
682
|
self._qDocument.syntaxHighlighter.rehighlight()
|
645
683
|
qApp.restoreOverrideCursor()
|
646
684
|
logger.debug("Document highlighted in %.3f ms", 1000*(time() - start))
|
@@ -690,9 +728,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|
690
728
|
elif action == nwDocAction.D_QUOTE:
|
691
729
|
self._wrapSelection(self._typDQuoteO, self._typDQuoteC)
|
692
730
|
elif action == nwDocAction.SEL_ALL:
|
693
|
-
self._makeSelection(QTextCursor.Document)
|
731
|
+
self._makeSelection(QTextCursor.SelectionType.Document)
|
694
732
|
elif action == nwDocAction.SEL_PARA:
|
695
|
-
self._makeSelection(QTextCursor.BlockUnderCursor)
|
733
|
+
self._makeSelection(QTextCursor.SelectionType.BlockUnderCursor)
|
696
734
|
elif action == nwDocAction.BLOCK_H1:
|
697
735
|
self._formatBlock(nwDocAction.BLOCK_H1)
|
698
736
|
elif action == nwDocAction.BLOCK_H2:
|
@@ -796,6 +834,10 @@ class GuiDocEditor(QPlainTextEdit):
|
|
796
834
|
text = "% Synopsis: "
|
797
835
|
newBlock = True
|
798
836
|
goAfter = True
|
837
|
+
elif insert == nwDocInsert.SHORT:
|
838
|
+
text = "% Short: "
|
839
|
+
newBlock = True
|
840
|
+
goAfter = True
|
799
841
|
elif insert == nwDocInsert.NEW_PAGE:
|
800
842
|
text = "[newpage]"
|
801
843
|
newBlock = True
|
@@ -873,17 +915,17 @@ class GuiDocEditor(QPlainTextEdit):
|
|
873
915
|
* We also handle automatic scrolling here.
|
874
916
|
"""
|
875
917
|
self._lastActive = time()
|
876
|
-
isReturn = event.key() == Qt.Key_Return
|
877
|
-
isReturn |= event.key() == Qt.Key_Enter
|
918
|
+
isReturn = event.key() == Qt.Key.Key_Return
|
919
|
+
isReturn |= event.key() == Qt.Key.Key_Enter
|
878
920
|
if isReturn and self.docSearch.anyFocus():
|
879
921
|
return
|
880
|
-
elif event == QKeySequence.Redo:
|
922
|
+
elif event == QKeySequence.StandardKey.Redo:
|
881
923
|
self.docAction(nwDocAction.REDO)
|
882
924
|
return
|
883
|
-
elif event == QKeySequence.Undo:
|
925
|
+
elif event == QKeySequence.StandardKey.Undo:
|
884
926
|
self.docAction(nwDocAction.UNDO)
|
885
927
|
return
|
886
|
-
elif event == QKeySequence.SelectAll:
|
928
|
+
elif event == QKeySequence.StandardKey.SelectAll:
|
887
929
|
self.docAction(nwDocAction.SEL_ALL)
|
888
930
|
return
|
889
931
|
|
@@ -892,7 +934,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
892
934
|
super().keyPressEvent(event)
|
893
935
|
nPos = self.cursorRect().topLeft().y()
|
894
936
|
kMod = event.modifiers()
|
895
|
-
okMod = kMod
|
937
|
+
okMod = kMod in (Qt.KeyboardModifier.NoModifier, Qt.KeyboardModifier.ShiftModifier)
|
896
938
|
okKey = event.key() not in self.MOVE_KEYS
|
897
939
|
if nPos != cPos and okMod and okKey:
|
898
940
|
mPos = CONFIG.autoScrollPos*0.01 * self.viewport().height()
|
@@ -923,7 +965,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
923
965
|
pressed, check if we're clicking on a tag, and trigger the
|
924
966
|
follow tag function.
|
925
967
|
"""
|
926
|
-
if qApp.keyboardModifiers() == Qt.ControlModifier:
|
968
|
+
if qApp.keyboardModifiers() == Qt.KeyboardModifier.ControlModifier:
|
927
969
|
self._processTag(self.cursorForPosition(event.pos()))
|
928
970
|
super().mouseReleaseEvent(event)
|
929
971
|
self.docFooter.updateLineCount()
|
@@ -996,7 +1038,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|
996
1038
|
return
|
997
1039
|
|
998
1040
|
text = block.text()
|
999
|
-
if text.startswith("@"):
|
1041
|
+
if text.startswith("@") and added + removed == 1:
|
1042
|
+
# Only run on single keypresses, otherwise it will trigger
|
1043
|
+
# at unwanted times when other changes are made to the document
|
1000
1044
|
cursor = self.textCursor()
|
1001
1045
|
bPos = cursor.positionInBlock()
|
1002
1046
|
if bPos > 0:
|
@@ -1004,8 +1048,10 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1004
1048
|
point = self.cursorRect().bottomRight()
|
1005
1049
|
self._completer.move(self.viewport().mapToGlobal(point))
|
1006
1050
|
self._completer.setVisible(show)
|
1051
|
+
else:
|
1052
|
+
self._completer.setVisible(False)
|
1007
1053
|
|
1008
|
-
|
1054
|
+
if self._doReplace and added == 1:
|
1009
1055
|
self._docAutoReplace(text)
|
1010
1056
|
|
1011
1057
|
return
|
@@ -1025,43 +1071,50 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1025
1071
|
|
1026
1072
|
@pyqtSlot("QPoint")
|
1027
1073
|
def _openContextMenu(self, pos: QPoint) -> None:
|
1028
|
-
"""
|
1029
|
-
triggered by the Ctrl+. shortcut.
|
1030
|
-
"""
|
1074
|
+
"""Open the editor context menu at a given coordinate."""
|
1031
1075
|
uCursor = self.textCursor()
|
1032
1076
|
pCursor = self.cursorForPosition(pos)
|
1077
|
+
pBlock = pCursor.block()
|
1033
1078
|
|
1034
1079
|
ctxMenu = QMenu(self)
|
1080
|
+
ctxMenu.setObjectName("ContextMenu")
|
1081
|
+
if pBlock.userState() == GuiDocHighlighter.BLOCK_TITLE:
|
1082
|
+
action = ctxMenu.addAction(self.tr("Set as Document Name"))
|
1083
|
+
action.triggered.connect(lambda: self._emitRenameItem(pBlock))
|
1035
1084
|
|
1036
1085
|
# Follow
|
1037
1086
|
status = self._processTag(cursor=pCursor, follow=False)
|
1038
1087
|
if status == nwTrinary.POSITIVE:
|
1039
|
-
|
1040
|
-
|
1088
|
+
action = ctxMenu.addAction(self.tr("Follow Tag"))
|
1089
|
+
action.triggered.connect(lambda: self._processTag(cursor=pCursor, follow=True))
|
1041
1090
|
ctxMenu.addSeparator()
|
1042
1091
|
elif status == nwTrinary.NEGATIVE:
|
1043
|
-
|
1044
|
-
|
1092
|
+
action = ctxMenu.addAction(self.tr("Create Note for Tag"))
|
1093
|
+
action.triggered.connect(lambda: self._processTag(cursor=pCursor, create=True))
|
1045
1094
|
ctxMenu.addSeparator()
|
1046
1095
|
|
1047
1096
|
# Cut, Copy and Paste
|
1048
1097
|
if uCursor.hasSelection():
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1098
|
+
action = ctxMenu.addAction(self.tr("Cut"))
|
1099
|
+
action.triggered.connect(lambda: self.docAction(nwDocAction.CUT))
|
1100
|
+
action = ctxMenu.addAction(self.tr("Copy"))
|
1101
|
+
action.triggered.connect(lambda: self.docAction(nwDocAction.COPY))
|
1053
1102
|
|
1054
|
-
|
1055
|
-
|
1103
|
+
action = ctxMenu.addAction(self.tr("Paste"))
|
1104
|
+
action.triggered.connect(lambda: self.docAction(nwDocAction.PASTE))
|
1056
1105
|
ctxMenu.addSeparator()
|
1057
1106
|
|
1058
1107
|
# Selections
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1108
|
+
action = ctxMenu.addAction(self.tr("Select All"))
|
1109
|
+
action.triggered.connect(lambda: self.docAction(nwDocAction.SEL_ALL))
|
1110
|
+
action = ctxMenu.addAction(self.tr("Select Word"))
|
1111
|
+
action.triggered.connect(
|
1112
|
+
lambda: self._makePosSelection(QTextCursor.SelectionType.WordUnderCursor, pos)
|
1113
|
+
)
|
1114
|
+
action = ctxMenu.addAction(self.tr("Select Paragraph"))
|
1115
|
+
action.triggered.connect(lambda: self._makePosSelection(
|
1116
|
+
QTextCursor.SelectionType.BlockUnderCursor, pos)
|
1117
|
+
)
|
1065
1118
|
|
1066
1119
|
# Spell Checking
|
1067
1120
|
if SHARED.project.data.spellCheck:
|
@@ -1071,21 +1124,23 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1071
1124
|
block = pCursor.block()
|
1072
1125
|
sCursor = self.textCursor()
|
1073
1126
|
sCursor.setPosition(block.position() + cPos)
|
1074
|
-
sCursor.movePosition(
|
1127
|
+
sCursor.movePosition(
|
1128
|
+
QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, cLen
|
1129
|
+
)
|
1075
1130
|
if suggest:
|
1076
1131
|
ctxMenu.addSeparator()
|
1077
1132
|
ctxMenu.addAction(self.tr("Spelling Suggestion(s)"))
|
1078
1133
|
for option in suggest[:15]:
|
1079
|
-
|
1080
|
-
|
1134
|
+
action = ctxMenu.addAction(f"{nwUnicode.U_ENDASH} {option}")
|
1135
|
+
action.triggered.connect(
|
1081
1136
|
lambda _, option=option: self._correctWord(sCursor, option)
|
1082
1137
|
)
|
1083
1138
|
else:
|
1084
1139
|
ctxMenu.addAction("%s %s" % (nwUnicode.U_ENDASH, self.tr("No Suggestions")))
|
1085
1140
|
|
1086
1141
|
ctxMenu.addSeparator()
|
1087
|
-
|
1088
|
-
|
1142
|
+
action = ctxMenu.addAction(self.tr("Add Word to Dictionary"))
|
1143
|
+
action.triggered.connect(lambda: self._addWord(word, block))
|
1089
1144
|
|
1090
1145
|
# Execute the context menu
|
1091
1146
|
ctxMenu.exec_(self.viewport().mapToGlobal(pos))
|
@@ -1276,8 +1331,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1276
1331
|
else:
|
1277
1332
|
resIdx = 0 if doLoop else maxIdx
|
1278
1333
|
|
1279
|
-
cursor.setPosition(resS[resIdx], QTextCursor.MoveAnchor)
|
1280
|
-
cursor.setPosition(resE[resIdx], QTextCursor.KeepAnchor)
|
1334
|
+
cursor.setPosition(resS[resIdx], QTextCursor.MoveMode.MoveAnchor)
|
1335
|
+
cursor.setPosition(resE[resIdx], QTextCursor.MoveMode.KeepAnchor)
|
1281
1336
|
self.setTextCursor(cursor)
|
1282
1337
|
|
1283
1338
|
self.docFooter.updateLineCount()
|
@@ -1303,9 +1358,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1303
1358
|
|
1304
1359
|
findOpt = QTextDocument.FindFlag(0)
|
1305
1360
|
if self.docSearch.isCaseSense:
|
1306
|
-
findOpt |= QTextDocument.FindCaseSensitively
|
1361
|
+
findOpt |= QTextDocument.FindFlag.FindCaseSensitively
|
1307
1362
|
if self.docSearch.isWholeWord:
|
1308
|
-
findOpt |= QTextDocument.FindWholeWords
|
1363
|
+
findOpt |= QTextDocument.FindFlag.FindWholeWords
|
1309
1364
|
|
1310
1365
|
searchFor = self.docSearch.getSearchObject()
|
1311
1366
|
cursor.setPosition(0)
|
@@ -1323,8 +1378,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1323
1378
|
break
|
1324
1379
|
|
1325
1380
|
if hasSelection:
|
1326
|
-
cursor.setPosition(origA, QTextCursor.MoveAnchor)
|
1327
|
-
cursor.setPosition(origB, QTextCursor.KeepAnchor)
|
1381
|
+
cursor.setPosition(origA, QTextCursor.MoveMode.MoveAnchor)
|
1382
|
+
cursor.setPosition(origB, QTextCursor.MoveMode.KeepAnchor)
|
1328
1383
|
else:
|
1329
1384
|
cursor.setPosition(origA)
|
1330
1385
|
|
@@ -1410,22 +1465,33 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1410
1465
|
If more than one block is selected, the formatting is applied to
|
1411
1466
|
the first block.
|
1412
1467
|
"""
|
1413
|
-
cursor = self.
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1468
|
+
cursor = self.textCursor()
|
1469
|
+
posO = cursor.position()
|
1470
|
+
if cursor.hasSelection():
|
1471
|
+
select = _SelectAction.KEEP_SELECTION
|
1472
|
+
else:
|
1473
|
+
cursor = self._autoSelect()
|
1474
|
+
if cursor.hasSelection() and posO == cursor.selectionEnd():
|
1475
|
+
select = _SelectAction.MOVE_AFTER
|
1476
|
+
else:
|
1477
|
+
select = _SelectAction.KEEP_POSITION
|
1417
1478
|
|
1418
1479
|
posS = cursor.selectionStart()
|
1419
1480
|
posE = cursor.selectionEnd()
|
1481
|
+
if self._qDocument.characterAt(posO - 1) == fChar:
|
1482
|
+
logger.warning("Format repetition, cancelling action")
|
1483
|
+
cursor.clearSelection()
|
1484
|
+
cursor.setPosition(posO)
|
1485
|
+
self.setTextCursor(cursor)
|
1486
|
+
return False
|
1420
1487
|
|
1421
1488
|
blockS = self._qDocument.findBlock(posS)
|
1422
1489
|
blockE = self._qDocument.findBlock(posE)
|
1423
|
-
|
1424
1490
|
if blockS != blockE:
|
1425
1491
|
posE = blockS.position() + blockS.length() - 1
|
1426
1492
|
cursor.clearSelection()
|
1427
|
-
cursor.setPosition(posS, QTextCursor.MoveAnchor)
|
1428
|
-
cursor.setPosition(posE, QTextCursor.KeepAnchor)
|
1493
|
+
cursor.setPosition(posS, QTextCursor.MoveMode.MoveAnchor)
|
1494
|
+
cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor)
|
1429
1495
|
self.setTextCursor(cursor)
|
1430
1496
|
|
1431
1497
|
numB = 0
|
@@ -1443,34 +1509,26 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1443
1509
|
break
|
1444
1510
|
|
1445
1511
|
if fLen == min(numA, numB):
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1512
|
+
cursor.clearSelection()
|
1513
|
+
cursor.beginEditBlock()
|
1514
|
+
cursor.setPosition(posS)
|
1515
|
+
for i in range(fLen):
|
1516
|
+
cursor.deletePreviousChar()
|
1517
|
+
cursor.setPosition(posE)
|
1518
|
+
for i in range(fLen):
|
1519
|
+
cursor.deletePreviousChar()
|
1520
|
+
cursor.endEditBlock()
|
1521
|
+
cursor.clearSelection()
|
1522
|
+
cursor.setPosition(posO - fLen)
|
1523
|
+
self.setTextCursor(cursor)
|
1457
1524
|
|
1458
|
-
|
1459
|
-
|
1460
|
-
cursor.clearSelection()
|
1461
|
-
cursor.beginEditBlock()
|
1462
|
-
cursor.setPosition(posS)
|
1463
|
-
for i in range(nChars):
|
1464
|
-
cursor.deletePreviousChar()
|
1465
|
-
cursor.setPosition(posE)
|
1466
|
-
for i in range(nChars):
|
1467
|
-
cursor.deletePreviousChar()
|
1468
|
-
cursor.endEditBlock()
|
1469
|
-
cursor.clearSelection()
|
1525
|
+
else:
|
1526
|
+
self._wrapSelection(fChar*fLen, pos=posO, select=select)
|
1470
1527
|
|
1471
1528
|
return True
|
1472
1529
|
|
1473
|
-
def _wrapSelection(self, before: str, after: str | None = None
|
1530
|
+
def _wrapSelection(self, before: str, after: str | None = None, pos: int | None = None,
|
1531
|
+
select: _SelectAction = _SelectAction.NO_DECISION) -> bool:
|
1474
1532
|
"""Wrap the selected text in whatever is in tBefore and tAfter.
|
1475
1533
|
If there is no selection, the autoSelect setting decides the
|
1476
1534
|
action. AutoSelect will select the word under the cursor before
|
@@ -1479,10 +1537,17 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1479
1537
|
if after is None:
|
1480
1538
|
after = before
|
1481
1539
|
|
1482
|
-
cursor = self.
|
1483
|
-
if
|
1484
|
-
|
1485
|
-
|
1540
|
+
cursor = self.textCursor()
|
1541
|
+
posO = pos if isinstance(pos, int) else cursor.position()
|
1542
|
+
if select == _SelectAction.NO_DECISION:
|
1543
|
+
if cursor.hasSelection():
|
1544
|
+
select = _SelectAction.KEEP_SELECTION
|
1545
|
+
else:
|
1546
|
+
cursor = self._autoSelect()
|
1547
|
+
if cursor.hasSelection() and posO == cursor.selectionEnd():
|
1548
|
+
select = _SelectAction.MOVE_AFTER
|
1549
|
+
else:
|
1550
|
+
select = _SelectAction.KEEP_POSITION
|
1486
1551
|
|
1487
1552
|
posS = cursor.selectionStart()
|
1488
1553
|
posE = cursor.selectionEnd()
|
@@ -1500,8 +1565,14 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1500
1565
|
cursor.insertText(before)
|
1501
1566
|
cursor.endEditBlock()
|
1502
1567
|
|
1503
|
-
|
1504
|
-
|
1568
|
+
if select == _SelectAction.MOVE_AFTER:
|
1569
|
+
cursor.setPosition(posE + len(before + after))
|
1570
|
+
elif select == _SelectAction.KEEP_SELECTION:
|
1571
|
+
cursor.setPosition(posE + len(before), QTextCursor.MoveMode.MoveAnchor)
|
1572
|
+
cursor.setPosition(posS + len(before), QTextCursor.MoveMode.KeepAnchor)
|
1573
|
+
elif select == _SelectAction.KEEP_POSITION:
|
1574
|
+
cursor.setPosition(posO + len(before))
|
1575
|
+
|
1505
1576
|
self.setTextCursor(cursor)
|
1506
1577
|
|
1507
1578
|
return True
|
@@ -1522,7 +1593,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1522
1593
|
self._allowAutoReplace(False)
|
1523
1594
|
for posC in range(posS, posE+1):
|
1524
1595
|
cursor.setPosition(posC)
|
1525
|
-
cursor.movePosition(
|
1596
|
+
cursor.movePosition(
|
1597
|
+
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 2
|
1598
|
+
)
|
1526
1599
|
selText = cursor.selectedText()
|
1527
1600
|
|
1528
1601
|
nS = len(selText)
|
@@ -1542,12 +1615,16 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1542
1615
|
cursor.setPosition(posC)
|
1543
1616
|
if pC in closeCheck:
|
1544
1617
|
cursor.beginEditBlock()
|
1545
|
-
cursor.movePosition(
|
1618
|
+
cursor.movePosition(
|
1619
|
+
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 1
|
1620
|
+
)
|
1546
1621
|
cursor.insertText(oQuote)
|
1547
1622
|
cursor.endEditBlock()
|
1548
1623
|
else:
|
1549
1624
|
cursor.beginEditBlock()
|
1550
|
-
cursor.movePosition(
|
1625
|
+
cursor.movePosition(
|
1626
|
+
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 1
|
1627
|
+
)
|
1551
1628
|
cursor.insertText(cQuote)
|
1552
1629
|
cursor.endEditBlock()
|
1553
1630
|
|
@@ -1667,7 +1744,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1667
1744
|
# Replace the block text
|
1668
1745
|
cursor.beginEditBlock()
|
1669
1746
|
posO = cursor.position()
|
1670
|
-
cursor.select(QTextCursor.BlockUnderCursor)
|
1747
|
+
cursor.select(QTextCursor.SelectionType.BlockUnderCursor)
|
1671
1748
|
posS = cursor.selectionStart()
|
1672
1749
|
cursor.removeSelectedText()
|
1673
1750
|
cursor.setPosition(posS)
|
@@ -1727,7 +1804,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1727
1804
|
cursor.beginEditBlock()
|
1728
1805
|
cursor.clearSelection()
|
1729
1806
|
cursor.setPosition(rS)
|
1730
|
-
cursor.movePosition(
|
1807
|
+
cursor.movePosition(
|
1808
|
+
QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, rE-rS
|
1809
|
+
)
|
1731
1810
|
cursor.insertText(cleanText.rstrip() + "\n")
|
1732
1811
|
cursor.endEditBlock()
|
1733
1812
|
|
@@ -1751,13 +1830,13 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1751
1830
|
block = cursor.block()
|
1752
1831
|
text = block.text()
|
1753
1832
|
if len(text) == 0:
|
1754
|
-
return nwTrinary.
|
1833
|
+
return nwTrinary.NEUTRAL
|
1755
1834
|
|
1756
1835
|
if text.startswith("@") and isinstance(self._nwItem, NWItem):
|
1757
1836
|
|
1758
1837
|
isGood, tBits, tPos = SHARED.project.index.scanThis(text)
|
1759
1838
|
if not isGood:
|
1760
|
-
return nwTrinary.
|
1839
|
+
return nwTrinary.NEUTRAL
|
1761
1840
|
|
1762
1841
|
tag = ""
|
1763
1842
|
exist = False
|
@@ -1774,7 +1853,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1774
1853
|
|
1775
1854
|
if not tag or tag.startswith("@"):
|
1776
1855
|
# The keyword cannot be looked up, so we ignore that
|
1777
|
-
return nwTrinary.
|
1856
|
+
return nwTrinary.NEUTRAL
|
1778
1857
|
|
1779
1858
|
if follow and exist:
|
1780
1859
|
logger.debug("Attempting to follow tag '%s'", tag)
|
@@ -1794,7 +1873,14 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1794
1873
|
|
1795
1874
|
return nwTrinary.POSITIVE if exist else nwTrinary.NEGATIVE
|
1796
1875
|
|
1797
|
-
return nwTrinary.
|
1876
|
+
return nwTrinary.NEUTRAL
|
1877
|
+
|
1878
|
+
def _emitRenameItem(self, block: QTextBlock) -> None:
|
1879
|
+
"""Emit a signal to request an item be renamed."""
|
1880
|
+
if self._docHandle:
|
1881
|
+
text = block.text().lstrip("#").lstrip("!").strip()
|
1882
|
+
self.requestProjectItemRenamed.emit(self._docHandle, text)
|
1883
|
+
return
|
1798
1884
|
|
1799
1885
|
def _openContextFromCursor(self) -> None:
|
1800
1886
|
"""Open the spell check context menu at the cursor."""
|
@@ -1887,7 +1973,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1887
1973
|
tInsert = tInsert + self._typPadChar
|
1888
1974
|
|
1889
1975
|
if nDelete > 0:
|
1890
|
-
cursor.movePosition(
|
1976
|
+
cursor.movePosition(
|
1977
|
+
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, nDelete
|
1978
|
+
)
|
1891
1979
|
cursor.insertText(tInsert)
|
1892
1980
|
|
1893
1981
|
return
|
@@ -1908,27 +1996,38 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1908
1996
|
|
1909
1997
|
def _autoSelect(self) -> QTextCursor:
|
1910
1998
|
"""Return a cursor which may or may not have a selection based
|
1911
|
-
on user settings and document action.
|
1999
|
+
on user settings and document action. The selection will be the
|
2000
|
+
word closest to the cursor consisting of alphanumerical unicode
|
2001
|
+
characters.
|
1912
2002
|
"""
|
1913
2003
|
cursor = self.textCursor()
|
1914
2004
|
if CONFIG.autoSelect and not cursor.hasSelection():
|
1915
|
-
cursor.
|
1916
|
-
|
1917
|
-
|
2005
|
+
cPos = cursor.position()
|
2006
|
+
bPos = cursor.block().position()
|
2007
|
+
bLen = cursor.block().length()
|
2008
|
+
|
2009
|
+
# Scan backwards
|
2010
|
+
sPos = cPos
|
2011
|
+
for i in range(cPos - bPos):
|
2012
|
+
sPos = cPos - i - 1
|
2013
|
+
if not self._qDocument.characterAt(sPos).isalnum():
|
2014
|
+
sPos += 1
|
2015
|
+
break
|
2016
|
+
|
2017
|
+
# Scan forwards
|
2018
|
+
ePos = cPos
|
2019
|
+
for i in range(bPos + bLen - cPos):
|
2020
|
+
ePos = cPos + i
|
2021
|
+
if not self._qDocument.characterAt(ePos).isalnum():
|
2022
|
+
break
|
2023
|
+
|
2024
|
+
if ePos - sPos <= 0:
|
2025
|
+
# No selection possible
|
2026
|
+
return cursor
|
1918
2027
|
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
if self._qDocument.characterAt(posS) == "_":
|
1923
|
-
posS += 1
|
1924
|
-
reSelect = True
|
1925
|
-
if self._qDocument.characterAt(posE) == "_":
|
1926
|
-
posE -= 1
|
1927
|
-
reSelect = True
|
1928
|
-
if reSelect:
|
1929
|
-
cursor.clearSelection()
|
1930
|
-
cursor.setPosition(posS, QTextCursor.MoveAnchor)
|
1931
|
-
cursor.setPosition(posE-1, QTextCursor.KeepAnchor)
|
2028
|
+
cursor.clearSelection()
|
2029
|
+
cursor.setPosition(sPos, QTextCursor.MoveMode.MoveAnchor)
|
2030
|
+
cursor.setPosition(ePos, QTextCursor.MoveMode.KeepAnchor)
|
1932
2031
|
|
1933
2032
|
self.setTextCursor(cursor)
|
1934
2033
|
|
@@ -1940,18 +2039,18 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1940
2039
|
cursor.clearSelection()
|
1941
2040
|
cursor.select(mode)
|
1942
2041
|
|
1943
|
-
if mode == QTextCursor.WordUnderCursor:
|
2042
|
+
if mode == QTextCursor.SelectionType.WordUnderCursor:
|
1944
2043
|
cursor = self._autoSelect()
|
1945
2044
|
|
1946
|
-
elif mode == QTextCursor.BlockUnderCursor:
|
2045
|
+
elif mode == QTextCursor.SelectionType.BlockUnderCursor:
|
1947
2046
|
# This selection mode also selects the preceding paragraph
|
1948
2047
|
# separator, which we want to avoid.
|
1949
2048
|
posS = cursor.selectionStart()
|
1950
2049
|
posE = cursor.selectionEnd()
|
1951
2050
|
selTxt = cursor.selectedText()
|
1952
2051
|
if selTxt.startswith(nwUnicode.U_PSEP):
|
1953
|
-
cursor.setPosition(posS+1, QTextCursor.MoveAnchor)
|
1954
|
-
cursor.setPosition(posE, QTextCursor.KeepAnchor)
|
2052
|
+
cursor.setPosition(posS+1, QTextCursor.MoveMode.MoveAnchor)
|
2053
|
+
cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor)
|
1955
2054
|
|
1956
2055
|
self.setTextCursor(cursor)
|
1957
2056
|
|
@@ -2011,7 +2110,7 @@ class MetaCompleter(QMenu):
|
|
2011
2110
|
length = len(lookup)
|
2012
2111
|
suffix = ""
|
2013
2112
|
options = list(filter(
|
2014
|
-
lambda x: lookup in x.lower(), SHARED.project.index.
|
2113
|
+
lambda x: lookup in x.lower(), SHARED.project.index.getClassTags(
|
2015
2114
|
nwKeyWords.KEY_CLASS.get(kw.strip(), nwItemClass.NO_CLASS)
|
2016
2115
|
)
|
2017
2116
|
))[:15]
|
@@ -2033,7 +2132,10 @@ class MetaCompleter(QMenu):
|
|
2033
2132
|
def keyPressEvent(self, event: QKeyEvent) -> None:
|
2034
2133
|
"""Capture keypresses and forward most of them to the editor."""
|
2035
2134
|
parent = self.parent()
|
2036
|
-
if event.key() in (
|
2135
|
+
if event.key() in (
|
2136
|
+
Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_Return,
|
2137
|
+
Qt.Key.Key_Enter, Qt.Key.Key_Escape
|
2138
|
+
):
|
2037
2139
|
super().keyPressEvent(event)
|
2038
2140
|
elif isinstance(parent, GuiDocEditor):
|
2039
2141
|
parent.keyPressEvent(event)
|
@@ -2187,9 +2289,9 @@ class GuiDocToolBar(QWidget):
|
|
2187
2289
|
def updateTheme(self) -> None:
|
2188
2290
|
"""Initialise GUI elements that depend on specific settings."""
|
2189
2291
|
palette = QPalette()
|
2190
|
-
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
2191
|
-
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
2192
|
-
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
2292
|
+
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
2293
|
+
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
2294
|
+
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
2193
2295
|
self.setPalette(palette)
|
2194
2296
|
|
2195
2297
|
tPx = int(0.8*SHARED.theme.fontPixelSize)
|
@@ -2269,7 +2371,7 @@ class GuiDocEditSearch(QFrame):
|
|
2269
2371
|
|
2270
2372
|
self.setContentsMargins(0, 0, 0, 0)
|
2271
2373
|
self.setAutoFillBackground(True)
|
2272
|
-
self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
|
2374
|
+
self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
|
2273
2375
|
|
2274
2376
|
self.mainBox = QGridLayout(self)
|
2275
2377
|
self.setLayout(self.mainBox)
|
@@ -2288,7 +2390,7 @@ class GuiDocEditSearch(QFrame):
|
|
2288
2390
|
self.replaceBox.returnPressed.connect(self._doReplace)
|
2289
2391
|
|
2290
2392
|
self.searchOpt = QToolBar(self)
|
2291
|
-
self.searchOpt.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
2393
|
+
self.searchOpt.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
2292
2394
|
self.searchOpt.setIconSize(QSize(tPx, tPx))
|
2293
2395
|
self.searchOpt.setContentsMargins(0, 0, 0, 0)
|
2294
2396
|
|
@@ -2350,7 +2452,7 @@ class GuiDocEditSearch(QFrame):
|
|
2350
2452
|
bPx = self.searchBox.sizeHint().height()
|
2351
2453
|
|
2352
2454
|
self.showReplace = QToolButton(self)
|
2353
|
-
self.showReplace.setArrowType(Qt.RightArrow)
|
2455
|
+
self.showReplace.setArrowType(Qt.ArrowType.RightArrow)
|
2354
2456
|
self.showReplace.setCheckable(True)
|
2355
2457
|
self.showReplace.toggled.connect(self._doToggleReplace)
|
2356
2458
|
|
@@ -2364,8 +2466,8 @@ class GuiDocEditSearch(QFrame):
|
|
2364
2466
|
self.replaceButton.setToolTip(self.tr("Find and replace in current document"))
|
2365
2467
|
self.replaceButton.clicked.connect(self._doReplace)
|
2366
2468
|
|
2367
|
-
self.mainBox.addWidget(self.searchLabel, 0, 0, 1, 2, Qt.AlignLeft)
|
2368
|
-
self.mainBox.addWidget(self.searchOpt, 0, 2, 1, 3, Qt.AlignRight)
|
2469
|
+
self.mainBox.addWidget(self.searchLabel, 0, 0, 1, 2, Qt.AlignmentFlag.AlignLeft)
|
2470
|
+
self.mainBox.addWidget(self.searchOpt, 0, 2, 1, 3, Qt.AlignmentFlag.AlignRight)
|
2369
2471
|
self.mainBox.addWidget(self.showReplace, 1, 0, 1, 1)
|
2370
2472
|
self.mainBox.addWidget(self.searchBox, 1, 1, 1, 2)
|
2371
2473
|
self.mainBox.addWidget(self.searchButton, 1, 3, 1, 1)
|
@@ -2423,18 +2525,18 @@ class GuiDocEditSearch(QFrame):
|
|
2423
2525
|
# only added in Qt 5.13. Otherwise, 5.3 and up supports
|
2424
2526
|
# only the QRegExp class.
|
2425
2527
|
if CONFIG.verQtValue >= 0x050d00:
|
2426
|
-
rxOpt = QRegularExpression.UseUnicodePropertiesOption
|
2528
|
+
rxOpt = QRegularExpression.PatternOption.UseUnicodePropertiesOption
|
2427
2529
|
if not self.isCaseSense:
|
2428
|
-
rxOpt |= QRegularExpression.CaseInsensitiveOption
|
2530
|
+
rxOpt |= QRegularExpression.PatternOption.CaseInsensitiveOption
|
2429
2531
|
regEx = QRegularExpression(text, rxOpt)
|
2430
2532
|
self._alertSearchValid(regEx.isValid())
|
2431
2533
|
return regEx
|
2432
2534
|
else: # pragma: no cover
|
2433
2535
|
# >= 50300 to < 51300
|
2434
2536
|
if self.isCaseSense:
|
2435
|
-
rxOpt = Qt.CaseSensitive
|
2537
|
+
rxOpt = Qt.CaseSensitivity.CaseSensitive
|
2436
2538
|
else:
|
2437
|
-
rxOpt = Qt.CaseInsensitive
|
2539
|
+
rxOpt = Qt.CaseSensitivity.CaseInsensitive
|
2438
2540
|
regEx = QRegExp(text, rxOpt)
|
2439
2541
|
self._alertSearchValid(regEx.isValid())
|
2440
2542
|
return regEx
|
@@ -2570,7 +2672,7 @@ class GuiDocEditSearch(QFrame):
|
|
2570
2672
|
def _doSearch(self) -> None:
|
2571
2673
|
"""Call the search action function for the document editor."""
|
2572
2674
|
modKey = qApp.keyboardModifiers()
|
2573
|
-
if modKey == Qt.ShiftModifier:
|
2675
|
+
if modKey == Qt.KeyboardModifier.ShiftModifier:
|
2574
2676
|
self.docEditor.findNext(goBack=True)
|
2575
2677
|
else:
|
2576
2678
|
self.docEditor.findNext()
|
@@ -2586,9 +2688,9 @@ class GuiDocEditSearch(QFrame):
|
|
2586
2688
|
def _doToggleReplace(self, state: bool) -> None:
|
2587
2689
|
"""Toggle the show/hide of the replace box."""
|
2588
2690
|
if state:
|
2589
|
-
self.showReplace.setArrowType(Qt.DownArrow)
|
2691
|
+
self.showReplace.setArrowType(Qt.ArrowType.DownArrow)
|
2590
2692
|
else:
|
2591
|
-
self.showReplace.setArrowType(Qt.RightArrow)
|
2693
|
+
self.showReplace.setArrowType(Qt.ArrowType.RightArrow)
|
2592
2694
|
self.replaceBox.setVisible(state)
|
2593
2695
|
self.replaceButton.setVisible(state)
|
2594
2696
|
self.repVisible = state
|
@@ -2641,7 +2743,7 @@ class GuiDocEditSearch(QFrame):
|
|
2641
2743
|
isn't valid. Take the colour from the replace box.
|
2642
2744
|
"""
|
2643
2745
|
qPalette = self.replaceBox.palette()
|
2644
|
-
qPalette.setColor(QPalette.Base, self.rxCol[isValid])
|
2746
|
+
qPalette.setColor(QPalette.ColorRole.Base, self.rxCol[isValid])
|
2645
2747
|
self.searchBox.setPalette(qPalette)
|
2646
2748
|
return
|
2647
2749
|
|
@@ -2682,7 +2784,7 @@ class GuiDocEditHeader(QWidget):
|
|
2682
2784
|
self.itemTitle.setMargin(0)
|
2683
2785
|
self.itemTitle.setContentsMargins(0, 0, 0, 0)
|
2684
2786
|
self.itemTitle.setAutoFillBackground(True)
|
2685
|
-
self.itemTitle.setAlignment(Qt.AlignHCenter | Qt.AlignTop)
|
2787
|
+
self.itemTitle.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop)
|
2686
2788
|
self.itemTitle.setFixedHeight(fPx)
|
2687
2789
|
|
2688
2790
|
lblFont = self.itemTitle.font()
|
@@ -2694,7 +2796,7 @@ class GuiDocEditHeader(QWidget):
|
|
2694
2796
|
self.tbButton.setContentsMargins(0, 0, 0, 0)
|
2695
2797
|
self.tbButton.setIconSize(iconSize)
|
2696
2798
|
self.tbButton.setFixedSize(fPx, fPx)
|
2697
|
-
self.tbButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
2799
|
+
self.tbButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
2698
2800
|
self.tbButton.setVisible(False)
|
2699
2801
|
self.tbButton.setToolTip(self.tr("Toggle Tool Bar"))
|
2700
2802
|
self.tbButton.clicked.connect(lambda: self.toggleToolBarRequest.emit())
|
@@ -2703,7 +2805,7 @@ class GuiDocEditHeader(QWidget):
|
|
2703
2805
|
self.searchButton.setContentsMargins(0, 0, 0, 0)
|
2704
2806
|
self.searchButton.setIconSize(iconSize)
|
2705
2807
|
self.searchButton.setFixedSize(fPx, fPx)
|
2706
|
-
self.searchButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
2808
|
+
self.searchButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
2707
2809
|
self.searchButton.setVisible(False)
|
2708
2810
|
self.searchButton.setToolTip(self.tr("Search"))
|
2709
2811
|
self.searchButton.clicked.connect(self.docEditor.toggleSearch)
|
@@ -2712,7 +2814,7 @@ class GuiDocEditHeader(QWidget):
|
|
2712
2814
|
self.minmaxButton.setContentsMargins(0, 0, 0, 0)
|
2713
2815
|
self.minmaxButton.setIconSize(iconSize)
|
2714
2816
|
self.minmaxButton.setFixedSize(fPx, fPx)
|
2715
|
-
self.minmaxButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
2817
|
+
self.minmaxButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
2716
2818
|
self.minmaxButton.setVisible(False)
|
2717
2819
|
self.minmaxButton.setToolTip(self.tr("Toggle Focus Mode"))
|
2718
2820
|
self.minmaxButton.clicked.connect(lambda: self.docEditor.toggleFocusModeRequest.emit())
|
@@ -2721,7 +2823,7 @@ class GuiDocEditHeader(QWidget):
|
|
2721
2823
|
self.closeButton.setContentsMargins(0, 0, 0, 0)
|
2722
2824
|
self.closeButton.setIconSize(iconSize)
|
2723
2825
|
self.closeButton.setFixedSize(fPx, fPx)
|
2724
|
-
self.closeButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
2826
|
+
self.closeButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
2725
2827
|
self.closeButton.setVisible(False)
|
2726
2828
|
self.closeButton.setToolTip(self.tr("Close"))
|
2727
2829
|
self.closeButton.clicked.connect(self._closeDocument)
|
@@ -2779,9 +2881,9 @@ class GuiDocEditHeader(QWidget):
|
|
2779
2881
|
theme rather than the main GUI.
|
2780
2882
|
"""
|
2781
2883
|
palette = QPalette()
|
2782
|
-
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
2783
|
-
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
2784
|
-
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
2884
|
+
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
2885
|
+
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
2886
|
+
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
2785
2887
|
|
2786
2888
|
self.setPalette(palette)
|
2787
2889
|
self.itemTitle.setPalette(palette)
|
@@ -2857,7 +2959,8 @@ class GuiDocEditHeader(QWidget):
|
|
2857
2959
|
"""Capture a click on the title and ensure that the item is
|
2858
2960
|
selected in the project tree.
|
2859
2961
|
"""
|
2860
|
-
|
2962
|
+
if event.button() == Qt.MouseButton.LeftButton:
|
2963
|
+
self.docEditor.requestProjectItemSelected.emit(self._docHandle, True)
|
2861
2964
|
return
|
2862
2965
|
|
2863
2966
|
# END Class GuiDocEditHeader
|
@@ -2894,11 +2997,13 @@ class GuiDocEditFooter(QWidget):
|
|
2894
2997
|
self.setContentsMargins(0, 0, 0, 0)
|
2895
2998
|
self.setAutoFillBackground(True)
|
2896
2999
|
|
3000
|
+
alLeftTop = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop
|
3001
|
+
|
2897
3002
|
# Status
|
2898
3003
|
self.statusIcon = QLabel("")
|
2899
3004
|
self.statusIcon.setContentsMargins(0, 0, 0, 0)
|
2900
3005
|
self.statusIcon.setFixedHeight(self.sPx)
|
2901
|
-
self.statusIcon.setAlignment(
|
3006
|
+
self.statusIcon.setAlignment(alLeftTop)
|
2902
3007
|
|
2903
3008
|
self.statusText = QLabel(self.tr("Status"))
|
2904
3009
|
self.statusText.setIndent(0)
|
@@ -2906,14 +3011,14 @@ class GuiDocEditFooter(QWidget):
|
|
2906
3011
|
self.statusText.setContentsMargins(0, 0, 0, 0)
|
2907
3012
|
self.statusText.setAutoFillBackground(True)
|
2908
3013
|
self.statusText.setFixedHeight(fPx)
|
2909
|
-
self.statusText.setAlignment(
|
3014
|
+
self.statusText.setAlignment(alLeftTop)
|
2910
3015
|
self.statusText.setFont(lblFont)
|
2911
3016
|
|
2912
3017
|
# Lines
|
2913
3018
|
self.linesIcon = QLabel("")
|
2914
3019
|
self.linesIcon.setContentsMargins(0, 0, 0, 0)
|
2915
3020
|
self.linesIcon.setFixedHeight(self.sPx)
|
2916
|
-
self.linesIcon.setAlignment(
|
3021
|
+
self.linesIcon.setAlignment(alLeftTop)
|
2917
3022
|
|
2918
3023
|
self.linesText = QLabel("")
|
2919
3024
|
self.linesText.setIndent(0)
|
@@ -2921,14 +3026,14 @@ class GuiDocEditFooter(QWidget):
|
|
2921
3026
|
self.linesText.setContentsMargins(0, 0, 0, 0)
|
2922
3027
|
self.linesText.setAutoFillBackground(True)
|
2923
3028
|
self.linesText.setFixedHeight(fPx)
|
2924
|
-
self.linesText.setAlignment(
|
3029
|
+
self.linesText.setAlignment(alLeftTop)
|
2925
3030
|
self.linesText.setFont(lblFont)
|
2926
3031
|
|
2927
3032
|
# Words
|
2928
3033
|
self.wordsIcon = QLabel("")
|
2929
3034
|
self.wordsIcon.setContentsMargins(0, 0, 0, 0)
|
2930
3035
|
self.wordsIcon.setFixedHeight(self.sPx)
|
2931
|
-
self.wordsIcon.setAlignment(
|
3036
|
+
self.wordsIcon.setAlignment(alLeftTop)
|
2932
3037
|
|
2933
3038
|
self.wordsText = QLabel("")
|
2934
3039
|
self.wordsText.setIndent(0)
|
@@ -2936,7 +3041,7 @@ class GuiDocEditFooter(QWidget):
|
|
2936
3041
|
self.wordsText.setContentsMargins(0, 0, 0, 0)
|
2937
3042
|
self.wordsText.setAutoFillBackground(True)
|
2938
3043
|
self.wordsText.setFixedHeight(fPx)
|
2939
|
-
self.wordsText.setAlignment(
|
3044
|
+
self.wordsText.setAlignment(alLeftTop)
|
2940
3045
|
self.wordsText.setFont(lblFont)
|
2941
3046
|
|
2942
3047
|
# Assemble Layout
|
@@ -2984,9 +3089,9 @@ class GuiDocEditFooter(QWidget):
|
|
2984
3089
|
theme rather than the main GUI.
|
2985
3090
|
"""
|
2986
3091
|
palette = QPalette()
|
2987
|
-
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
2988
|
-
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
2989
|
-
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
3092
|
+
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
3093
|
+
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
3094
|
+
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
2990
3095
|
|
2991
3096
|
self.setPalette(palette)
|
2992
3097
|
self.statusText.setPalette(palette)
|