Add a context menu entry to set item name from heading (#1614)

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