Add a context menu entry to set item name from heading (#1614)
This commit is contained in:
+147
-113
@@ -83,8 +83,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
"""Gui Widget: Main Document Editor"""
|
"""Gui Widget: Main Document Editor"""
|
||||||
|
|
||||||
MOVE_KEYS = (
|
MOVE_KEYS = (
|
||||||
Qt.Key_Left, Qt.Key_Right, Qt.Key_Up, Qt.Key_Down,
|
Qt.Key.Key_Left, Qt.Key.Key_Right, Qt.Key.Key_Up, Qt.Key.Key_Down,
|
||||||
Qt.Key_PageUp, Qt.Key_PageDown
|
Qt.Key.Key_PageUp, Qt.Key.Key_PageDown
|
||||||
)
|
)
|
||||||
|
|
||||||
# Custom Signals
|
# Custom Signals
|
||||||
@@ -97,6 +97,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
spellCheckStateChanged = pyqtSignal(bool)
|
spellCheckStateChanged = pyqtSignal(bool)
|
||||||
closeDocumentRequest = pyqtSignal()
|
closeDocumentRequest = pyqtSignal()
|
||||||
toggleFocusModeRequest = pyqtSignal()
|
toggleFocusModeRequest = pyqtSignal()
|
||||||
|
requestProjectItemSelected = pyqtSignal(str, bool)
|
||||||
|
requestProjectItemRenamed = pyqtSignal(str, str)
|
||||||
|
|
||||||
def __init__(self, mainGui: GuiMain) -> None:
|
def __init__(self, mainGui: GuiMain) -> None:
|
||||||
super().__init__(parent=mainGui)
|
super().__init__(parent=mainGui)
|
||||||
@@ -157,28 +159,28 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
self.docToolBar.requestDocAction.connect(self.docAction)
|
self.docToolBar.requestDocAction.connect(self.docAction)
|
||||||
|
|
||||||
# Context Menu
|
# Context Menu
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||||
self.customContextMenuRequested.connect(self._openContextMenu)
|
self.customContextMenuRequested.connect(self._openContextMenu)
|
||||||
|
|
||||||
# Editor Settings
|
# Editor Settings
|
||||||
self.setMinimumWidth(CONFIG.pxInt(300))
|
self.setMinimumWidth(CONFIG.pxInt(300))
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
self.setFrameStyle(QFrame.NoFrame)
|
self.setFrameStyle(QFrame.Shape.NoFrame)
|
||||||
|
|
||||||
# Custom Shortcuts
|
# Custom Shortcuts
|
||||||
self.keyContext = QShortcut(self)
|
self.keyContext = QShortcut(self)
|
||||||
self.keyContext.setKey("Ctrl+.")
|
self.keyContext.setKey("Ctrl+.")
|
||||||
self.keyContext.setContext(Qt.WidgetShortcut)
|
self.keyContext.setContext(Qt.ShortcutContext.WidgetShortcut)
|
||||||
self.keyContext.activated.connect(self._openContextFromCursor)
|
self.keyContext.activated.connect(self._openContextFromCursor)
|
||||||
|
|
||||||
self.followTag1 = QShortcut(self)
|
self.followTag1 = QShortcut(self)
|
||||||
self.followTag1.setKey(Qt.Key_Return | Qt.ControlModifier)
|
self.followTag1.setKey(Qt.Key.Key_Return | Qt.KeyboardModifier.ControlModifier)
|
||||||
self.followTag1.setContext(Qt.WidgetShortcut)
|
self.followTag1.setContext(Qt.ShortcutContext.WidgetShortcut)
|
||||||
self.followTag1.activated.connect(self._processTag)
|
self.followTag1.activated.connect(self._processTag)
|
||||||
|
|
||||||
self.followTag2 = QShortcut(self)
|
self.followTag2 = QShortcut(self)
|
||||||
self.followTag2.setKey(Qt.Key_Enter | Qt.ControlModifier)
|
self.followTag2.setKey(Qt.Key.Key_Enter | Qt.KeyboardModifier.ControlModifier)
|
||||||
self.followTag2.setContext(Qt.WidgetShortcut)
|
self.followTag2.setContext(Qt.ShortcutContext.WidgetShortcut)
|
||||||
self.followTag2.activated.connect(self._processTag)
|
self.followTag2.activated.connect(self._processTag)
|
||||||
|
|
||||||
# Set Up Document Word Counter
|
# Set Up Document Word Counter
|
||||||
@@ -274,14 +276,14 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
def updateSyntaxColours(self) -> None:
|
def updateSyntaxColours(self) -> None:
|
||||||
"""Update the syntax highlighting theme."""
|
"""Update the syntax highlighting theme."""
|
||||||
mainPalette = self.palette()
|
mainPalette = self.palette()
|
||||||
mainPalette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
mainPalette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
||||||
mainPalette.setColor(QPalette.Base, QColor(*SHARED.theme.colBack))
|
mainPalette.setColor(QPalette.ColorRole.Base, QColor(*SHARED.theme.colBack))
|
||||||
mainPalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
mainPalette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
self.setPalette(mainPalette)
|
self.setPalette(mainPalette)
|
||||||
|
|
||||||
docPalette = self.viewport().palette()
|
docPalette = self.viewport().palette()
|
||||||
docPalette.setColor(QPalette.Base, QColor(*SHARED.theme.colBack))
|
docPalette.setColor(QPalette.ColorRole.Base, QColor(*SHARED.theme.colBack))
|
||||||
docPalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
docPalette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
self.viewport().setPalette(docPalette)
|
self.viewport().setPalette(docPalette)
|
||||||
|
|
||||||
self.docHeader.matchColours()
|
self.docHeader.matchColours()
|
||||||
@@ -333,25 +335,25 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
options = QTextOption()
|
options = QTextOption()
|
||||||
|
|
||||||
if CONFIG.doJustify:
|
if CONFIG.doJustify:
|
||||||
options.setAlignment(Qt.AlignJustify)
|
options.setAlignment(Qt.AlignmentFlag.AlignJustify)
|
||||||
if CONFIG.showTabsNSpaces:
|
if CONFIG.showTabsNSpaces:
|
||||||
options.setFlags(options.flags() | QTextOption.ShowTabsAndSpaces)
|
options.setFlags(options.flags() | QTextOption.Flag.ShowTabsAndSpaces)
|
||||||
if CONFIG.showLineEndings:
|
if CONFIG.showLineEndings:
|
||||||
options.setFlags(options.flags() | QTextOption.ShowLineAndParagraphSeparators)
|
options.setFlags(options.flags() | QTextOption.Flag.ShowLineAndParagraphSeparators)
|
||||||
|
|
||||||
self._qDocument.setDefaultTextOption(options)
|
self._qDocument.setDefaultTextOption(options)
|
||||||
|
|
||||||
# Scrolling
|
# Scrolling
|
||||||
self.setCenterOnScroll(CONFIG.scrollPastEnd)
|
self.setCenterOnScroll(CONFIG.scrollPastEnd)
|
||||||
if CONFIG.hideVScroll:
|
if CONFIG.hideVScroll:
|
||||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
else:
|
else:
|
||||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
|
|
||||||
if CONFIG.hideHScroll:
|
if CONFIG.hideHScroll:
|
||||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
else:
|
else:
|
||||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
|
|
||||||
# Refresh the tab stops
|
# Refresh the tab stops
|
||||||
self.setTabStopDistance(CONFIG.getTabWidth())
|
self.setTabStopDistance(CONFIG.getTabWidth())
|
||||||
@@ -370,7 +372,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def loadText(self, tHandle, tLine=None) -> bool:
|
def loadText(self, tHandle: str, tLine=None) -> bool:
|
||||||
"""Load text from a document into the editor. If we have an I/O
|
"""Load text from a document into the editor. If we have an I/O
|
||||||
error, we must handle this and clear the editor so that we don't
|
error, we must handle this and clear the editor so that we don't
|
||||||
risk overwriting the file if it exists. This can for instance
|
risk overwriting the file if it exists. This can for instance
|
||||||
@@ -388,7 +390,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
self.clearEditor()
|
self.clearEditor()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
||||||
self._docHandle = tHandle
|
self._docHandle = tHandle
|
||||||
|
|
||||||
self._allowAutoReplace(False)
|
self._allowAutoReplace(False)
|
||||||
@@ -441,7 +443,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
"""Replace the text of the current document with the provided
|
"""Replace the text of the current document with the provided
|
||||||
text. This also clears undo history.
|
text. This also clears undo history.
|
||||||
"""
|
"""
|
||||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
||||||
self.setPlainText(text)
|
self.setPlainText(text)
|
||||||
self.updateDocMargins()
|
self.updateDocMargins()
|
||||||
self.setDocumentChanged(True)
|
self.setDocumentChanged(True)
|
||||||
@@ -676,7 +678,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
"""
|
"""
|
||||||
logger.debug("Running spell checker")
|
logger.debug("Running spell checker")
|
||||||
start = time()
|
start = time()
|
||||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
||||||
self._qDocument.syntaxHighlighter.rehighlight()
|
self._qDocument.syntaxHighlighter.rehighlight()
|
||||||
qApp.restoreOverrideCursor()
|
qApp.restoreOverrideCursor()
|
||||||
logger.debug("Document highlighted in %.3f ms", 1000*(time() - start))
|
logger.debug("Document highlighted in %.3f ms", 1000*(time() - start))
|
||||||
@@ -726,9 +728,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
elif action == nwDocAction.D_QUOTE:
|
elif action == nwDocAction.D_QUOTE:
|
||||||
self._wrapSelection(self._typDQuoteO, self._typDQuoteC)
|
self._wrapSelection(self._typDQuoteO, self._typDQuoteC)
|
||||||
elif action == nwDocAction.SEL_ALL:
|
elif action == nwDocAction.SEL_ALL:
|
||||||
self._makeSelection(QTextCursor.Document)
|
self._makeSelection(QTextCursor.SelectionType.Document)
|
||||||
elif action == nwDocAction.SEL_PARA:
|
elif action == nwDocAction.SEL_PARA:
|
||||||
self._makeSelection(QTextCursor.BlockUnderCursor)
|
self._makeSelection(QTextCursor.SelectionType.BlockUnderCursor)
|
||||||
elif action == nwDocAction.BLOCK_H1:
|
elif action == nwDocAction.BLOCK_H1:
|
||||||
self._formatBlock(nwDocAction.BLOCK_H1)
|
self._formatBlock(nwDocAction.BLOCK_H1)
|
||||||
elif action == nwDocAction.BLOCK_H2:
|
elif action == nwDocAction.BLOCK_H2:
|
||||||
@@ -909,17 +911,17 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
* We also handle automatic scrolling here.
|
* We also handle automatic scrolling here.
|
||||||
"""
|
"""
|
||||||
self._lastActive = time()
|
self._lastActive = time()
|
||||||
isReturn = event.key() == Qt.Key_Return
|
isReturn = event.key() == Qt.Key.Key_Return
|
||||||
isReturn |= event.key() == Qt.Key_Enter
|
isReturn |= event.key() == Qt.Key.Key_Enter
|
||||||
if isReturn and self.docSearch.anyFocus():
|
if isReturn and self.docSearch.anyFocus():
|
||||||
return
|
return
|
||||||
elif event == QKeySequence.Redo:
|
elif event == QKeySequence.StandardKey.Redo:
|
||||||
self.docAction(nwDocAction.REDO)
|
self.docAction(nwDocAction.REDO)
|
||||||
return
|
return
|
||||||
elif event == QKeySequence.Undo:
|
elif event == QKeySequence.StandardKey.Undo:
|
||||||
self.docAction(nwDocAction.UNDO)
|
self.docAction(nwDocAction.UNDO)
|
||||||
return
|
return
|
||||||
elif event == QKeySequence.SelectAll:
|
elif event == QKeySequence.StandardKey.SelectAll:
|
||||||
self.docAction(nwDocAction.SEL_ALL)
|
self.docAction(nwDocAction.SEL_ALL)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -928,7 +930,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
super().keyPressEvent(event)
|
super().keyPressEvent(event)
|
||||||
nPos = self.cursorRect().topLeft().y()
|
nPos = self.cursorRect().topLeft().y()
|
||||||
kMod = event.modifiers()
|
kMod = event.modifiers()
|
||||||
okMod = kMod == Qt.NoModifier or kMod == Qt.ShiftModifier
|
okMod = kMod in (Qt.KeyboardModifier.NoModifier, Qt.KeyboardModifier.ShiftModifier)
|
||||||
okKey = event.key() not in self.MOVE_KEYS
|
okKey = event.key() not in self.MOVE_KEYS
|
||||||
if nPos != cPos and okMod and okKey:
|
if nPos != cPos and okMod and okKey:
|
||||||
mPos = CONFIG.autoScrollPos*0.01 * self.viewport().height()
|
mPos = CONFIG.autoScrollPos*0.01 * self.viewport().height()
|
||||||
@@ -959,7 +961,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
pressed, check if we're clicking on a tag, and trigger the
|
pressed, check if we're clicking on a tag, and trigger the
|
||||||
follow tag function.
|
follow tag function.
|
||||||
"""
|
"""
|
||||||
if qApp.keyboardModifiers() == Qt.ControlModifier:
|
if qApp.keyboardModifiers() == Qt.KeyboardModifier.ControlModifier:
|
||||||
self._processTag(self.cursorForPosition(event.pos()))
|
self._processTag(self.cursorForPosition(event.pos()))
|
||||||
super().mouseReleaseEvent(event)
|
super().mouseReleaseEvent(event)
|
||||||
self.docFooter.updateLineCount()
|
self.docFooter.updateLineCount()
|
||||||
@@ -1065,43 +1067,50 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
|
|
||||||
@pyqtSlot("QPoint")
|
@pyqtSlot("QPoint")
|
||||||
def _openContextMenu(self, pos: QPoint) -> None:
|
def _openContextMenu(self, pos: QPoint) -> None:
|
||||||
"""Triggered by right click to open the context menu. Also
|
"""Open the editor context menu at a given coordinate."""
|
||||||
triggered by the Ctrl+. shortcut.
|
|
||||||
"""
|
|
||||||
uCursor = self.textCursor()
|
uCursor = self.textCursor()
|
||||||
pCursor = self.cursorForPosition(pos)
|
pCursor = self.cursorForPosition(pos)
|
||||||
|
pBlock = pCursor.block()
|
||||||
|
|
||||||
ctxMenu = QMenu(self)
|
ctxMenu = QMenu(self)
|
||||||
|
ctxMenu.setObjectName("ContextMenu")
|
||||||
|
if pBlock.userState() == GuiDocHighlighter.BLOCK_TITLE:
|
||||||
|
action = ctxMenu.addAction(self.tr("Set as Document Name"))
|
||||||
|
action.triggered.connect(lambda: self._emitRenameItem(pBlock))
|
||||||
|
|
||||||
# Follow
|
# Follow
|
||||||
status = self._processTag(cursor=pCursor, follow=False)
|
status = self._processTag(cursor=pCursor, follow=False)
|
||||||
if status == nwTrinary.POSITIVE:
|
if status == nwTrinary.POSITIVE:
|
||||||
aTag = ctxMenu.addAction(self.tr("Follow Tag"))
|
action = ctxMenu.addAction(self.tr("Follow Tag"))
|
||||||
aTag.triggered.connect(lambda: self._processTag(cursor=pCursor, follow=True))
|
action.triggered.connect(lambda: self._processTag(cursor=pCursor, follow=True))
|
||||||
ctxMenu.addSeparator()
|
ctxMenu.addSeparator()
|
||||||
elif status == nwTrinary.NEGATIVE:
|
elif status == nwTrinary.NEGATIVE:
|
||||||
aTag = ctxMenu.addAction(self.tr("Create Note for Tag"))
|
action = ctxMenu.addAction(self.tr("Create Note for Tag"))
|
||||||
aTag.triggered.connect(lambda: self._processTag(cursor=pCursor, create=True))
|
action.triggered.connect(lambda: self._processTag(cursor=pCursor, create=True))
|
||||||
ctxMenu.addSeparator()
|
ctxMenu.addSeparator()
|
||||||
|
|
||||||
# Cut, Copy and Paste
|
# Cut, Copy and Paste
|
||||||
if uCursor.hasSelection():
|
if uCursor.hasSelection():
|
||||||
aCut = ctxMenu.addAction(self.tr("Cut"))
|
action = ctxMenu.addAction(self.tr("Cut"))
|
||||||
aCut.triggered.connect(lambda: self.docAction(nwDocAction.CUT))
|
action.triggered.connect(lambda: self.docAction(nwDocAction.CUT))
|
||||||
aCopy = ctxMenu.addAction(self.tr("Copy"))
|
action = ctxMenu.addAction(self.tr("Copy"))
|
||||||
aCopy.triggered.connect(lambda: self.docAction(nwDocAction.COPY))
|
action.triggered.connect(lambda: self.docAction(nwDocAction.COPY))
|
||||||
|
|
||||||
aPaste = ctxMenu.addAction(self.tr("Paste"))
|
action = ctxMenu.addAction(self.tr("Paste"))
|
||||||
aPaste.triggered.connect(lambda: self.docAction(nwDocAction.PASTE))
|
action.triggered.connect(lambda: self.docAction(nwDocAction.PASTE))
|
||||||
ctxMenu.addSeparator()
|
ctxMenu.addSeparator()
|
||||||
|
|
||||||
# Selections
|
# Selections
|
||||||
aSAll = ctxMenu.addAction(self.tr("Select All"))
|
action = ctxMenu.addAction(self.tr("Select All"))
|
||||||
aSAll.triggered.connect(lambda: self.docAction(nwDocAction.SEL_ALL))
|
action.triggered.connect(lambda: self.docAction(nwDocAction.SEL_ALL))
|
||||||
aSWrd = ctxMenu.addAction(self.tr("Select Word"))
|
action = ctxMenu.addAction(self.tr("Select Word"))
|
||||||
aSWrd.triggered.connect(lambda: self._makePosSelection(QTextCursor.WordUnderCursor, pos))
|
action.triggered.connect(
|
||||||
aSPar = ctxMenu.addAction(self.tr("Select Paragraph"))
|
lambda: self._makePosSelection(QTextCursor.SelectionType.WordUnderCursor, pos)
|
||||||
aSPar.triggered.connect(lambda: self._makePosSelection(QTextCursor.BlockUnderCursor, pos))
|
)
|
||||||
|
action = ctxMenu.addAction(self.tr("Select Paragraph"))
|
||||||
|
action.triggered.connect(lambda: self._makePosSelection(
|
||||||
|
QTextCursor.SelectionType.BlockUnderCursor, pos)
|
||||||
|
)
|
||||||
|
|
||||||
# Spell Checking
|
# Spell Checking
|
||||||
if SHARED.project.data.spellCheck:
|
if SHARED.project.data.spellCheck:
|
||||||
@@ -1111,21 +1120,23 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
block = pCursor.block()
|
block = pCursor.block()
|
||||||
sCursor = self.textCursor()
|
sCursor = self.textCursor()
|
||||||
sCursor.setPosition(block.position() + cPos)
|
sCursor.setPosition(block.position() + cPos)
|
||||||
sCursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, cLen)
|
sCursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, cLen
|
||||||
|
)
|
||||||
if suggest:
|
if suggest:
|
||||||
ctxMenu.addSeparator()
|
ctxMenu.addSeparator()
|
||||||
ctxMenu.addAction(self.tr("Spelling Suggestion(s)"))
|
ctxMenu.addAction(self.tr("Spelling Suggestion(s)"))
|
||||||
for option in suggest[:15]:
|
for option in suggest[:15]:
|
||||||
aFix = ctxMenu.addAction(f"{nwUnicode.U_ENDASH} {option}")
|
action = ctxMenu.addAction(f"{nwUnicode.U_ENDASH} {option}")
|
||||||
aFix.triggered.connect(
|
action.triggered.connect(
|
||||||
lambda _, option=option: self._correctWord(sCursor, option)
|
lambda _, option=option: self._correctWord(sCursor, option)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ctxMenu.addAction("%s %s" % (nwUnicode.U_ENDASH, self.tr("No Suggestions")))
|
ctxMenu.addAction("%s %s" % (nwUnicode.U_ENDASH, self.tr("No Suggestions")))
|
||||||
|
|
||||||
ctxMenu.addSeparator()
|
ctxMenu.addSeparator()
|
||||||
aAdd = ctxMenu.addAction(self.tr("Add Word to Dictionary"))
|
action = ctxMenu.addAction(self.tr("Add Word to Dictionary"))
|
||||||
aAdd.triggered.connect(lambda: self._addWord(word, block))
|
action.triggered.connect(lambda: self._addWord(word, block))
|
||||||
|
|
||||||
# Execute the context menu
|
# Execute the context menu
|
||||||
ctxMenu.exec_(self.viewport().mapToGlobal(pos))
|
ctxMenu.exec_(self.viewport().mapToGlobal(pos))
|
||||||
@@ -1316,8 +1327,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
else:
|
else:
|
||||||
resIdx = 0 if doLoop else maxIdx
|
resIdx = 0 if doLoop else maxIdx
|
||||||
|
|
||||||
cursor.setPosition(resS[resIdx], QTextCursor.MoveAnchor)
|
cursor.setPosition(resS[resIdx], QTextCursor.MoveMode.MoveAnchor)
|
||||||
cursor.setPosition(resE[resIdx], QTextCursor.KeepAnchor)
|
cursor.setPosition(resE[resIdx], QTextCursor.MoveMode.KeepAnchor)
|
||||||
self.setTextCursor(cursor)
|
self.setTextCursor(cursor)
|
||||||
|
|
||||||
self.docFooter.updateLineCount()
|
self.docFooter.updateLineCount()
|
||||||
@@ -1343,9 +1354,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
|
|
||||||
findOpt = QTextDocument.FindFlag(0)
|
findOpt = QTextDocument.FindFlag(0)
|
||||||
if self.docSearch.isCaseSense:
|
if self.docSearch.isCaseSense:
|
||||||
findOpt |= QTextDocument.FindCaseSensitively
|
findOpt |= QTextDocument.FindFlag.FindCaseSensitively
|
||||||
if self.docSearch.isWholeWord:
|
if self.docSearch.isWholeWord:
|
||||||
findOpt |= QTextDocument.FindWholeWords
|
findOpt |= QTextDocument.FindFlag.FindWholeWords
|
||||||
|
|
||||||
searchFor = self.docSearch.getSearchObject()
|
searchFor = self.docSearch.getSearchObject()
|
||||||
cursor.setPosition(0)
|
cursor.setPosition(0)
|
||||||
@@ -1363,8 +1374,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if hasSelection:
|
if hasSelection:
|
||||||
cursor.setPosition(origA, QTextCursor.MoveAnchor)
|
cursor.setPosition(origA, QTextCursor.MoveMode.MoveAnchor)
|
||||||
cursor.setPosition(origB, QTextCursor.KeepAnchor)
|
cursor.setPosition(origB, QTextCursor.MoveMode.KeepAnchor)
|
||||||
else:
|
else:
|
||||||
cursor.setPosition(origA)
|
cursor.setPosition(origA)
|
||||||
|
|
||||||
@@ -1475,8 +1486,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
if blockS != blockE:
|
if blockS != blockE:
|
||||||
posE = blockS.position() + blockS.length() - 1
|
posE = blockS.position() + blockS.length() - 1
|
||||||
cursor.clearSelection()
|
cursor.clearSelection()
|
||||||
cursor.setPosition(posS, QTextCursor.MoveAnchor)
|
cursor.setPosition(posS, QTextCursor.MoveMode.MoveAnchor)
|
||||||
cursor.setPosition(posE, QTextCursor.KeepAnchor)
|
cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor)
|
||||||
self.setTextCursor(cursor)
|
self.setTextCursor(cursor)
|
||||||
|
|
||||||
numB = 0
|
numB = 0
|
||||||
@@ -1578,7 +1589,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
self._allowAutoReplace(False)
|
self._allowAutoReplace(False)
|
||||||
for posC in range(posS, posE+1):
|
for posC in range(posS, posE+1):
|
||||||
cursor.setPosition(posC)
|
cursor.setPosition(posC)
|
||||||
cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 2)
|
cursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 2
|
||||||
|
)
|
||||||
selText = cursor.selectedText()
|
selText = cursor.selectedText()
|
||||||
|
|
||||||
nS = len(selText)
|
nS = len(selText)
|
||||||
@@ -1598,12 +1611,16 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
cursor.setPosition(posC)
|
cursor.setPosition(posC)
|
||||||
if pC in closeCheck:
|
if pC in closeCheck:
|
||||||
cursor.beginEditBlock()
|
cursor.beginEditBlock()
|
||||||
cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 1)
|
cursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 1
|
||||||
|
)
|
||||||
cursor.insertText(oQuote)
|
cursor.insertText(oQuote)
|
||||||
cursor.endEditBlock()
|
cursor.endEditBlock()
|
||||||
else:
|
else:
|
||||||
cursor.beginEditBlock()
|
cursor.beginEditBlock()
|
||||||
cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 1)
|
cursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 1
|
||||||
|
)
|
||||||
cursor.insertText(cQuote)
|
cursor.insertText(cQuote)
|
||||||
cursor.endEditBlock()
|
cursor.endEditBlock()
|
||||||
|
|
||||||
@@ -1723,7 +1740,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
# Replace the block text
|
# Replace the block text
|
||||||
cursor.beginEditBlock()
|
cursor.beginEditBlock()
|
||||||
posO = cursor.position()
|
posO = cursor.position()
|
||||||
cursor.select(QTextCursor.BlockUnderCursor)
|
cursor.select(QTextCursor.SelectionType.BlockUnderCursor)
|
||||||
posS = cursor.selectionStart()
|
posS = cursor.selectionStart()
|
||||||
cursor.removeSelectedText()
|
cursor.removeSelectedText()
|
||||||
cursor.setPosition(posS)
|
cursor.setPosition(posS)
|
||||||
@@ -1783,7 +1800,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
cursor.beginEditBlock()
|
cursor.beginEditBlock()
|
||||||
cursor.clearSelection()
|
cursor.clearSelection()
|
||||||
cursor.setPosition(rS)
|
cursor.setPosition(rS)
|
||||||
cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, rE-rS)
|
cursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, rE-rS
|
||||||
|
)
|
||||||
cursor.insertText(cleanText.rstrip() + "\n")
|
cursor.insertText(cleanText.rstrip() + "\n")
|
||||||
cursor.endEditBlock()
|
cursor.endEditBlock()
|
||||||
|
|
||||||
@@ -1852,6 +1871,13 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
|
|
||||||
return nwTrinary.NEUTRAL
|
return nwTrinary.NEUTRAL
|
||||||
|
|
||||||
|
def _emitRenameItem(self, block: QTextBlock) -> None:
|
||||||
|
"""Emit a signal to request an item be renamed."""
|
||||||
|
if self._docHandle:
|
||||||
|
text = block.text().lstrip("#").lstrip("!").strip()
|
||||||
|
self.requestProjectItemRenamed.emit(self._docHandle, text)
|
||||||
|
return
|
||||||
|
|
||||||
def _openContextFromCursor(self) -> None:
|
def _openContextFromCursor(self) -> None:
|
||||||
"""Open the spell check context menu at the cursor."""
|
"""Open the spell check context menu at the cursor."""
|
||||||
self._openContextMenu(self.cursorRect().center())
|
self._openContextMenu(self.cursorRect().center())
|
||||||
@@ -1943,7 +1969,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
tInsert = tInsert + self._typPadChar
|
tInsert = tInsert + self._typPadChar
|
||||||
|
|
||||||
if nDelete > 0:
|
if nDelete > 0:
|
||||||
cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, nDelete)
|
cursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, nDelete
|
||||||
|
)
|
||||||
cursor.insertText(tInsert)
|
cursor.insertText(tInsert)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -1994,8 +2022,8 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
return cursor
|
return cursor
|
||||||
|
|
||||||
cursor.clearSelection()
|
cursor.clearSelection()
|
||||||
cursor.setPosition(sPos, QTextCursor.MoveAnchor)
|
cursor.setPosition(sPos, QTextCursor.MoveMode.MoveAnchor)
|
||||||
cursor.setPosition(ePos, QTextCursor.KeepAnchor)
|
cursor.setPosition(ePos, QTextCursor.MoveMode.KeepAnchor)
|
||||||
|
|
||||||
self.setTextCursor(cursor)
|
self.setTextCursor(cursor)
|
||||||
|
|
||||||
@@ -2007,18 +2035,18 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
cursor.clearSelection()
|
cursor.clearSelection()
|
||||||
cursor.select(mode)
|
cursor.select(mode)
|
||||||
|
|
||||||
if mode == QTextCursor.WordUnderCursor:
|
if mode == QTextCursor.SelectionType.WordUnderCursor:
|
||||||
cursor = self._autoSelect()
|
cursor = self._autoSelect()
|
||||||
|
|
||||||
elif mode == QTextCursor.BlockUnderCursor:
|
elif mode == QTextCursor.SelectionType.BlockUnderCursor:
|
||||||
# This selection mode also selects the preceding paragraph
|
# This selection mode also selects the preceding paragraph
|
||||||
# separator, which we want to avoid.
|
# separator, which we want to avoid.
|
||||||
posS = cursor.selectionStart()
|
posS = cursor.selectionStart()
|
||||||
posE = cursor.selectionEnd()
|
posE = cursor.selectionEnd()
|
||||||
selTxt = cursor.selectedText()
|
selTxt = cursor.selectedText()
|
||||||
if selTxt.startswith(nwUnicode.U_PSEP):
|
if selTxt.startswith(nwUnicode.U_PSEP):
|
||||||
cursor.setPosition(posS+1, QTextCursor.MoveAnchor)
|
cursor.setPosition(posS+1, QTextCursor.MoveMode.MoveAnchor)
|
||||||
cursor.setPosition(posE, QTextCursor.KeepAnchor)
|
cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor)
|
||||||
|
|
||||||
self.setTextCursor(cursor)
|
self.setTextCursor(cursor)
|
||||||
|
|
||||||
@@ -2100,7 +2128,10 @@ class MetaCompleter(QMenu):
|
|||||||
def keyPressEvent(self, event: QKeyEvent) -> None:
|
def keyPressEvent(self, event: QKeyEvent) -> None:
|
||||||
"""Capture keypresses and forward most of them to the editor."""
|
"""Capture keypresses and forward most of them to the editor."""
|
||||||
parent = self.parent()
|
parent = self.parent()
|
||||||
if event.key() in (Qt.Key_Up, Qt.Key_Down, Qt.Key_Return, Qt.Key_Enter, Qt.Key_Escape):
|
if event.key() in (
|
||||||
|
Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_Return,
|
||||||
|
Qt.Key.Key_Enter, Qt.Key.Key_Escape
|
||||||
|
):
|
||||||
super().keyPressEvent(event)
|
super().keyPressEvent(event)
|
||||||
elif isinstance(parent, GuiDocEditor):
|
elif isinstance(parent, GuiDocEditor):
|
||||||
parent.keyPressEvent(event)
|
parent.keyPressEvent(event)
|
||||||
@@ -2254,9 +2285,9 @@ class GuiDocToolBar(QWidget):
|
|||||||
def updateTheme(self) -> None:
|
def updateTheme(self) -> None:
|
||||||
"""Initialise GUI elements that depend on specific settings."""
|
"""Initialise GUI elements that depend on specific settings."""
|
||||||
palette = QPalette()
|
palette = QPalette()
|
||||||
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
||||||
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
||||||
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
self.setPalette(palette)
|
self.setPalette(palette)
|
||||||
|
|
||||||
tPx = int(0.8*SHARED.theme.fontPixelSize)
|
tPx = int(0.8*SHARED.theme.fontPixelSize)
|
||||||
@@ -2336,7 +2367,7 @@ class GuiDocEditSearch(QFrame):
|
|||||||
|
|
||||||
self.setContentsMargins(0, 0, 0, 0)
|
self.setContentsMargins(0, 0, 0, 0)
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
|
self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
|
||||||
|
|
||||||
self.mainBox = QGridLayout(self)
|
self.mainBox = QGridLayout(self)
|
||||||
self.setLayout(self.mainBox)
|
self.setLayout(self.mainBox)
|
||||||
@@ -2355,7 +2386,7 @@ class GuiDocEditSearch(QFrame):
|
|||||||
self.replaceBox.returnPressed.connect(self._doReplace)
|
self.replaceBox.returnPressed.connect(self._doReplace)
|
||||||
|
|
||||||
self.searchOpt = QToolBar(self)
|
self.searchOpt = QToolBar(self)
|
||||||
self.searchOpt.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.searchOpt.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.searchOpt.setIconSize(QSize(tPx, tPx))
|
self.searchOpt.setIconSize(QSize(tPx, tPx))
|
||||||
self.searchOpt.setContentsMargins(0, 0, 0, 0)
|
self.searchOpt.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
@@ -2417,7 +2448,7 @@ class GuiDocEditSearch(QFrame):
|
|||||||
bPx = self.searchBox.sizeHint().height()
|
bPx = self.searchBox.sizeHint().height()
|
||||||
|
|
||||||
self.showReplace = QToolButton(self)
|
self.showReplace = QToolButton(self)
|
||||||
self.showReplace.setArrowType(Qt.RightArrow)
|
self.showReplace.setArrowType(Qt.ArrowType.RightArrow)
|
||||||
self.showReplace.setCheckable(True)
|
self.showReplace.setCheckable(True)
|
||||||
self.showReplace.toggled.connect(self._doToggleReplace)
|
self.showReplace.toggled.connect(self._doToggleReplace)
|
||||||
|
|
||||||
@@ -2431,8 +2462,8 @@ class GuiDocEditSearch(QFrame):
|
|||||||
self.replaceButton.setToolTip(self.tr("Find and replace in current document"))
|
self.replaceButton.setToolTip(self.tr("Find and replace in current document"))
|
||||||
self.replaceButton.clicked.connect(self._doReplace)
|
self.replaceButton.clicked.connect(self._doReplace)
|
||||||
|
|
||||||
self.mainBox.addWidget(self.searchLabel, 0, 0, 1, 2, Qt.AlignLeft)
|
self.mainBox.addWidget(self.searchLabel, 0, 0, 1, 2, Qt.AlignmentFlag.AlignLeft)
|
||||||
self.mainBox.addWidget(self.searchOpt, 0, 2, 1, 3, Qt.AlignRight)
|
self.mainBox.addWidget(self.searchOpt, 0, 2, 1, 3, Qt.AlignmentFlag.AlignRight)
|
||||||
self.mainBox.addWidget(self.showReplace, 1, 0, 1, 1)
|
self.mainBox.addWidget(self.showReplace, 1, 0, 1, 1)
|
||||||
self.mainBox.addWidget(self.searchBox, 1, 1, 1, 2)
|
self.mainBox.addWidget(self.searchBox, 1, 1, 1, 2)
|
||||||
self.mainBox.addWidget(self.searchButton, 1, 3, 1, 1)
|
self.mainBox.addWidget(self.searchButton, 1, 3, 1, 1)
|
||||||
@@ -2490,18 +2521,18 @@ class GuiDocEditSearch(QFrame):
|
|||||||
# only added in Qt 5.13. Otherwise, 5.3 and up supports
|
# only added in Qt 5.13. Otherwise, 5.3 and up supports
|
||||||
# only the QRegExp class.
|
# only the QRegExp class.
|
||||||
if CONFIG.verQtValue >= 0x050d00:
|
if CONFIG.verQtValue >= 0x050d00:
|
||||||
rxOpt = QRegularExpression.UseUnicodePropertiesOption
|
rxOpt = QRegularExpression.PatternOption.UseUnicodePropertiesOption
|
||||||
if not self.isCaseSense:
|
if not self.isCaseSense:
|
||||||
rxOpt |= QRegularExpression.CaseInsensitiveOption
|
rxOpt |= QRegularExpression.PatternOption.CaseInsensitiveOption
|
||||||
regEx = QRegularExpression(text, rxOpt)
|
regEx = QRegularExpression(text, rxOpt)
|
||||||
self._alertSearchValid(regEx.isValid())
|
self._alertSearchValid(regEx.isValid())
|
||||||
return regEx
|
return regEx
|
||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
# >= 50300 to < 51300
|
# >= 50300 to < 51300
|
||||||
if self.isCaseSense:
|
if self.isCaseSense:
|
||||||
rxOpt = Qt.CaseSensitive
|
rxOpt = Qt.CaseSensitivity.CaseSensitive
|
||||||
else:
|
else:
|
||||||
rxOpt = Qt.CaseInsensitive
|
rxOpt = Qt.CaseSensitivity.CaseInsensitive
|
||||||
regEx = QRegExp(text, rxOpt)
|
regEx = QRegExp(text, rxOpt)
|
||||||
self._alertSearchValid(regEx.isValid())
|
self._alertSearchValid(regEx.isValid())
|
||||||
return regEx
|
return regEx
|
||||||
@@ -2637,7 +2668,7 @@ class GuiDocEditSearch(QFrame):
|
|||||||
def _doSearch(self) -> None:
|
def _doSearch(self) -> None:
|
||||||
"""Call the search action function for the document editor."""
|
"""Call the search action function for the document editor."""
|
||||||
modKey = qApp.keyboardModifiers()
|
modKey = qApp.keyboardModifiers()
|
||||||
if modKey == Qt.ShiftModifier:
|
if modKey == Qt.KeyboardModifier.ShiftModifier:
|
||||||
self.docEditor.findNext(goBack=True)
|
self.docEditor.findNext(goBack=True)
|
||||||
else:
|
else:
|
||||||
self.docEditor.findNext()
|
self.docEditor.findNext()
|
||||||
@@ -2653,9 +2684,9 @@ class GuiDocEditSearch(QFrame):
|
|||||||
def _doToggleReplace(self, state: bool) -> None:
|
def _doToggleReplace(self, state: bool) -> None:
|
||||||
"""Toggle the show/hide of the replace box."""
|
"""Toggle the show/hide of the replace box."""
|
||||||
if state:
|
if state:
|
||||||
self.showReplace.setArrowType(Qt.DownArrow)
|
self.showReplace.setArrowType(Qt.ArrowType.DownArrow)
|
||||||
else:
|
else:
|
||||||
self.showReplace.setArrowType(Qt.RightArrow)
|
self.showReplace.setArrowType(Qt.ArrowType.RightArrow)
|
||||||
self.replaceBox.setVisible(state)
|
self.replaceBox.setVisible(state)
|
||||||
self.replaceButton.setVisible(state)
|
self.replaceButton.setVisible(state)
|
||||||
self.repVisible = state
|
self.repVisible = state
|
||||||
@@ -2708,7 +2739,7 @@ class GuiDocEditSearch(QFrame):
|
|||||||
isn't valid. Take the colour from the replace box.
|
isn't valid. Take the colour from the replace box.
|
||||||
"""
|
"""
|
||||||
qPalette = self.replaceBox.palette()
|
qPalette = self.replaceBox.palette()
|
||||||
qPalette.setColor(QPalette.Base, self.rxCol[isValid])
|
qPalette.setColor(QPalette.ColorRole.Base, self.rxCol[isValid])
|
||||||
self.searchBox.setPalette(qPalette)
|
self.searchBox.setPalette(qPalette)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -2749,7 +2780,7 @@ class GuiDocEditHeader(QWidget):
|
|||||||
self.itemTitle.setMargin(0)
|
self.itemTitle.setMargin(0)
|
||||||
self.itemTitle.setContentsMargins(0, 0, 0, 0)
|
self.itemTitle.setContentsMargins(0, 0, 0, 0)
|
||||||
self.itemTitle.setAutoFillBackground(True)
|
self.itemTitle.setAutoFillBackground(True)
|
||||||
self.itemTitle.setAlignment(Qt.AlignHCenter | Qt.AlignTop)
|
self.itemTitle.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop)
|
||||||
self.itemTitle.setFixedHeight(fPx)
|
self.itemTitle.setFixedHeight(fPx)
|
||||||
|
|
||||||
lblFont = self.itemTitle.font()
|
lblFont = self.itemTitle.font()
|
||||||
@@ -2761,7 +2792,7 @@ class GuiDocEditHeader(QWidget):
|
|||||||
self.tbButton.setContentsMargins(0, 0, 0, 0)
|
self.tbButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.tbButton.setIconSize(iconSize)
|
self.tbButton.setIconSize(iconSize)
|
||||||
self.tbButton.setFixedSize(fPx, fPx)
|
self.tbButton.setFixedSize(fPx, fPx)
|
||||||
self.tbButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.tbButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.tbButton.setVisible(False)
|
self.tbButton.setVisible(False)
|
||||||
self.tbButton.setToolTip(self.tr("Toggle Tool Bar"))
|
self.tbButton.setToolTip(self.tr("Toggle Tool Bar"))
|
||||||
self.tbButton.clicked.connect(lambda: self.toggleToolBarRequest.emit())
|
self.tbButton.clicked.connect(lambda: self.toggleToolBarRequest.emit())
|
||||||
@@ -2770,7 +2801,7 @@ class GuiDocEditHeader(QWidget):
|
|||||||
self.searchButton.setContentsMargins(0, 0, 0, 0)
|
self.searchButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.searchButton.setIconSize(iconSize)
|
self.searchButton.setIconSize(iconSize)
|
||||||
self.searchButton.setFixedSize(fPx, fPx)
|
self.searchButton.setFixedSize(fPx, fPx)
|
||||||
self.searchButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.searchButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.searchButton.setVisible(False)
|
self.searchButton.setVisible(False)
|
||||||
self.searchButton.setToolTip(self.tr("Search"))
|
self.searchButton.setToolTip(self.tr("Search"))
|
||||||
self.searchButton.clicked.connect(self.docEditor.toggleSearch)
|
self.searchButton.clicked.connect(self.docEditor.toggleSearch)
|
||||||
@@ -2779,7 +2810,7 @@ class GuiDocEditHeader(QWidget):
|
|||||||
self.minmaxButton.setContentsMargins(0, 0, 0, 0)
|
self.minmaxButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.minmaxButton.setIconSize(iconSize)
|
self.minmaxButton.setIconSize(iconSize)
|
||||||
self.minmaxButton.setFixedSize(fPx, fPx)
|
self.minmaxButton.setFixedSize(fPx, fPx)
|
||||||
self.minmaxButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.minmaxButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.minmaxButton.setVisible(False)
|
self.minmaxButton.setVisible(False)
|
||||||
self.minmaxButton.setToolTip(self.tr("Toggle Focus Mode"))
|
self.minmaxButton.setToolTip(self.tr("Toggle Focus Mode"))
|
||||||
self.minmaxButton.clicked.connect(lambda: self.docEditor.toggleFocusModeRequest.emit())
|
self.minmaxButton.clicked.connect(lambda: self.docEditor.toggleFocusModeRequest.emit())
|
||||||
@@ -2788,7 +2819,7 @@ class GuiDocEditHeader(QWidget):
|
|||||||
self.closeButton.setContentsMargins(0, 0, 0, 0)
|
self.closeButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.closeButton.setIconSize(iconSize)
|
self.closeButton.setIconSize(iconSize)
|
||||||
self.closeButton.setFixedSize(fPx, fPx)
|
self.closeButton.setFixedSize(fPx, fPx)
|
||||||
self.closeButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.closeButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.closeButton.setVisible(False)
|
self.closeButton.setVisible(False)
|
||||||
self.closeButton.setToolTip(self.tr("Close"))
|
self.closeButton.setToolTip(self.tr("Close"))
|
||||||
self.closeButton.clicked.connect(self._closeDocument)
|
self.closeButton.clicked.connect(self._closeDocument)
|
||||||
@@ -2846,9 +2877,9 @@ class GuiDocEditHeader(QWidget):
|
|||||||
theme rather than the main GUI.
|
theme rather than the main GUI.
|
||||||
"""
|
"""
|
||||||
palette = QPalette()
|
palette = QPalette()
|
||||||
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
||||||
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
||||||
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
|
|
||||||
self.setPalette(palette)
|
self.setPalette(palette)
|
||||||
self.itemTitle.setPalette(palette)
|
self.itemTitle.setPalette(palette)
|
||||||
@@ -2924,7 +2955,8 @@ class GuiDocEditHeader(QWidget):
|
|||||||
"""Capture a click on the title and ensure that the item is
|
"""Capture a click on the title and ensure that the item is
|
||||||
selected in the project tree.
|
selected in the project tree.
|
||||||
"""
|
"""
|
||||||
self.mainGui.projView.setSelectedHandle(self._docHandle, doScroll=True)
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
|
self.docEditor.requestProjectItemSelected.emit(self._docHandle, True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# END Class GuiDocEditHeader
|
# END Class GuiDocEditHeader
|
||||||
@@ -2961,11 +2993,13 @@ class GuiDocEditFooter(QWidget):
|
|||||||
self.setContentsMargins(0, 0, 0, 0)
|
self.setContentsMargins(0, 0, 0, 0)
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
|
|
||||||
|
alLeftTop = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
self.statusIcon = QLabel("")
|
self.statusIcon = QLabel("")
|
||||||
self.statusIcon.setContentsMargins(0, 0, 0, 0)
|
self.statusIcon.setContentsMargins(0, 0, 0, 0)
|
||||||
self.statusIcon.setFixedHeight(self.sPx)
|
self.statusIcon.setFixedHeight(self.sPx)
|
||||||
self.statusIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.statusIcon.setAlignment(alLeftTop)
|
||||||
|
|
||||||
self.statusText = QLabel(self.tr("Status"))
|
self.statusText = QLabel(self.tr("Status"))
|
||||||
self.statusText.setIndent(0)
|
self.statusText.setIndent(0)
|
||||||
@@ -2973,14 +3007,14 @@ class GuiDocEditFooter(QWidget):
|
|||||||
self.statusText.setContentsMargins(0, 0, 0, 0)
|
self.statusText.setContentsMargins(0, 0, 0, 0)
|
||||||
self.statusText.setAutoFillBackground(True)
|
self.statusText.setAutoFillBackground(True)
|
||||||
self.statusText.setFixedHeight(fPx)
|
self.statusText.setFixedHeight(fPx)
|
||||||
self.statusText.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.statusText.setAlignment(alLeftTop)
|
||||||
self.statusText.setFont(lblFont)
|
self.statusText.setFont(lblFont)
|
||||||
|
|
||||||
# Lines
|
# Lines
|
||||||
self.linesIcon = QLabel("")
|
self.linesIcon = QLabel("")
|
||||||
self.linesIcon.setContentsMargins(0, 0, 0, 0)
|
self.linesIcon.setContentsMargins(0, 0, 0, 0)
|
||||||
self.linesIcon.setFixedHeight(self.sPx)
|
self.linesIcon.setFixedHeight(self.sPx)
|
||||||
self.linesIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.linesIcon.setAlignment(alLeftTop)
|
||||||
|
|
||||||
self.linesText = QLabel("")
|
self.linesText = QLabel("")
|
||||||
self.linesText.setIndent(0)
|
self.linesText.setIndent(0)
|
||||||
@@ -2988,14 +3022,14 @@ class GuiDocEditFooter(QWidget):
|
|||||||
self.linesText.setContentsMargins(0, 0, 0, 0)
|
self.linesText.setContentsMargins(0, 0, 0, 0)
|
||||||
self.linesText.setAutoFillBackground(True)
|
self.linesText.setAutoFillBackground(True)
|
||||||
self.linesText.setFixedHeight(fPx)
|
self.linesText.setFixedHeight(fPx)
|
||||||
self.linesText.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.linesText.setAlignment(alLeftTop)
|
||||||
self.linesText.setFont(lblFont)
|
self.linesText.setFont(lblFont)
|
||||||
|
|
||||||
# Words
|
# Words
|
||||||
self.wordsIcon = QLabel("")
|
self.wordsIcon = QLabel("")
|
||||||
self.wordsIcon.setContentsMargins(0, 0, 0, 0)
|
self.wordsIcon.setContentsMargins(0, 0, 0, 0)
|
||||||
self.wordsIcon.setFixedHeight(self.sPx)
|
self.wordsIcon.setFixedHeight(self.sPx)
|
||||||
self.wordsIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.wordsIcon.setAlignment(alLeftTop)
|
||||||
|
|
||||||
self.wordsText = QLabel("")
|
self.wordsText = QLabel("")
|
||||||
self.wordsText.setIndent(0)
|
self.wordsText.setIndent(0)
|
||||||
@@ -3003,7 +3037,7 @@ class GuiDocEditFooter(QWidget):
|
|||||||
self.wordsText.setContentsMargins(0, 0, 0, 0)
|
self.wordsText.setContentsMargins(0, 0, 0, 0)
|
||||||
self.wordsText.setAutoFillBackground(True)
|
self.wordsText.setAutoFillBackground(True)
|
||||||
self.wordsText.setFixedHeight(fPx)
|
self.wordsText.setFixedHeight(fPx)
|
||||||
self.wordsText.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.wordsText.setAlignment(alLeftTop)
|
||||||
self.wordsText.setFont(lblFont)
|
self.wordsText.setFont(lblFont)
|
||||||
|
|
||||||
# Assemble Layout
|
# Assemble Layout
|
||||||
@@ -3051,9 +3085,9 @@ class GuiDocEditFooter(QWidget):
|
|||||||
theme rather than the main GUI.
|
theme rather than the main GUI.
|
||||||
"""
|
"""
|
||||||
palette = QPalette()
|
palette = QPalette()
|
||||||
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
||||||
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
||||||
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
|
|
||||||
self.setPalette(palette)
|
self.setPalette(palette)
|
||||||
self.statusText.setPalette(palette)
|
self.statusText.setPalette(palette)
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ from PyQt5.QtGui import (
|
|||||||
QTextOption
|
QTextOption
|
||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAction, qApp, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser,
|
QAction, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser, QToolButton,
|
||||||
QToolButton, QWidget
|
QWidget, qApp
|
||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
@@ -59,6 +59,7 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
documentLoaded = pyqtSignal(str)
|
documentLoaded = pyqtSignal(str)
|
||||||
loadDocumentTagRequest = pyqtSignal(str, Enum)
|
loadDocumentTagRequest = pyqtSignal(str, Enum)
|
||||||
togglePanelVisibility = pyqtSignal()
|
togglePanelVisibility = pyqtSignal()
|
||||||
|
requestProjectItemSelected = pyqtSignal(str, bool)
|
||||||
|
|
||||||
def __init__(self, mainGui: GuiMain) -> None:
|
def __init__(self, mainGui: GuiMain) -> None:
|
||||||
super().__init__(parent=mainGui)
|
super().__init__(parent=mainGui)
|
||||||
@@ -75,8 +76,8 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
self.setMinimumWidth(CONFIG.pxInt(300))
|
self.setMinimumWidth(CONFIG.pxInt(300))
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
self.setOpenExternalLinks(False)
|
self.setOpenExternalLinks(False)
|
||||||
self.setFocusPolicy(Qt.StrongFocus)
|
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||||
self.setFrameStyle(QFrame.NoFrame)
|
self.setFrameStyle(QFrame.Shape.NoFrame)
|
||||||
|
|
||||||
# Document Header and Footer
|
# Document Header and Footer
|
||||||
self.docHeader = GuiDocViewHeader(self)
|
self.docHeader = GuiDocViewHeader(self)
|
||||||
@@ -92,7 +93,7 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
self.installEventFilter(self.wheelEventFilter)
|
self.installEventFilter(self.wheelEventFilter)
|
||||||
|
|
||||||
# Context Menu
|
# Context Menu
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||||
self.customContextMenuRequested.connect(self._openContextMenu)
|
self.customContextMenuRequested.connect(self._openContextMenu)
|
||||||
|
|
||||||
self.initViewer()
|
self.initViewer()
|
||||||
@@ -148,14 +149,14 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
|
|
||||||
# Set the widget colours to match syntax theme
|
# Set the widget colours to match syntax theme
|
||||||
mainPalette = self.palette()
|
mainPalette = self.palette()
|
||||||
mainPalette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
mainPalette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
||||||
mainPalette.setColor(QPalette.Base, QColor(*SHARED.theme.colBack))
|
mainPalette.setColor(QPalette.ColorRole.Base, QColor(*SHARED.theme.colBack))
|
||||||
mainPalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
mainPalette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
self.setPalette(mainPalette)
|
self.setPalette(mainPalette)
|
||||||
|
|
||||||
docPalette = self.viewport().palette()
|
docPalette = self.viewport().palette()
|
||||||
docPalette.setColor(QPalette.Base, QColor(*SHARED.theme.colBack))
|
docPalette.setColor(QPalette.ColorRole.Base, QColor(*SHARED.theme.colBack))
|
||||||
docPalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
docPalette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
self.viewport().setPalette(docPalette)
|
self.viewport().setPalette(docPalette)
|
||||||
|
|
||||||
self.docHeader.matchColours()
|
self.docHeader.matchColours()
|
||||||
@@ -165,19 +166,19 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
self.document().setDocumentMargin(0)
|
self.document().setDocumentMargin(0)
|
||||||
theOpt = QTextOption()
|
theOpt = QTextOption()
|
||||||
if CONFIG.doJustify:
|
if CONFIG.doJustify:
|
||||||
theOpt.setAlignment(Qt.AlignJustify)
|
theOpt.setAlignment(Qt.AlignmentFlag.AlignJustify)
|
||||||
self.document().setDefaultTextOption(theOpt)
|
self.document().setDefaultTextOption(theOpt)
|
||||||
|
|
||||||
# Scroll bars
|
# Scroll bars
|
||||||
if CONFIG.hideVScroll:
|
if CONFIG.hideVScroll:
|
||||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
else:
|
else:
|
||||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
|
|
||||||
if CONFIG.hideHScroll:
|
if CONFIG.hideHScroll:
|
||||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
else:
|
else:
|
||||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
|
|
||||||
# Refresh the tab stops
|
# Refresh the tab stops
|
||||||
self.setTabStopDistance(CONFIG.getTabWidth())
|
self.setTabStopDistance(CONFIG.getTabWidth())
|
||||||
@@ -196,7 +197,7 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
logger.debug("Generating preview for item '%s'", tHandle)
|
logger.debug("Generating preview for item '%s'", tHandle)
|
||||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
||||||
|
|
||||||
sPos = self.verticalScrollBar().value()
|
sPos = self.verticalScrollBar().value()
|
||||||
aDoc = ToHtml(SHARED.project)
|
aDoc = ToHtml(SHARED.project)
|
||||||
@@ -272,9 +273,9 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
elif action == nwDocAction.COPY:
|
elif action == nwDocAction.COPY:
|
||||||
self.copy()
|
self.copy()
|
||||||
elif action == nwDocAction.SEL_ALL:
|
elif action == nwDocAction.SEL_ALL:
|
||||||
self._makeSelection(QTextCursor.Document)
|
self._makeSelection(QTextCursor.SelectionType.Document)
|
||||||
elif action == nwDocAction.SEL_PARA:
|
elif action == nwDocAction.SEL_PARA:
|
||||||
self._makeSelection(QTextCursor.BlockUnderCursor)
|
self._makeSelection(QTextCursor.SelectionType.BlockUnderCursor)
|
||||||
else:
|
else:
|
||||||
logger.debug("Unknown or unsupported document action '%s'", str(action))
|
logger.debug("Unknown or unsupported document action '%s'", str(action))
|
||||||
return False
|
return False
|
||||||
@@ -392,13 +393,13 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
|
|
||||||
mnuSelWord = QAction(self.tr("Select Word"), mnuContext)
|
mnuSelWord = QAction(self.tr("Select Word"), mnuContext)
|
||||||
mnuSelWord.triggered.connect(
|
mnuSelWord.triggered.connect(
|
||||||
lambda: self._makePosSelection(QTextCursor.WordUnderCursor, point)
|
lambda: self._makePosSelection(QTextCursor.SelectionType.WordUnderCursor, point)
|
||||||
)
|
)
|
||||||
mnuContext.addAction(mnuSelWord)
|
mnuContext.addAction(mnuSelWord)
|
||||||
|
|
||||||
mnuSelPara = QAction(self.tr("Select Paragraph"), mnuContext)
|
mnuSelPara = QAction(self.tr("Select Paragraph"), mnuContext)
|
||||||
mnuSelPara.triggered.connect(
|
mnuSelPara.triggered.connect(
|
||||||
lambda: self._makePosSelection(QTextCursor.BlockUnderCursor, point)
|
lambda: self._makePosSelection(QTextCursor.SelectionType.BlockUnderCursor, point)
|
||||||
)
|
)
|
||||||
mnuContext.addAction(mnuSelPara)
|
mnuContext.addAction(mnuSelPara)
|
||||||
|
|
||||||
@@ -419,9 +420,9 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
|
|
||||||
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
||||||
"""Capture mouse click events on the document."""
|
"""Capture mouse click events on the document."""
|
||||||
if event.button() == Qt.BackButton:
|
if event.button() == Qt.MouseButton.BackButton:
|
||||||
self.navBackward()
|
self.navBackward()
|
||||||
elif event.button() == Qt.ForwardButton:
|
elif event.button() == Qt.MouseButton.ForwardButton:
|
||||||
self.navForward()
|
self.navForward()
|
||||||
else:
|
else:
|
||||||
super().mouseReleaseEvent(event)
|
super().mouseReleaseEvent(event)
|
||||||
@@ -437,15 +438,15 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
cursor.clearSelection()
|
cursor.clearSelection()
|
||||||
cursor.select(selType)
|
cursor.select(selType)
|
||||||
|
|
||||||
if selType == QTextCursor.BlockUnderCursor:
|
if selType == QTextCursor.SelectionType.BlockUnderCursor:
|
||||||
# This selection mode also selects the preceding paragraph
|
# This selection mode also selects the preceding paragraph
|
||||||
# separator, which we want to avoid.
|
# separator, which we want to avoid.
|
||||||
posS = cursor.selectionStart()
|
posS = cursor.selectionStart()
|
||||||
posE = cursor.selectionEnd()
|
posE = cursor.selectionEnd()
|
||||||
selTxt = cursor.selectedText()
|
selTxt = cursor.selectedText()
|
||||||
if selTxt.startswith(nwUnicode.U_PSEP):
|
if selTxt.startswith(nwUnicode.U_PSEP):
|
||||||
cursor.setPosition(posS+1, QTextCursor.MoveAnchor)
|
cursor.setPosition(posS+1, QTextCursor.MoveMode.MoveAnchor)
|
||||||
cursor.setPosition(posE, QTextCursor.KeepAnchor)
|
cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor)
|
||||||
|
|
||||||
self.setTextCursor(cursor)
|
self.setTextCursor(cursor)
|
||||||
|
|
||||||
@@ -663,7 +664,7 @@ class GuiDocViewHeader(QWidget):
|
|||||||
self.docTitle.setMargin(0)
|
self.docTitle.setMargin(0)
|
||||||
self.docTitle.setContentsMargins(0, 0, 0, 0)
|
self.docTitle.setContentsMargins(0, 0, 0, 0)
|
||||||
self.docTitle.setAutoFillBackground(True)
|
self.docTitle.setAutoFillBackground(True)
|
||||||
self.docTitle.setAlignment(Qt.AlignHCenter | Qt.AlignTop)
|
self.docTitle.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop)
|
||||||
self.docTitle.setFixedHeight(fPx)
|
self.docTitle.setFixedHeight(fPx)
|
||||||
|
|
||||||
lblFont = self.docTitle.font()
|
lblFont = self.docTitle.font()
|
||||||
@@ -675,7 +676,7 @@ class GuiDocViewHeader(QWidget):
|
|||||||
self.backButton.setContentsMargins(0, 0, 0, 0)
|
self.backButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.backButton.setIconSize(QSize(fPx, fPx))
|
self.backButton.setIconSize(QSize(fPx, fPx))
|
||||||
self.backButton.setFixedSize(fPx, fPx)
|
self.backButton.setFixedSize(fPx, fPx)
|
||||||
self.backButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.backButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.backButton.setVisible(False)
|
self.backButton.setVisible(False)
|
||||||
self.backButton.setToolTip(self.tr("Go Backward"))
|
self.backButton.setToolTip(self.tr("Go Backward"))
|
||||||
self.backButton.clicked.connect(self.docViewer.navBackward)
|
self.backButton.clicked.connect(self.docViewer.navBackward)
|
||||||
@@ -684,7 +685,7 @@ class GuiDocViewHeader(QWidget):
|
|||||||
self.forwardButton.setContentsMargins(0, 0, 0, 0)
|
self.forwardButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.forwardButton.setIconSize(QSize(fPx, fPx))
|
self.forwardButton.setIconSize(QSize(fPx, fPx))
|
||||||
self.forwardButton.setFixedSize(fPx, fPx)
|
self.forwardButton.setFixedSize(fPx, fPx)
|
||||||
self.forwardButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.forwardButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.forwardButton.setVisible(False)
|
self.forwardButton.setVisible(False)
|
||||||
self.forwardButton.setToolTip(self.tr("Go Forward"))
|
self.forwardButton.setToolTip(self.tr("Go Forward"))
|
||||||
self.forwardButton.clicked.connect(self.docViewer.navForward)
|
self.forwardButton.clicked.connect(self.docViewer.navForward)
|
||||||
@@ -693,7 +694,7 @@ class GuiDocViewHeader(QWidget):
|
|||||||
self.refreshButton.setContentsMargins(0, 0, 0, 0)
|
self.refreshButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.refreshButton.setIconSize(QSize(fPx, fPx))
|
self.refreshButton.setIconSize(QSize(fPx, fPx))
|
||||||
self.refreshButton.setFixedSize(fPx, fPx)
|
self.refreshButton.setFixedSize(fPx, fPx)
|
||||||
self.refreshButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.refreshButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.refreshButton.setVisible(False)
|
self.refreshButton.setVisible(False)
|
||||||
self.refreshButton.setToolTip(self.tr("Reload"))
|
self.refreshButton.setToolTip(self.tr("Reload"))
|
||||||
self.refreshButton.clicked.connect(self._refreshDocument)
|
self.refreshButton.clicked.connect(self._refreshDocument)
|
||||||
@@ -702,7 +703,7 @@ class GuiDocViewHeader(QWidget):
|
|||||||
self.closeButton.setContentsMargins(0, 0, 0, 0)
|
self.closeButton.setContentsMargins(0, 0, 0, 0)
|
||||||
self.closeButton.setIconSize(QSize(fPx, fPx))
|
self.closeButton.setIconSize(QSize(fPx, fPx))
|
||||||
self.closeButton.setFixedSize(fPx, fPx)
|
self.closeButton.setFixedSize(fPx, fPx)
|
||||||
self.closeButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.closeButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.closeButton.setVisible(False)
|
self.closeButton.setVisible(False)
|
||||||
self.closeButton.setToolTip(self.tr("Close"))
|
self.closeButton.setToolTip(self.tr("Close"))
|
||||||
self.closeButton.clicked.connect(self._closeDocument)
|
self.closeButton.clicked.connect(self._closeDocument)
|
||||||
@@ -761,9 +762,9 @@ class GuiDocViewHeader(QWidget):
|
|||||||
theme rather than the main GUI.
|
theme rather than the main GUI.
|
||||||
"""
|
"""
|
||||||
palette = QPalette()
|
palette = QPalette()
|
||||||
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
||||||
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
||||||
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
self.setPalette(palette)
|
self.setPalette(palette)
|
||||||
self.docTitle.setPalette(palette)
|
self.docTitle.setPalette(palette)
|
||||||
return
|
return
|
||||||
@@ -834,7 +835,8 @@ class GuiDocViewHeader(QWidget):
|
|||||||
"""Capture a click on the title and ensure that the item is
|
"""Capture a click on the title and ensure that the item is
|
||||||
selected in the project tree.
|
selected in the project tree.
|
||||||
"""
|
"""
|
||||||
self.mainGui.projView.setSelectedHandle(self._docHandle, doScroll=True)
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
|
self.docViewer.requestProjectItemSelected.emit(self._docHandle, True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# END Class GuiDocViewHeader
|
# END Class GuiDocViewHeader
|
||||||
@@ -868,7 +870,7 @@ class GuiDocViewFooter(QWidget):
|
|||||||
|
|
||||||
# Show/Hide Details
|
# Show/Hide Details
|
||||||
self.showHide = QToolButton(self)
|
self.showHide = QToolButton(self)
|
||||||
self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.showHide.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.showHide.setIconSize(QSize(fPx, fPx))
|
self.showHide.setIconSize(QSize(fPx, fPx))
|
||||||
self.showHide.setFixedSize(QSize(fPx, fPx))
|
self.showHide.setFixedSize(QSize(fPx, fPx))
|
||||||
self.showHide.clicked.connect(lambda: self.docViewer.togglePanelVisibility.emit())
|
self.showHide.clicked.connect(lambda: self.docViewer.togglePanelVisibility.emit())
|
||||||
@@ -878,7 +880,7 @@ class GuiDocViewFooter(QWidget):
|
|||||||
self.showComments = QToolButton(self)
|
self.showComments = QToolButton(self)
|
||||||
self.showComments.setCheckable(True)
|
self.showComments.setCheckable(True)
|
||||||
self.showComments.setChecked(CONFIG.viewComments)
|
self.showComments.setChecked(CONFIG.viewComments)
|
||||||
self.showComments.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.showComments.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.showComments.setIconSize(QSize(fPx, fPx))
|
self.showComments.setIconSize(QSize(fPx, fPx))
|
||||||
self.showComments.setFixedSize(QSize(fPx, fPx))
|
self.showComments.setFixedSize(QSize(fPx, fPx))
|
||||||
self.showComments.toggled.connect(self._doToggleComments)
|
self.showComments.toggled.connect(self._doToggleComments)
|
||||||
@@ -888,7 +890,7 @@ class GuiDocViewFooter(QWidget):
|
|||||||
self.showSynopsis = QToolButton(self)
|
self.showSynopsis = QToolButton(self)
|
||||||
self.showSynopsis.setCheckable(True)
|
self.showSynopsis.setCheckable(True)
|
||||||
self.showSynopsis.setChecked(CONFIG.viewSynopsis)
|
self.showSynopsis.setChecked(CONFIG.viewSynopsis)
|
||||||
self.showSynopsis.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
self.showSynopsis.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
||||||
self.showSynopsis.setIconSize(QSize(fPx, fPx))
|
self.showSynopsis.setIconSize(QSize(fPx, fPx))
|
||||||
self.showSynopsis.setFixedSize(QSize(fPx, fPx))
|
self.showSynopsis.setFixedSize(QSize(fPx, fPx))
|
||||||
self.showSynopsis.toggled.connect(self._doToggleSynopsis)
|
self.showSynopsis.toggled.connect(self._doToggleSynopsis)
|
||||||
@@ -902,7 +904,7 @@ class GuiDocViewFooter(QWidget):
|
|||||||
self.lblComments.setContentsMargins(0, 0, 0, 0)
|
self.lblComments.setContentsMargins(0, 0, 0, 0)
|
||||||
self.lblComments.setAutoFillBackground(True)
|
self.lblComments.setAutoFillBackground(True)
|
||||||
self.lblComments.setFixedHeight(fPx)
|
self.lblComments.setFixedHeight(fPx)
|
||||||
self.lblComments.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.lblComments.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
|
||||||
|
|
||||||
self.lblSynopsis = QLabel(self.tr("Synopsis"))
|
self.lblSynopsis = QLabel(self.tr("Synopsis"))
|
||||||
self.lblSynopsis.setBuddy(self.showSynopsis)
|
self.lblSynopsis.setBuddy(self.showSynopsis)
|
||||||
@@ -911,7 +913,7 @@ class GuiDocViewFooter(QWidget):
|
|||||||
self.lblSynopsis.setContentsMargins(0, 0, 0, 0)
|
self.lblSynopsis.setContentsMargins(0, 0, 0, 0)
|
||||||
self.lblSynopsis.setAutoFillBackground(True)
|
self.lblSynopsis.setAutoFillBackground(True)
|
||||||
self.lblSynopsis.setFixedHeight(fPx)
|
self.lblSynopsis.setFixedHeight(fPx)
|
||||||
self.lblSynopsis.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
self.lblSynopsis.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
|
||||||
|
|
||||||
lblFont = self.font()
|
lblFont = self.font()
|
||||||
lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
|
lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
|
||||||
@@ -977,9 +979,9 @@ class GuiDocViewFooter(QWidget):
|
|||||||
theme rather than the main GUI.
|
theme rather than the main GUI.
|
||||||
"""
|
"""
|
||||||
palette = QPalette()
|
palette = QPalette()
|
||||||
palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack))
|
palette.setColor(QPalette.ColorRole.Window, QColor(*SHARED.theme.colBack))
|
||||||
palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
|
||||||
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
|
palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
|
||||||
self.setPalette(palette)
|
self.setPalette(palette)
|
||||||
self.lblComments.setPalette(palette)
|
self.lblComments.setPalette(palette)
|
||||||
self.lblSynopsis.setPalette(palette)
|
self.lblSynopsis.setPalette(palette)
|
||||||
|
|||||||
+22
-17
@@ -138,7 +138,6 @@ class GuiProjectView(QWidget):
|
|||||||
self.emptyTrash = self.projTree.emptyTrash
|
self.emptyTrash = self.projTree.emptyTrash
|
||||||
self.requestDeleteItem = self.projTree.requestDeleteItem
|
self.requestDeleteItem = self.projTree.requestDeleteItem
|
||||||
self.getSelectedHandle = self.projTree.getSelectedHandle
|
self.getSelectedHandle = self.projTree.getSelectedHandle
|
||||||
self.setSelectedHandle = self.projTree.setSelectedHandle
|
|
||||||
self.changedSince = self.projTree.changedSince
|
self.changedSince = self.projTree.changedSince
|
||||||
self.createNewNote = self.projTree.createNewNote
|
self.createNewNote = self.projTree.createNewNote
|
||||||
|
|
||||||
@@ -191,17 +190,26 @@ class GuiProjectView(QWidget):
|
|||||||
"""Check if the project tree has focus."""
|
"""Check if the project tree has focus."""
|
||||||
return self.projTree.hasFocus()
|
return self.projTree.hasFocus()
|
||||||
|
|
||||||
def renameTreeItem(self, tHandle: str | None = None) -> bool:
|
##
|
||||||
|
# Public Slots
|
||||||
|
##
|
||||||
|
|
||||||
|
@pyqtSlot(str, str)
|
||||||
|
def renameTreeItem(self, tHandle: str | None = None, name: str = "") -> None:
|
||||||
"""External request to rename an item or the currently selected
|
"""External request to rename an item or the currently selected
|
||||||
item. This is triggered by the global menu or keyboard shortcut.
|
item. This is triggered by the global menu or keyboard shortcut.
|
||||||
"""
|
"""
|
||||||
if tHandle is None:
|
if tHandle is None:
|
||||||
tHandle = self.projTree.getSelectedHandle()
|
tHandle = self.projTree.getSelectedHandle()
|
||||||
return self.projTree.renameTreeItem(tHandle) if tHandle else False
|
if tHandle:
|
||||||
|
self.projTree.renameTreeItem(tHandle, name=name)
|
||||||
|
return
|
||||||
|
|
||||||
##
|
@pyqtSlot(str, bool)
|
||||||
# Public Slots
|
def setSelectedHandle(self, tHandle: str, doScroll: bool = False) -> None:
|
||||||
##
|
"""Select an item and optionally scroll it into view."""
|
||||||
|
self.projTree.setSelectedHandle(tHandle, doScroll=doScroll)
|
||||||
|
return
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def updateItemValues(self, tHandle: str) -> None:
|
def updateItemValues(self, tHandle: str) -> None:
|
||||||
@@ -761,19 +769,16 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
self.setCurrentItem(tItem.child(0))
|
self.setCurrentItem(tItem.child(0))
|
||||||
return
|
return
|
||||||
|
|
||||||
def renameTreeItem(self, tHandle: str) -> bool:
|
def renameTreeItem(self, tHandle: str, name: str = "") -> None:
|
||||||
"""Open a dialog to edit the label of an item."""
|
"""Open a dialog to edit the label of an item."""
|
||||||
tItem = SHARED.project.tree[tHandle]
|
tItem = SHARED.project.tree[tHandle]
|
||||||
if tItem is None:
|
if tItem:
|
||||||
return False
|
newLabel, dlgOk = GuiEditLabel.getLabel(self, text=name or tItem.itemName)
|
||||||
|
if dlgOk:
|
||||||
newLabel, dlgOk = GuiEditLabel.getLabel(self, text=tItem.itemName)
|
tItem.setName(newLabel)
|
||||||
if dlgOk:
|
self.setTreeItemValues(tHandle)
|
||||||
tItem.setName(newLabel)
|
self._alertTreeChange(tHandle, flush=False)
|
||||||
self.setTreeItemValues(tHandle)
|
return
|
||||||
self._alertTreeChange(tHandle, flush=False)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def saveTreeOrder(self) -> None:
|
def saveTreeOrder(self) -> None:
|
||||||
"""Build a list of the items in the project tree and send them
|
"""Build a list of the items in the project tree and send them
|
||||||
|
|||||||
@@ -284,10 +284,13 @@ class GuiMain(QMainWindow):
|
|||||||
self.docEditor.spellCheckStateChanged.connect(self.mainMenu.setSpellCheckState)
|
self.docEditor.spellCheckStateChanged.connect(self.mainMenu.setSpellCheckState)
|
||||||
self.docEditor.closeDocumentRequest.connect(self.closeDocEditor)
|
self.docEditor.closeDocumentRequest.connect(self.closeDocEditor)
|
||||||
self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode)
|
self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode)
|
||||||
|
self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
||||||
|
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
|
||||||
|
|
||||||
self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
|
self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
|
||||||
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
|
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
|
||||||
self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility)
|
self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility)
|
||||||
|
self.docViewer.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
||||||
|
|
||||||
self.docViewerPanel.loadDocumentTagRequest.connect(self._followTag)
|
self.docViewerPanel.loadDocumentTagRequest.connect(self._followTag)
|
||||||
self.docViewerPanel.openDocumentRequest.connect(self._openDocument)
|
self.docViewerPanel.openDocumentRequest.connect(self._openDocument)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
from PyQt5.QtWidgets import QWidget
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from PyQt5.QtCore import QUrl
|
from PyQt5.QtCore import QUrl
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
@@ -28,6 +28,8 @@ from zipfile import ZipFile
|
|||||||
from mocked import causeOSError
|
from mocked import causeOSError
|
||||||
from tools import C, cmpFiles, buildTestProject, XML_IGNORE
|
from tools import C, cmpFiles, buildTestProject, XML_IGNORE
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.enum import nwItemClass
|
from novelwriter.enum import nwItemClass
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,12 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from PyQt5.QtCore import QEvent, QObject, QPoint, Qt
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PyQt5.QtGui import QKeyEvent, QWheelEvent
|
from PyQt5.QtGui import QKeyEvent, QWheelEvent
|
||||||
|
from PyQt5.QtCore import QEvent, QObject, QPoint, Qt
|
||||||
from PyQt5.QtWidgets import QWidget
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
|
||||||
from novelwriter.extensions.wheeleventfilter import WheelEventFilter
|
from novelwriter.extensions.wheeleventfilter import WheelEventFilter
|
||||||
|
|||||||
@@ -18,21 +18,23 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tools import C, buildTestProject
|
from tools import C, buildTestProject
|
||||||
from mocked import causeOSError
|
from mocked import causeOSError
|
||||||
|
|
||||||
from PyQt5.QtGui import QTextBlock, QTextCursor, QTextOption
|
from PyQt5.QtGui import QClipboard, QTextBlock, QTextCursor, QTextOption
|
||||||
from PyQt5.QtCore import QThreadPool, Qt
|
from PyQt5.QtCore import QThreadPool, Qt
|
||||||
from PyQt5.QtWidgets import QAction, qApp
|
from PyQt5.QtWidgets import QAction, QMenu, qApp
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.enum import nwDocAction, nwDocInsert, nwItemLayout, nwTrinary, nwWidget
|
from novelwriter.enum import nwDocAction, nwDocInsert, nwItemLayout, nwTrinary, nwWidget
|
||||||
from novelwriter.constants import nwKeyWords, nwUnicode
|
from novelwriter.constants import nwKeyWords, nwUnicode
|
||||||
from novelwriter.core.index import countWords
|
from novelwriter.core.index import countWords
|
||||||
from novelwriter.gui.doceditor import GuiDocEditor, GuiDocToolBar
|
from novelwriter.gui.doceditor import GuiDocEditor, GuiDocToolBar
|
||||||
|
from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||||
|
|
||||||
KEY_DELAY = 1
|
KEY_DELAY = 1
|
||||||
|
|
||||||
@@ -209,6 +211,148 @@ def testGuiEditor_MetaData(qtbot, nwGUI, projPath, mockRnd):
|
|||||||
# END Test testGuiEditor_MetaData
|
# END Test testGuiEditor_MetaData
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiEditor_ContextMenu(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
|
||||||
|
"""Test the editor context menu."""
|
||||||
|
monkeypatch.setattr(QMenu, "exec_", lambda *a: None)
|
||||||
|
|
||||||
|
buildTestProject(nwGUI, projPath)
|
||||||
|
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||||
|
docEditor = nwGUI.docEditor
|
||||||
|
sceneItem = SHARED.project.tree[C.hSceneDoc]
|
||||||
|
assert sceneItem is not None
|
||||||
|
|
||||||
|
def getMenuForPos(pos: int, select: bool = False) -> QMenu | None:
|
||||||
|
nonlocal docEditor
|
||||||
|
cursor = docEditor.textCursor()
|
||||||
|
cursor.setPosition(pos)
|
||||||
|
if select:
|
||||||
|
cursor.select(QTextCursor.SelectionType.WordUnderCursor)
|
||||||
|
docEditor.setTextCursor(cursor)
|
||||||
|
docEditor._openContextMenu(docEditor.cursorRect().center())
|
||||||
|
for obj in docEditor.children():
|
||||||
|
if isinstance(obj, QMenu) and obj.objectName() == "ContextMenu":
|
||||||
|
return obj
|
||||||
|
return None
|
||||||
|
|
||||||
|
docText = (
|
||||||
|
"### A Scene\n\n"
|
||||||
|
"@pov: Jane\n"
|
||||||
|
"Some text ..."
|
||||||
|
)
|
||||||
|
docEditor.setPlainText(docText)
|
||||||
|
assert docEditor.getText() == docText
|
||||||
|
|
||||||
|
# Rename Item from Heading
|
||||||
|
ctxMenu = getMenuForPos(1)
|
||||||
|
assert ctxMenu is not None
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Set as Document Name", "Paste",
|
||||||
|
"Select All", "Select Word", "Select Paragraph"
|
||||||
|
]
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(GuiEditLabel, "getLabel", lambda a, text: (text, True))
|
||||||
|
assert sceneItem.itemName == "New Scene"
|
||||||
|
ctxMenu.actions()[0].trigger()
|
||||||
|
assert sceneItem.itemName == "A Scene"
|
||||||
|
ctxMenu.setObjectName("")
|
||||||
|
ctxMenu.deleteLater()
|
||||||
|
|
||||||
|
# Create Character
|
||||||
|
ctxMenu = getMenuForPos(21)
|
||||||
|
assert ctxMenu is not None
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Create Note for Tag", "Paste",
|
||||||
|
"Select All", "Select Word", "Select Paragraph"
|
||||||
|
]
|
||||||
|
ctxMenu.actions()[0].trigger()
|
||||||
|
janeItem = SHARED.project.tree["0000000000010"]
|
||||||
|
assert janeItem is not None
|
||||||
|
assert janeItem.itemName == "Jane"
|
||||||
|
ctxMenu.setObjectName("")
|
||||||
|
ctxMenu.deleteLater()
|
||||||
|
|
||||||
|
# Follow Character Tag
|
||||||
|
ctxMenu = getMenuForPos(21)
|
||||||
|
assert ctxMenu is not None
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Follow Tag", "Paste",
|
||||||
|
"Select All", "Select Word", "Select Paragraph"
|
||||||
|
]
|
||||||
|
ctxMenu.actions()[0].trigger()
|
||||||
|
assert nwGUI.docViewer.docHandle == "0000000000010"
|
||||||
|
ctxMenu.setObjectName("")
|
||||||
|
ctxMenu.deleteLater()
|
||||||
|
|
||||||
|
# Select Word
|
||||||
|
ctxMenu = getMenuForPos(31)
|
||||||
|
assert ctxMenu is not None
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Paste", "Select All", "Select Word", "Select Paragraph"
|
||||||
|
]
|
||||||
|
ctxMenu.actions()[3].trigger()
|
||||||
|
assert docEditor.textCursor().selectedText() == "text"
|
||||||
|
ctxMenu.setObjectName("")
|
||||||
|
ctxMenu.deleteLater()
|
||||||
|
|
||||||
|
# Select Paragraph
|
||||||
|
ctxMenu = getMenuForPos(31)
|
||||||
|
assert ctxMenu is not None
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Paste", "Select All", "Select Word", "Select Paragraph"
|
||||||
|
]
|
||||||
|
ctxMenu.actions()[4].trigger()
|
||||||
|
assert docEditor.textCursor().selectedText() == "Some text ..."
|
||||||
|
ctxMenu.setObjectName("")
|
||||||
|
ctxMenu.deleteLater()
|
||||||
|
|
||||||
|
# Select All
|
||||||
|
ctxMenu = getMenuForPos(31)
|
||||||
|
assert ctxMenu is not None
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Paste", "Select All", "Select Word", "Select Paragraph"
|
||||||
|
]
|
||||||
|
ctxMenu.actions()[2].trigger()
|
||||||
|
assert docEditor.textCursor().selectedText() == docEditor.document().toRawText()
|
||||||
|
ctxMenu.setObjectName("")
|
||||||
|
ctxMenu.deleteLater()
|
||||||
|
|
||||||
|
# Copy Text
|
||||||
|
ctxMenu = getMenuForPos(31, True)
|
||||||
|
assert ctxMenu is not None
|
||||||
|
assert docEditor.textCursor().selectedText() == "text"
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Cut", "Copy", "Paste", "Select All", "Select Word", "Select Paragraph"
|
||||||
|
]
|
||||||
|
qApp.clipboard().clear()
|
||||||
|
ctxMenu.actions()[1].trigger()
|
||||||
|
assert qApp.clipboard().text(QClipboard.Mode.Clipboard) == "text"
|
||||||
|
|
||||||
|
# Cut Text
|
||||||
|
qApp.clipboard().clear()
|
||||||
|
ctxMenu.actions()[0].trigger()
|
||||||
|
assert qApp.clipboard().text(QClipboard.Mode.Clipboard) == "text"
|
||||||
|
assert "text" not in docEditor.getText()
|
||||||
|
|
||||||
|
# Paste Text
|
||||||
|
ctxMenu.actions()[2].trigger()
|
||||||
|
assert docEditor.getText() == docText
|
||||||
|
|
||||||
|
ctxMenu.setObjectName("")
|
||||||
|
ctxMenu.deleteLater()
|
||||||
|
|
||||||
|
# qtbot.stop()
|
||||||
|
|
||||||
|
# END Test testGuiEditor_ContextMenu
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||||
"""Test the document actions. This is not an extensive test of the
|
"""Test the document actions. This is not an extensive test of the
|
||||||
|
|||||||
@@ -18,13 +18,14 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mocked import causeException
|
from mocked import causeException
|
||||||
|
|
||||||
from PyQt5.QtGui import QTextCursor
|
from PyQt5.QtGui import QMouseEvent, QTextCursor
|
||||||
from PyQt5.QtCore import Qt, QUrl
|
from PyQt5.QtCore import QEvent, QPoint, Qt, QUrl
|
||||||
from PyQt5.QtWidgets import QMenu, qApp, QAction
|
from PyQt5.QtWidgets import QMenu, qApp, QAction
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
@@ -58,7 +59,10 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
|
|||||||
assert nwGUI.projView.projTree.getSelectedHandle() is None
|
assert nwGUI.projView.projTree.getSelectedHandle() is None
|
||||||
|
|
||||||
# Re-select via header click
|
# Re-select via header click
|
||||||
docViewer.docHeader.mousePressEvent(None) # type: ignore
|
button = Qt.MouseButton.LeftButton
|
||||||
|
modifier = Qt.KeyboardModifier.NoModifier
|
||||||
|
event = QMouseEvent(QEvent.MouseButtonPress, QPoint(), button, button, modifier)
|
||||||
|
docViewer.docHeader.mousePressEvent(event)
|
||||||
assert nwGUI.projView.projTree.getSelectedHandle() == "88243afbe5ed8"
|
assert nwGUI.projView.projTree.getSelectedHandle() == "88243afbe5ed8"
|
||||||
|
|
||||||
# Reload the text
|
# Reload the text
|
||||||
@@ -127,7 +131,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
|
|||||||
assert docViewer.docAction(nwDocAction.COPY) is False
|
assert docViewer.docAction(nwDocAction.COPY) is False
|
||||||
|
|
||||||
# Open again via menu
|
# Open again via menu
|
||||||
assert nwGUI.projView.setSelectedHandle("88243afbe5ed8")
|
assert nwGUI.projView.projTree.setSelectedHandle("88243afbe5ed8")
|
||||||
nwGUI.mainMenu.aViewDoc.activate(QAction.Trigger)
|
nwGUI.mainMenu.aViewDoc.activate(QAction.Trigger)
|
||||||
|
|
||||||
# Open context menu
|
# Open context menu
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,15 +18,16 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from tools import C, writeFile, buildTestProject
|
||||||
|
|
||||||
from PyQt5.QtGui import QTextCursor, QTextBlock
|
from PyQt5.QtGui import QTextCursor, QTextBlock
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox
|
from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox
|
||||||
|
|
||||||
from tools import C, writeFile, buildTestProject
|
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.enum import nwDocAction, nwDocInsert
|
from novelwriter.enum import nwDocAction, nwDocInsert
|
||||||
from novelwriter.constants import nwKeyWords, nwUnicode
|
from novelwriter.constants import nwKeyWords, nwUnicode
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -156,12 +156,9 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
|
|||||||
# Rename plot folder
|
# Rename plot folder
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("Stuff", True))
|
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("Stuff", True))
|
||||||
projTree.renameTreeItem(C.hPlotRoot) is True
|
projTree.renameTreeItem(C.hPlotRoot)
|
||||||
assert project.tree[C.hPlotRoot].itemName == "Stuff" # type: ignore
|
assert project.tree[C.hPlotRoot].itemName == "Stuff" # type: ignore
|
||||||
|
|
||||||
# Rename invalid folder
|
|
||||||
projTree.renameTreeItem("0000000000000") is False
|
|
||||||
|
|
||||||
# Other Checks
|
# Other Checks
|
||||||
# ============
|
# ============
|
||||||
|
|
||||||
@@ -1095,12 +1092,12 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd)
|
|||||||
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("FooBar", True))
|
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("FooBar", True))
|
||||||
projTree.clearSelection()
|
projTree.clearSelection()
|
||||||
assert SHARED.project.tree[C.hChapterDoc].itemName == "New Chapter" # type: ignore
|
assert SHARED.project.tree[C.hChapterDoc].itemName == "New Chapter" # type: ignore
|
||||||
assert projView.renameTreeItem(C.hChapterDoc) is True
|
projView.renameTreeItem(C.hChapterDoc)
|
||||||
assert SHARED.project.tree[C.hChapterDoc].itemName == "FooBar" # type: ignore
|
assert SHARED.project.tree[C.hChapterDoc].itemName == "FooBar" # type: ignore
|
||||||
|
|
||||||
projTree.setSelectedHandle(C.hSceneDoc)
|
projTree.setSelectedHandle(C.hSceneDoc)
|
||||||
assert SHARED.project.tree[C.hSceneDoc].itemName == "New Scene" # type: ignore
|
assert SHARED.project.tree[C.hSceneDoc].itemName == "New Scene" # type: ignore
|
||||||
assert projView.renameTreeItem() is True
|
projView.renameTreeItem()
|
||||||
assert SHARED.project.tree[C.hSceneDoc].itemName == "FooBar" # type: ignore
|
assert SHARED.project.tree[C.hSceneDoc].itemName == "FooBar" # type: ignore
|
||||||
|
|
||||||
# Check Crash Resistance
|
# Check Crash Resistance
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import enchant
|
import enchant
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from PyQt5.QtCore import QUrl
|
|
||||||
from PyQt5.QtGui import QDesktopServices
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -28,6 +27,8 @@ from pytestqt.qtbot import QtBot
|
|||||||
|
|
||||||
from tools import buildTestProject
|
from tools import buildTestProject
|
||||||
|
|
||||||
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
from PyQt5.QtCore import QUrl
|
||||||
from PyQt5.QtWidgets import QDialogButtonBox, QFileDialog, QListWidgetItem, QMessageBox
|
from PyQt5.QtWidgets import QDialogButtonBox, QFileDialog, QListWidgetItem, QMessageBox
|
||||||
|
|
||||||
from novelwriter.enum import nwBuildFmt
|
from novelwriter.enum import nwBuildFmt
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
Reference in New Issue
Block a user