Update linting for main code
This commit is contained in:
+23
-134
@@ -29,7 +29,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import bisect
|
||||
@@ -98,7 +98,7 @@ class _TagAction(IntFlag):
|
||||
|
||||
|
||||
class GuiDocEditor(QPlainTextEdit):
|
||||
"""Gui Widget: Main Document Editor"""
|
||||
"""Gui Widget: Main Document Editor."""
|
||||
|
||||
__slots__ = (
|
||||
"_autoReplace", "_completer", "_doReplace", "_docChanged", "_docHandle", "_followTag1",
|
||||
@@ -236,8 +236,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
logger.debug("Ready: GuiDocEditor")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
@@ -290,15 +288,12 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
self.itemHandleChanged.emit("")
|
||||
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
self.docSearch.updateTheme()
|
||||
self.docHeader.updateTheme()
|
||||
self.docFooter.updateTheme()
|
||||
self.docToolBar.updateTheme()
|
||||
return
|
||||
|
||||
def updateSyntaxColors(self) -> None:
|
||||
"""Update the syntax highlighting theme."""
|
||||
@@ -323,8 +318,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self._selection.format.setBackground(self._lineColor)
|
||||
self._selection.format.setProperty(QTextFormat.Property.FullWidthSelection, True)
|
||||
|
||||
return
|
||||
|
||||
def initEditor(self) -> None:
|
||||
"""Initialise or re-initialise the editor with the user's
|
||||
settings. This function is both called when the editor is
|
||||
@@ -392,8 +385,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
else:
|
||||
self.clearEditor()
|
||||
|
||||
return
|
||||
|
||||
def loadText(self, tHandle: str, tLine: int | None = 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
|
||||
@@ -471,7 +462,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self.updateDocMargins()
|
||||
self.setDocumentChanged(True)
|
||||
QApplication.restoreOverrideCursor()
|
||||
return
|
||||
|
||||
def saveText(self) -> bool:
|
||||
"""Save the text currently in the editor to the NWDocument
|
||||
@@ -539,7 +529,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
vBar.setValue(vBar.value() + 1)
|
||||
count += 1
|
||||
QApplication.processEvents()
|
||||
return
|
||||
|
||||
def updateDocMargins(self) -> None:
|
||||
"""Automatically adjust the margins so the text is centred if
|
||||
@@ -580,8 +569,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
lM = max(self._vpMargin, fH)
|
||||
self.setViewportMargins(tM, uM, tM, lM)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Getters
|
||||
##
|
||||
@@ -591,20 +578,19 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
QTextDocument->toRawText instead of toPlainText. The former preserves
|
||||
non-breaking spaces, the latter does not. We still want to get rid of
|
||||
paragraph and line separators though.
|
||||
|
||||
See: https://doc.qt.io/qt-6/qtextdocument.html#toPlainText
|
||||
"""
|
||||
text = self._qDocument.toRawText()
|
||||
text = text.replace(nwUnicode.U_LSEP, "\n") # Line separators
|
||||
text = text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
|
||||
return text
|
||||
return text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
|
||||
|
||||
def getSelectedText(self) -> str:
|
||||
"""Get currently selected text."""
|
||||
if (cursor := self.textCursor()).hasSelection():
|
||||
text = cursor.selectedText()
|
||||
text = text.replace(nwUnicode.U_LSEP, "\n") # Line separators
|
||||
text = text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
|
||||
return text
|
||||
return text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
|
||||
return ""
|
||||
|
||||
def getCursorPosition(self) -> int:
|
||||
@@ -625,7 +611,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
logger.debug("Document changed status is '%s'", state)
|
||||
self._docChanged = state
|
||||
self.editedStatusChanged.emit(self._docChanged)
|
||||
return
|
||||
|
||||
def setCursorPosition(self, position: int) -> None:
|
||||
"""Move the cursor to a given position in the document."""
|
||||
@@ -634,14 +619,12 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
cursor.setPosition(minmax(position, 0, chars-1))
|
||||
self.setTextCursor(cursor)
|
||||
self.centerCursor()
|
||||
return
|
||||
|
||||
def saveCursorPosition(self) -> None:
|
||||
"""Save the cursor position to the current project item."""
|
||||
if self._nwItem is not None:
|
||||
cursPos = self.getCursorPosition()
|
||||
self._nwItem.setCursorPos(cursPos)
|
||||
return
|
||||
|
||||
def setCursorLine(self, line: int | None) -> None:
|
||||
"""Move the cursor to a given line in the document."""
|
||||
@@ -650,7 +633,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
if block:
|
||||
self.setCursorPosition(block.position())
|
||||
logger.debug("Cursor moved to line %d", line)
|
||||
return
|
||||
|
||||
def setCursorSelection(self, start: int, length: int) -> None:
|
||||
"""Make a text selection."""
|
||||
@@ -659,14 +641,15 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
cursor.setPosition(start, QtMoveAnchor)
|
||||
cursor.setPosition(start + length, QtKeepAnchor)
|
||||
self.setTextCursor(cursor)
|
||||
return
|
||||
|
||||
##
|
||||
# Spell Checking
|
||||
##
|
||||
|
||||
def toggleSpellCheck(self, state: bool | None) -> None:
|
||||
"""This is the main spell check setting function, and this one
|
||||
"""Toggle spell checking.
|
||||
|
||||
This is the main spell check setting function, and this one
|
||||
should call all other setSpellCheck functions in other classes.
|
||||
If the spell check state is not defined (None), then toggle the
|
||||
current status saved in this class.
|
||||
@@ -690,8 +673,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
logger.debug("Spell check is set to '%s'", str(state))
|
||||
|
||||
return
|
||||
|
||||
def spellCheckDocument(self) -> None:
|
||||
"""Rerun the highlighter to update spell checking status of the
|
||||
currently loaded text.
|
||||
@@ -703,7 +684,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
QApplication.restoreOverrideCursor()
|
||||
logger.debug("Document highlighted in %.3f ms", 1000*(time() - start))
|
||||
self.updateStatusMessage.emit(self.tr("Spell check complete"))
|
||||
return
|
||||
|
||||
##
|
||||
# General Class Methods
|
||||
@@ -832,7 +812,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
details=self.tr("File Location: {0}").format(self._nwDocument.fileLocation),
|
||||
log=False
|
||||
)
|
||||
return
|
||||
|
||||
def insertText(self, insert: str | nwDocInsert) -> None:
|
||||
"""Insert a specific type of text at the cursor position."""
|
||||
@@ -974,7 +953,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragEnterEvent(event)
|
||||
return
|
||||
|
||||
def dragMoveEvent(self, event: QDragMoveEvent) -> None:
|
||||
"""Overload drag move event to handle dragged items."""
|
||||
@@ -982,7 +960,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragMoveEvent(event)
|
||||
return
|
||||
|
||||
def dropEvent(self, event: QDropEvent) -> None:
|
||||
"""Overload drop event to handle dragged items."""
|
||||
@@ -992,7 +969,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self.openDocumentRequest.emit(handles[0], nwDocMode.EDIT, "", True)
|
||||
else:
|
||||
super().dropEvent(event)
|
||||
return
|
||||
|
||||
def focusNextPrevChild(self, _next: bool) -> bool:
|
||||
"""Capture the focus request from the tab key on the text
|
||||
@@ -1019,7 +995,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
else:
|
||||
self._processTag(cursor)
|
||||
super().mouseReleaseEvent(event)
|
||||
return
|
||||
|
||||
def resizeEvent(self, event: QResizeEvent) -> None:
|
||||
"""If the text editor is resized, we must make sure the document
|
||||
@@ -1027,7 +1002,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
"""
|
||||
self.updateDocMargins()
|
||||
super().resizeEvent(event)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -1035,14 +1009,13 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
@pyqtSlot(str, Enum)
|
||||
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
|
||||
"""Called when an item label is changed to check if the document
|
||||
title bar needs updating,
|
||||
"""Process project item change. Called when an item label is
|
||||
changed to check if the document title bar needs updating.
|
||||
"""
|
||||
if tHandle == self._docHandle and change == nwChange.UPDATE:
|
||||
self.docHeader.setHandle(tHandle)
|
||||
self.docFooter.updateInfo()
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def insertKeyWord(self, keyword: str) -> bool:
|
||||
@@ -1053,8 +1026,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
logger.error("Invalid keyword '%s'", keyword)
|
||||
return False
|
||||
logger.debug("Inserting keyword '%s'", keyword)
|
||||
state = self.insertNewBlock(f"{keyword}: ")
|
||||
return state
|
||||
return self.insertNewBlock(f"{keyword}: ")
|
||||
|
||||
@pyqtSlot()
|
||||
def toggleSearch(self) -> None:
|
||||
@@ -1063,14 +1035,12 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self.closeSearch()
|
||||
else:
|
||||
self.beginSearch()
|
||||
return
|
||||
|
||||
@pyqtSlot(list, list)
|
||||
def updateChangedTags(self, updated: list[str], deleted: list[str]) -> None:
|
||||
"""Tags have changed, so just in case we rehighlight them."""
|
||||
if updated or deleted:
|
||||
self._qDocument.syntaxHighlighter.rehighlightByType(BLOCK_META)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -1116,8 +1086,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
if self._autoReplace.process(text, cursor):
|
||||
self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _cursorMoved(self) -> None:
|
||||
"""Triggered when the cursor moved in the editor."""
|
||||
@@ -1126,7 +1094,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self._selection.cursor = self.textCursor()
|
||||
self._selection.cursor.clearSelection()
|
||||
self.setExtraSelections([self._selection])
|
||||
return
|
||||
|
||||
@pyqtSlot(int, int, str)
|
||||
def _insertCompletion(self, pos: int, length: int, text: str) -> None:
|
||||
@@ -1138,13 +1105,11 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
cursor.setPosition(check + length, QtKeepAnchor)
|
||||
cursor.insertText(text)
|
||||
self._completer.hide()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _openContextFromCursor(self) -> None:
|
||||
"""Open the spell check context menu at the cursor."""
|
||||
self._openContextMenu(self.cursorRect().center())
|
||||
return
|
||||
|
||||
@pyqtSlot("QPoint")
|
||||
def _openContextMenu(self, pos: QPoint) -> None:
|
||||
@@ -1231,8 +1196,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
ctxMenu.setParent(None)
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _runDocumentTasks(self) -> None:
|
||||
"""Run timer document tasks."""
|
||||
@@ -1269,11 +1232,10 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
if not self.textCursor().hasSelection():
|
||||
# Selection counter should take precedence (#2155)
|
||||
self.docFooter.updateMainCount(mCount, False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _updateSelectedStatus(self) -> None:
|
||||
"""The user made a change in text selection. Forward this
|
||||
"""Process user change in text selection. Forward this
|
||||
information to the footer, and start the selection word counter.
|
||||
"""
|
||||
if self.textCursor().hasSelection():
|
||||
@@ -1282,7 +1244,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
else:
|
||||
self._timerSel.stop()
|
||||
self.docFooter.updateMainCount(0, False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _runSelCounter(self) -> None:
|
||||
@@ -1300,14 +1261,12 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
if self._docHandle and self._nwItem:
|
||||
self.docFooter.updateMainCount(cCount if CONFIG.useCharCount else wCount, True)
|
||||
self._timerSel.stop()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _closeCurrentDocument(self) -> None:
|
||||
"""Close the document. Forwarded to the main Gui."""
|
||||
self.closeEditorRequest.emit()
|
||||
self.docToolBar.setVisible(False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _toggleToolBarVisibility(self) -> None:
|
||||
@@ -1315,7 +1274,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
state = not self.docToolBar.isVisible()
|
||||
self.docToolBar.setVisible(state)
|
||||
CONFIG.showEditToolBar = state
|
||||
return
|
||||
|
||||
##
|
||||
# Search & Replace
|
||||
@@ -1326,14 +1284,12 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self.docSearch.setSearchText(self.getSelectedText() or None)
|
||||
resS, _ = self.findAllOccurences()
|
||||
self.docSearch.setResultCount(None, len(resS))
|
||||
return
|
||||
|
||||
def beginReplace(self) -> None:
|
||||
"""Initialise the search box and reset the replace text box."""
|
||||
self.beginSearch()
|
||||
self.docSearch.setReplaceText("")
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
def findNext(self, goBack: bool = False) -> None:
|
||||
"""Search for the next or previous occurrence of the search bar
|
||||
@@ -1621,8 +1577,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
self.setTextCursor(cursor)
|
||||
|
||||
return
|
||||
|
||||
def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> None:
|
||||
"""Replace all straight quotes in the selected text."""
|
||||
cursor = self.textCursor()
|
||||
@@ -1882,8 +1836,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
cursor.insertText(cleanText.rstrip() + "\n")
|
||||
cursor.endEditBlock()
|
||||
|
||||
return
|
||||
|
||||
def _insertCommentStructure(self, style: nwComment) -> None:
|
||||
"""Insert a shortcut/comment combo."""
|
||||
if self._docHandle and style == nwComment.FOOTNOTE:
|
||||
@@ -1925,7 +1877,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
cursor.endEditBlock()
|
||||
cursor.setPosition(pos)
|
||||
self.setTextCursor(cursor)
|
||||
return
|
||||
|
||||
def _addWord(self, word: str, block: QTextBlock, save: bool) -> None:
|
||||
"""Slot for the spell check context menu triggered when the user
|
||||
@@ -1934,7 +1885,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
logger.debug("Added '%s' to project dictionary, %s", word, "saved" if save else "unsaved")
|
||||
SHARED.spelling.addWord(word, save=save)
|
||||
self._qDocument.syntaxHighlighter.rehighlightBlock(block)
|
||||
return
|
||||
|
||||
def _processTag(
|
||||
self, cursor: QTextCursor | None = None, follow: bool = True, create: bool = False
|
||||
@@ -2008,7 +1958,6 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
if self._docHandle:
|
||||
text = block.text().lstrip("#").lstrip("!").strip()
|
||||
self.requestProjectItemRenamed.emit(self._docHandle, text)
|
||||
return
|
||||
|
||||
def _autoSelect(self) -> QTextCursor:
|
||||
"""Return a cursor which may or may not have a selection based
|
||||
@@ -2078,14 +2027,11 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
self.setTextCursor(cursor)
|
||||
|
||||
return
|
||||
|
||||
def _makePosSelection(self, mode: QTextCursor.SelectionType, pos: QPoint) -> None:
|
||||
"""Select text based on selection mode, but first move cursor."""
|
||||
cursor = self.cursorForPosition(pos)
|
||||
self.setTextCursor(cursor)
|
||||
self._makeSelection(mode)
|
||||
return
|
||||
|
||||
def _allowAutoReplace(self, state: bool) -> None:
|
||||
"""Enable/disable the auto-replace feature temporarily."""
|
||||
@@ -2093,11 +2039,10 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self._doReplace = CONFIG.doReplace
|
||||
else:
|
||||
self._doReplace = False
|
||||
return
|
||||
|
||||
|
||||
class CommandCompleter(QMenu):
|
||||
"""GuiWidget: Command Completer Menu
|
||||
"""GuiWidget: Command Completer Menu.
|
||||
|
||||
This is a context menu with options populated from the user's
|
||||
defined tags and keys. It also helps to type the meta data keyword
|
||||
@@ -2109,7 +2054,6 @@ class CommandCompleter(QMenu):
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
return
|
||||
|
||||
def updateMetaText(self, text: str, pos: int) -> bool:
|
||||
"""Update the menu options based on the line of text."""
|
||||
@@ -2203,7 +2147,6 @@ class CommandCompleter(QMenu):
|
||||
super().keyPressEvent(event)
|
||||
elif isinstance(parent, GuiDocEditor):
|
||||
parent.keyPressEvent(event)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -2212,11 +2155,10 @@ class CommandCompleter(QMenu):
|
||||
def _emitComplete(self, pos: int, length: int, value: str) -> None:
|
||||
"""Emit the signal to indicate a selection has been made."""
|
||||
self.complete.emit(pos, length, value)
|
||||
return
|
||||
|
||||
|
||||
class BackgroundWordCounter(QRunnable):
|
||||
"""The Off-GUI Thread Word Counter
|
||||
"""The Off-GUI Thread Word Counter.
|
||||
|
||||
A runnable for the word counter to be run in the thread pool off the
|
||||
main GUI thread.
|
||||
@@ -2228,9 +2170,9 @@ class BackgroundWordCounter(QRunnable):
|
||||
self._forSelection = forSelection
|
||||
self._isRunning = False
|
||||
self.signals = BackgroundWordCounterSignals()
|
||||
return
|
||||
|
||||
def isRunning(self) -> bool:
|
||||
"""Return True if the word counter is already running."""
|
||||
return self._isRunning
|
||||
|
||||
@pyqtSlot()
|
||||
@@ -2248,17 +2190,17 @@ class BackgroundWordCounter(QRunnable):
|
||||
self.signals.countsReady.emit(cC, wC, pC)
|
||||
self._isRunning = False
|
||||
|
||||
return
|
||||
|
||||
|
||||
class BackgroundWordCounterSignals(QObject):
|
||||
"""The QRunnable cannot emit a signal, so we need a simple QObject
|
||||
to hold the word counter signal.
|
||||
"""
|
||||
|
||||
countsReady = pyqtSignal(int, int, int)
|
||||
|
||||
|
||||
class TextAutoReplace:
|
||||
"""Encapsulates the editor auto replace feature."""
|
||||
|
||||
__slots__ = (
|
||||
"_doPadAfter", "_doPadBefore", "_padAfter", "_padBefore", "_padChar",
|
||||
@@ -2268,7 +2210,6 @@ class TextAutoReplace:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.initSettings()
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Initialise the auto-replace settings from config."""
|
||||
@@ -2287,7 +2228,6 @@ class TextAutoReplace:
|
||||
self._padAfter = CONFIG.fmtPadAfter
|
||||
self._doPadBefore = bool(CONFIG.fmtPadBefore)
|
||||
self._doPadAfter = bool(CONFIG.fmtPadAfter)
|
||||
return
|
||||
|
||||
def process(self, text: str, cursor: QTextCursor) -> bool:
|
||||
"""Auto-replace text elements based on main configuration.
|
||||
@@ -2401,7 +2341,7 @@ class TextAutoReplace:
|
||||
|
||||
|
||||
class GuiDocToolBar(QWidget):
|
||||
"""The Formatting and Options Fold Out Menu
|
||||
"""The Formatting and Options Fold Out Menu.
|
||||
|
||||
Only used by DocEditor, and is opened by the first button in the
|
||||
header.
|
||||
@@ -2513,8 +2453,6 @@ class GuiDocToolBar(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiDocToolBar")
|
||||
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Initialise GUI elements that depend on specific settings."""
|
||||
syntax = SHARED.theme.syntaxTheme
|
||||
@@ -2537,11 +2475,9 @@ class GuiDocToolBar(QWidget):
|
||||
self.tbSuperscript.setThemeIcon("fmt_superscript")
|
||||
self.tbSubscript.setThemeIcon("fmt_subscript")
|
||||
|
||||
return
|
||||
|
||||
|
||||
class GuiDocEditSearch(QFrame):
|
||||
"""The Embedded Document Search/Replace Feature
|
||||
"""The Embedded Document Search/Replace Feature.
|
||||
|
||||
Only used by DocEditor, and is at a fixed position in the
|
||||
QTextEdit's viewport.
|
||||
@@ -2671,8 +2607,6 @@ class GuiDocEditSearch(QFrame):
|
||||
|
||||
logger.debug("Ready: GuiDocEditSearch")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
@@ -2721,14 +2655,12 @@ class GuiDocEditSearch(QFrame):
|
||||
self.searchBox.selectAll()
|
||||
if CONFIG.searchRegEx:
|
||||
self._alertSearchValid(True)
|
||||
return
|
||||
|
||||
def setReplaceText(self, text: str) -> None:
|
||||
"""Set the replace text."""
|
||||
self.showReplace.setChecked(True)
|
||||
self.replaceBox.setFocus()
|
||||
self.replaceBox.setText(text)
|
||||
return
|
||||
|
||||
def setResultCount(self, currRes: int | None, resCount: int | None) -> None:
|
||||
"""Set the count values for the current search."""
|
||||
@@ -2743,7 +2675,6 @@ class GuiDocEditSearch(QFrame):
|
||||
self.resultLabel.setMinimumWidth(minWidth)
|
||||
self.adjustSize()
|
||||
self.docEditor.updateDocMargins()
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
@@ -2759,7 +2690,6 @@ class GuiDocEditSearch(QFrame):
|
||||
self.resultLabel.setMinimumWidth(
|
||||
SHARED.theme.getTextWidth("?/?", SHARED.theme.guiFontSmall)
|
||||
)
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
@@ -2784,11 +2714,9 @@ class GuiDocEditSearch(QFrame):
|
||||
self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
|
||||
self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
|
||||
|
||||
return
|
||||
|
||||
def cycleFocus(self) -> bool:
|
||||
"""The tab key just alternates focus between the two input
|
||||
boxes, if the replace box is visible.
|
||||
"""Cycle focus on tab key press. This just alternates focus
|
||||
between the two input boxes, if the replace box is visible.
|
||||
"""
|
||||
if self.searchBox.hasFocus():
|
||||
self.replaceBox.setFocus()
|
||||
@@ -2813,7 +2741,6 @@ class GuiDocEditSearch(QFrame):
|
||||
self.setVisible(False)
|
||||
self.docEditor.updateDocMargins()
|
||||
self.docEditor.setFocus()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -2823,13 +2750,11 @@ class GuiDocEditSearch(QFrame):
|
||||
def _doSearch(self) -> None:
|
||||
"""Call the search action function for the document editor."""
|
||||
self.docEditor.findNext(goBack=(QApplication.keyboardModifiers() == QtModShift))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _doReplace(self) -> None:
|
||||
"""Call the replace action function for the document editor."""
|
||||
self.docEditor.replaceNext()
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleReplace(self, state: bool) -> None:
|
||||
@@ -2838,43 +2763,36 @@ class GuiDocEditSearch(QFrame):
|
||||
self.replaceButton.setVisible(state)
|
||||
self.adjustSize()
|
||||
self.docEditor.updateDocMargins()
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleCase(self, state: bool) -> None:
|
||||
"""Enable/disable case sensitive mode."""
|
||||
CONFIG.searchCase = state
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleWord(self, state: bool) -> None:
|
||||
"""Enable/disable whole word search mode."""
|
||||
CONFIG.searchWord = state
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleRegEx(self, state: bool) -> None:
|
||||
"""Enable/disable regular expression search mode."""
|
||||
CONFIG.searchRegEx = state
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleLoop(self, state: bool) -> None:
|
||||
"""Enable/disable looping the search."""
|
||||
CONFIG.searchLoop = state
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleProject(self, state: bool) -> None:
|
||||
"""Enable/disable continuing search in next project file."""
|
||||
CONFIG.searchNextFile = state
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleMatchCap(self, state: bool) -> None:
|
||||
"""Enable/disable preserving capitalisation when replacing."""
|
||||
CONFIG.searchMatchCap = state
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -2890,11 +2808,10 @@ class GuiDocEditSearch(QFrame):
|
||||
palette.text().color() if isValid else SHARED.theme.errorText
|
||||
)
|
||||
self.searchBox.setPalette(palette)
|
||||
return
|
||||
|
||||
|
||||
class GuiDocEditHeader(QWidget):
|
||||
"""The Embedded Document Header
|
||||
"""The Embedded Document Header.
|
||||
|
||||
Only used by DocEditor, and is at a fixed position in the
|
||||
QTextEdit's viewport.
|
||||
@@ -2985,8 +2902,6 @@ class GuiDocEditHeader(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiDocEditHeader")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -3003,7 +2918,6 @@ class GuiDocEditHeader(QWidget):
|
||||
self.searchButton.setVisible(False)
|
||||
self.closeButton.setVisible(False)
|
||||
self.minmaxButton.setVisible(False)
|
||||
return
|
||||
|
||||
def setOutline(self, data: dict[int, str]) -> None:
|
||||
"""Set the document outline dataset."""
|
||||
@@ -3015,13 +2929,11 @@ class GuiDocEditHeader(QWidget):
|
||||
action.triggered.connect(qtLambda(self._gotoBlock, number))
|
||||
self._docOutline = data
|
||||
logger.debug("Document outline updated in %.3f ms", 1000*(time() - tStart))
|
||||
return
|
||||
|
||||
def updateFont(self) -> None:
|
||||
"""Update the font settings."""
|
||||
self.setFont(SHARED.theme.guiFont)
|
||||
self.itemTitle.setFont(SHARED.theme.guiFontSmall)
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
@@ -3040,8 +2952,6 @@ class GuiDocEditHeader(QWidget):
|
||||
|
||||
self.matchColors()
|
||||
|
||||
return
|
||||
|
||||
def matchColors(self) -> None:
|
||||
"""Update the colours of the widget to match those of the syntax
|
||||
theme rather than the main GUI.
|
||||
@@ -3055,12 +2965,10 @@ class GuiDocEditHeader(QWidget):
|
||||
self.itemTitle.setTextColors(
|
||||
color=palette.windowText().color(), faded=SHARED.theme.fadedText
|
||||
)
|
||||
return
|
||||
|
||||
def changeFocusState(self, state: bool) -> None:
|
||||
"""Toggle focus state."""
|
||||
self.itemTitle.setColorState(state)
|
||||
return
|
||||
|
||||
def setHandle(self, tHandle: str) -> None:
|
||||
"""Set the document title from the handle, or alternatively, set
|
||||
@@ -3081,8 +2989,6 @@ class GuiDocEditHeader(QWidget):
|
||||
self.closeButton.setVisible(True)
|
||||
self.minmaxButton.setVisible(True)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
@@ -3092,19 +2998,16 @@ class GuiDocEditHeader(QWidget):
|
||||
"""Trigger the close editor on the main window."""
|
||||
self.clearHeader()
|
||||
self.closeDocumentRequest.emit()
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _gotoBlock(self, blockNumber: int) -> None:
|
||||
"""Move cursor to a specific heading."""
|
||||
self.docEditor.setCursorLine(blockNumber + 1)
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _focusModeChanged(self, focusMode: bool) -> None:
|
||||
"""Update minimise/maximise icon of the Focus Mode button."""
|
||||
self.minmaxButton.setThemeIcon("minimise" if focusMode else "maximise", "blue")
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
@@ -3116,11 +3019,10 @@ class GuiDocEditHeader(QWidget):
|
||||
"""
|
||||
if event.button() == QtMouseLeft:
|
||||
self.docEditor.requestProjectItemSelected.emit(self._docHandle or "", True)
|
||||
return
|
||||
|
||||
|
||||
class GuiDocEditFooter(QWidget):
|
||||
"""The Embedded Document Footer
|
||||
"""The Embedded Document Footer.
|
||||
|
||||
Only used by DocEditor, and is at a fixed position in the
|
||||
QTextEdit's viewport.
|
||||
@@ -3205,8 +3107,6 @@ class GuiDocEditFooter(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiDocEditFooter")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -3216,7 +3116,6 @@ class GuiDocEditFooter(QWidget):
|
||||
self._trMainCount = trStats(nwLabels.STATS_DISPLAY[
|
||||
nwStats.CHARS if CONFIG.useCharCount else nwStats.WORDS
|
||||
])
|
||||
return
|
||||
|
||||
def updateFont(self) -> None:
|
||||
"""Update the font settings."""
|
||||
@@ -3224,7 +3123,6 @@ class GuiDocEditFooter(QWidget):
|
||||
self.statusText.setFont(SHARED.theme.guiFontSmall)
|
||||
self.linesText.setFont(SHARED.theme.guiFontSmall)
|
||||
self.wordsText.setFont(SHARED.theme.guiFontSmall)
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
@@ -3232,7 +3130,6 @@ class GuiDocEditFooter(QWidget):
|
||||
self.linesIcon.setPixmap(SHARED.theme.getPixmap("lines", (iPx, iPx)))
|
||||
self.wordsIcon.setPixmap(SHARED.theme.getPixmap("stats", (iPx, iPx)))
|
||||
self.matchColors()
|
||||
return
|
||||
|
||||
def matchColors(self) -> None:
|
||||
"""Update the colours of the widget to match those of the syntax
|
||||
@@ -3250,8 +3147,6 @@ class GuiDocEditFooter(QWidget):
|
||||
self.linesText.setPalette(palette)
|
||||
self.wordsText.setPalette(palette)
|
||||
|
||||
return
|
||||
|
||||
def setHandle(self, tHandle: str | None) -> None:
|
||||
"""Set the handle that will populate the footer's data."""
|
||||
self._docHandle = tHandle
|
||||
@@ -3264,8 +3159,6 @@ class GuiDocEditFooter(QWidget):
|
||||
self.updateInfo()
|
||||
self.updateMainCount(0, False)
|
||||
|
||||
return
|
||||
|
||||
def updateInfo(self) -> None:
|
||||
"""Update the content of text labels."""
|
||||
if self._tItem is None:
|
||||
@@ -3280,8 +3173,6 @@ class GuiDocEditFooter(QWidget):
|
||||
self.statusIcon.setPixmap(sIcon)
|
||||
self.statusText.setText(sText)
|
||||
|
||||
return
|
||||
|
||||
def updateLineCount(self, cursor: QTextCursor) -> None:
|
||||
"""Update the line and document position counter."""
|
||||
if document := cursor.document():
|
||||
@@ -3291,7 +3182,6 @@ class GuiDocEditFooter(QWidget):
|
||||
self.linesText.setText(
|
||||
self._trLineCount.format(f"{cLine:n}", f"{100*cPos//cCount:d} %")
|
||||
)
|
||||
return
|
||||
|
||||
def updateMainCount(self, count: int, selection: bool) -> None:
|
||||
"""Update main counter information."""
|
||||
@@ -3304,4 +3194,3 @@ class GuiDocEditFooter(QWidget):
|
||||
else:
|
||||
text = self._trMainCount.format("0", "+0")
|
||||
self.wordsText.setText(text)
|
||||
return
|
||||
|
||||
@@ -21,7 +21,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -57,6 +57,7 @@ BLOCK_TITLE = 4
|
||||
|
||||
|
||||
class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
"""GUI: Editor Syntax Highlighter."""
|
||||
|
||||
__slots__ = (
|
||||
"_cmnRules", "_dialogParser", "_hStyles", "_isInactive", "_isNovel",
|
||||
@@ -85,8 +86,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
|
||||
logger.debug("Ready: GuiDocHighlighter")
|
||||
|
||||
return
|
||||
|
||||
def initHighlighter(self) -> None:
|
||||
"""Initialise the syntax highlighter, setting all the colour
|
||||
rules and building the RegExes.
|
||||
@@ -255,8 +254,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
self._txtRules.append((rxRule, hlRule))
|
||||
self._cmnRules.append((rxRule, hlRule))
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
@@ -264,7 +261,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
def setSpellCheck(self, state: bool) -> None:
|
||||
"""Enable/disable the real time spell checker."""
|
||||
self._spellCheck = state
|
||||
return
|
||||
|
||||
def setHandle(self, tHandle: str) -> None:
|
||||
"""Set the handle of the currently highlighted document."""
|
||||
@@ -275,7 +271,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
self._isNovel = item.isDocumentLayout()
|
||||
self._isInactive = item.isInactiveClass()
|
||||
logger.debug("Syntax highlighter enabled for item '%s'", tHandle)
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
@@ -293,7 +288,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
if block.userState() & cType > 0:
|
||||
self.rehighlightBlock(block)
|
||||
logger.debug("Document highlighted in %.3f ms" % (1000*(time() - tStart)))
|
||||
return
|
||||
|
||||
##
|
||||
# Highlight Block
|
||||
@@ -506,10 +500,13 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
|
||||
self._hStyles[name] = charFormat
|
||||
|
||||
return
|
||||
|
||||
|
||||
class TextBlockData(QTextBlockUserData):
|
||||
"""Custom QTextBlock Data.
|
||||
|
||||
Custom data stored in a single text block. The spell check state is
|
||||
cached here and used when correcting misspelled text.
|
||||
"""
|
||||
|
||||
__slots__ = ("_metaData", "_offset", "_spellErrors", "_text")
|
||||
|
||||
@@ -519,7 +516,6 @@ class TextBlockData(QTextBlockUserData):
|
||||
self._offset = 0
|
||||
self._metaData: list[tuple[int, int, str, str]] = []
|
||||
self._spellErrors: list[tuple[int, int, str]] = []
|
||||
return
|
||||
|
||||
@property
|
||||
def metaData(self) -> list[tuple[int, int, str, str]]:
|
||||
@@ -553,8 +549,6 @@ class TextBlockData(QTextBlockUserData):
|
||||
self._text = text.replace("\u02bc", "'").replace("_", " ")
|
||||
self._offset = offset
|
||||
|
||||
return
|
||||
|
||||
def spellCheck(self, utf16Map: list[int] | None) -> list[tuple[int, int, str]]:
|
||||
"""Run the spell checker and cache the result, and return the
|
||||
list of spell check errors.
|
||||
|
||||
@@ -23,7 +23,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -60,6 +60,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiDocViewer(QTextBrowser):
|
||||
"""GUI: Document Viewer."""
|
||||
|
||||
closeDocumentRequest = pyqtSignal()
|
||||
documentLoaded = pyqtSignal(str)
|
||||
@@ -110,8 +111,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
logger.debug("Ready: GuiDocViewer")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
@@ -138,13 +137,11 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.setSearchPaths([""])
|
||||
self._docHandle = None
|
||||
self.docHeader.clearHeader()
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
self.docHeader.updateTheme()
|
||||
self.docFooter.updateTheme()
|
||||
return
|
||||
|
||||
def initViewer(self) -> None:
|
||||
"""Set editor settings from main config."""
|
||||
@@ -206,8 +203,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
# If we have a document open, we should reload it in case the font changed
|
||||
self.reloadText()
|
||||
|
||||
return
|
||||
|
||||
def loadText(self, tHandle: str, updateHistory: bool = True) -> bool:
|
||||
"""Load text into the viewer from an item handle."""
|
||||
if not SHARED.project.tree.checkType(tHandle, nwItemType.FILE):
|
||||
@@ -280,7 +275,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
"""Reload the text in the current document."""
|
||||
if self._docHandle:
|
||||
self.loadText(self._docHandle, updateHistory=False)
|
||||
return
|
||||
|
||||
def docAction(self, action: nwDocAction) -> bool:
|
||||
"""Process document actions on the current document."""
|
||||
@@ -308,7 +302,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
def clearNavHistory(self) -> None:
|
||||
"""Clear the navigation history."""
|
||||
self.docHistory.clear()
|
||||
return
|
||||
|
||||
def updateDocMargins(self) -> None:
|
||||
"""Automatically adjust the margins so the text is centred."""
|
||||
@@ -337,8 +330,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.docFooter.setGeometry(tB, fY, tW, fH)
|
||||
self.setViewportMargins(tM, max(cM, tH), tM, max(cM, fH))
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
@@ -347,7 +338,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
"""Set the scrollbar position."""
|
||||
if (vBar := self.verticalScrollBar()) and vBar.isVisible():
|
||||
vBar.setValue(pos)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -359,7 +349,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
if tHandle == self._docHandle and change == nwChange.UPDATE:
|
||||
self.docHeader.setHandle(tHandle)
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def navigateTo(self, anchor: str) -> None:
|
||||
@@ -367,7 +356,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
if isinstance(anchor, str) and anchor.startswith("#"):
|
||||
logger.debug("Moving to anchor '%s'", anchor)
|
||||
self.setSource(QUrl(anchor))
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -377,13 +365,11 @@ class GuiDocViewer(QTextBrowser):
|
||||
def navBackward(self) -> None:
|
||||
"""Navigate backwards in the document view history."""
|
||||
self.docHistory.backward()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def navForward(self) -> None:
|
||||
"""Navigate forwards in the document view history."""
|
||||
self.docHistory.forward()
|
||||
return
|
||||
|
||||
@pyqtSlot("QUrl")
|
||||
def _linkClicked(self, url: QUrl) -> None:
|
||||
@@ -396,7 +382,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.navigateTo(link)
|
||||
elif link.startswith("http"):
|
||||
QDesktopServices.openUrl(QUrl(url))
|
||||
return
|
||||
|
||||
@pyqtSlot("QPoint")
|
||||
def _openContextMenu(self, point: QPoint) -> None:
|
||||
@@ -430,8 +415,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
ctxMenu.setParent(None)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
@@ -440,7 +423,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
"""Update document margins when widget is resized."""
|
||||
self.updateDocMargins()
|
||||
super().resizeEvent(event)
|
||||
return
|
||||
|
||||
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
||||
"""Capture mouse click events on the document."""
|
||||
@@ -450,7 +432,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.navForward()
|
||||
else:
|
||||
super().mouseReleaseEvent(event)
|
||||
return
|
||||
|
||||
def dragEnterEvent(self, event: QDragEnterEvent) -> None:
|
||||
"""Overload drag enter event to handle dragged items."""
|
||||
@@ -458,7 +439,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragEnterEvent(event)
|
||||
return
|
||||
|
||||
def dragMoveEvent(self, event: QDragMoveEvent) -> None:
|
||||
"""Overload drag move event to handle dragged items."""
|
||||
@@ -466,7 +446,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragMoveEvent(event)
|
||||
return
|
||||
|
||||
def dropEvent(self, event: QDropEvent) -> None:
|
||||
"""Overload drop event to handle dragged items."""
|
||||
@@ -476,7 +455,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.openDocumentRequest.emit(handles[0], nwDocMode.VIEW, "", True)
|
||||
else:
|
||||
super().dropEvent(event)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -500,16 +478,18 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
self.setTextCursor(cursor)
|
||||
|
||||
return
|
||||
|
||||
def _makePosSelection(self, selType: QTextCursor.SelectionType, pos: QPoint) -> None:
|
||||
"""Handle text selection at a given location."""
|
||||
self.setTextCursor(self.cursorForPosition(pos))
|
||||
self._makeSelection(selType)
|
||||
return
|
||||
|
||||
|
||||
class GuiDocViewHistory:
|
||||
"""GUI: Document Viewer History.
|
||||
|
||||
This class holds the navigation history for the viewer panel, which
|
||||
is used for backward/forward navigation.
|
||||
"""
|
||||
|
||||
def __init__(self, docViewer: GuiDocViewer) -> None:
|
||||
self.docViewer = docViewer
|
||||
@@ -517,7 +497,6 @@ class GuiDocViewHistory:
|
||||
self._posHistory = []
|
||||
self._currPos = -1
|
||||
self._prevPos = -1
|
||||
return
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Clear the view history."""
|
||||
@@ -526,7 +505,6 @@ class GuiDocViewHistory:
|
||||
self._posHistory = []
|
||||
self._currPos = -1
|
||||
self._prevPos = -1
|
||||
return
|
||||
|
||||
def append(self, tHandle: str) -> bool:
|
||||
"""Append a document handle and its scroll bar position to the
|
||||
@@ -566,7 +544,6 @@ class GuiDocViewHistory:
|
||||
self._currPos = newPos
|
||||
self._updateNavButtons()
|
||||
self._dumpHistory()
|
||||
return
|
||||
|
||||
def backward(self) -> None:
|
||||
"""Navigate to the previous entry in the view history."""
|
||||
@@ -580,7 +557,6 @@ class GuiDocViewHistory:
|
||||
self._currPos = newPos
|
||||
self._updateNavButtons()
|
||||
self._dumpHistory()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -590,12 +566,10 @@ class GuiDocViewHistory:
|
||||
"""Update the scrollbar position of the previous entry."""
|
||||
if self._prevPos >= 0 and self._prevPos < len(self._posHistory):
|
||||
self._posHistory[self._prevPos] = self.docViewer.scrollPosition
|
||||
return
|
||||
|
||||
def _updateNavButtons(self) -> None:
|
||||
"""Update the navigation buttons in the document header."""
|
||||
self.docViewer.docHeader.updateNavButtons(0, len(self._navHistory) - 1, self._currPos)
|
||||
return
|
||||
|
||||
def _truncateHistory(self, atPos: int) -> None:
|
||||
"""Truncate the navigation history to the given position. Also
|
||||
@@ -606,7 +580,6 @@ class GuiDocViewHistory:
|
||||
self._posHistory = self._posHistory[nSkip:atPos + 1]
|
||||
self._currPos -= nSkip
|
||||
self._prevPos -= nSkip
|
||||
return
|
||||
|
||||
def _dumpHistory(self) -> None:
|
||||
"""Debug function to dump history to the logger. Since it is a
|
||||
@@ -616,11 +589,10 @@ class GuiDocViewHistory:
|
||||
for i, (h, p) in enumerate(zip(self._navHistory, self._posHistory, strict=False)):
|
||||
a = ">" if i == self._currPos else " "
|
||||
logger.debug(f"History {i + 1:02d}: {a} {h:13s} [x:{p}]")
|
||||
return
|
||||
|
||||
|
||||
class GuiDocViewHeader(QWidget):
|
||||
"""The Embedded Document Header
|
||||
"""The Embedded Document Header.
|
||||
|
||||
Only used by DocViewer, and is at a fixed position in the
|
||||
QTextBrowser's viewport.
|
||||
@@ -711,8 +683,6 @@ class GuiDocViewHeader(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiDocViewHeader")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -730,7 +700,6 @@ class GuiDocViewHeader(QWidget):
|
||||
self.editButton.setVisible(False)
|
||||
self.refreshButton.setVisible(False)
|
||||
self.closeButton.setVisible(False)
|
||||
return
|
||||
|
||||
def setOutline(self, data: dict[str, tuple[str, int]]) -> None:
|
||||
"""Set the document outline dataset."""
|
||||
@@ -750,13 +719,11 @@ class GuiDocViewHeader(QWidget):
|
||||
lambda _, title=title: self.docViewer.navigateTo(f"#{tHandle}:{title}")
|
||||
)
|
||||
self._docOutline = data
|
||||
return
|
||||
|
||||
def updateFont(self) -> None:
|
||||
"""Update the font settings."""
|
||||
self.setFont(SHARED.theme.guiFont)
|
||||
self.itemTitle.setFont(SHARED.theme.guiFontSmall)
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
@@ -777,8 +744,6 @@ class GuiDocViewHeader(QWidget):
|
||||
|
||||
self.matchColors()
|
||||
|
||||
return
|
||||
|
||||
def matchColors(self) -> None:
|
||||
"""Update the colours of the widget to match those of the syntax
|
||||
theme rather than the main GUI.
|
||||
@@ -792,15 +757,13 @@ class GuiDocViewHeader(QWidget):
|
||||
self.itemTitle.setTextColors(
|
||||
color=palette.windowText().color(), faded=SHARED.theme.fadedText
|
||||
)
|
||||
return
|
||||
|
||||
def changeFocusState(self, state: bool) -> None:
|
||||
"""Toggle focus state."""
|
||||
self.itemTitle.setColorState(state)
|
||||
return
|
||||
|
||||
def setHandle(self, tHandle: str) -> None:
|
||||
"""Sets the document title from the handle, or alternatively,
|
||||
"""Set the document title from the handle, or alternatively,
|
||||
set the whole document path.
|
||||
"""
|
||||
self._docHandle = tHandle
|
||||
@@ -819,13 +782,10 @@ class GuiDocViewHeader(QWidget):
|
||||
self.refreshButton.setVisible(True)
|
||||
self.closeButton.setVisible(True)
|
||||
|
||||
return
|
||||
|
||||
def updateNavButtons(self, firstIdx: int, lastIdx: int, currIdx: int) -> None:
|
||||
"""Enable and disable nav buttons based on index in history."""
|
||||
self.backButton.setEnabled(currIdx > firstIdx)
|
||||
self.forwardButton.setEnabled(currIdx < lastIdx)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -836,20 +796,17 @@ class GuiDocViewHeader(QWidget):
|
||||
"""Trigger the close editor/viewer on the main window."""
|
||||
self.clearHeader()
|
||||
self.docViewer.closeDocumentRequest.emit()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _refreshDocument(self) -> None:
|
||||
"""Reload the content of the document."""
|
||||
self.docViewer.reloadDocumentRequest.emit()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _editDocument(self) -> None:
|
||||
"""Open the document in the editor."""
|
||||
if tHandle := self._docHandle:
|
||||
self.docViewer.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, "", True)
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
@@ -861,11 +818,10 @@ class GuiDocViewHeader(QWidget):
|
||||
"""
|
||||
if event.button() == QtMouseLeft:
|
||||
self.docViewer.requestProjectItemSelected.emit(self._docHandle, True)
|
||||
return
|
||||
|
||||
|
||||
class GuiDocViewFooter(QWidget):
|
||||
"""The Embedded Document Footer
|
||||
"""The Embedded Document Footer.
|
||||
|
||||
Only used by DocViewer, and is at a fixed position in the
|
||||
QTextBrowser's viewport.
|
||||
@@ -944,8 +900,6 @@ class GuiDocViewFooter(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiDocViewFooter")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -956,7 +910,6 @@ class GuiDocViewFooter(QWidget):
|
||||
self.showComments.setFont(SHARED.theme.guiFontSmall)
|
||||
self.showSynopsis.setFont(SHARED.theme.guiFontSmall)
|
||||
self.showNotes.setFont(SHARED.theme.guiFontSmall)
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
@@ -977,8 +930,6 @@ class GuiDocViewFooter(QWidget):
|
||||
|
||||
self.matchColors()
|
||||
|
||||
return
|
||||
|
||||
def matchColors(self) -> None:
|
||||
"""Update the colours of the widget to match those of the syntax
|
||||
theme rather than the main GUI.
|
||||
@@ -989,7 +940,6 @@ class GuiDocViewFooter(QWidget):
|
||||
palette.setColor(QPalette.ColorRole.WindowText, syntax.text)
|
||||
palette.setColor(QPalette.ColorRole.Text, syntax.text)
|
||||
self.setPalette(palette)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -1000,18 +950,15 @@ class GuiDocViewFooter(QWidget):
|
||||
"""Toggle the view comment button and reload the document."""
|
||||
CONFIG.viewComments = state
|
||||
self.docViewer.reloadText()
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleSynopsis(self, state: bool) -> None:
|
||||
"""Toggle the view synopsis button and reload the document."""
|
||||
CONFIG.viewSynopsis = state
|
||||
self.docViewer.reloadText()
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _doToggleNotes(self, state: bool) -> None:
|
||||
"""Toggle the view notes button and reload the document."""
|
||||
CONFIG.viewNotes = state
|
||||
self.docViewer.reloadText()
|
||||
return
|
||||
|
||||
@@ -20,7 +20,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -49,6 +49,10 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiDocViewerPanel(QWidget):
|
||||
"""GUI: Document Viewer Panel.
|
||||
|
||||
The panel of project meta data below the viewer.
|
||||
"""
|
||||
|
||||
openDocumentRequest = pyqtSignal(str, Enum, str, bool)
|
||||
loadDocumentTagRequest = pyqtSignal(str, Enum)
|
||||
@@ -96,8 +100,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiDocViewerPanel")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -113,7 +115,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
for tab in self.kwTabs.values():
|
||||
tab.updateTheme()
|
||||
self._loadAllTags()
|
||||
return
|
||||
|
||||
def openProjectTasks(self) -> None:
|
||||
"""Run open project tasks."""
|
||||
@@ -124,7 +125,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
for key, value in colWidths.items():
|
||||
if key in self.kwTabs and isinstance(value, list):
|
||||
self.kwTabs[key].setColumnWidths(value)
|
||||
return
|
||||
|
||||
def closeProjectTasks(self) -> None:
|
||||
"""Run close project tasks."""
|
||||
@@ -133,7 +133,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
hideInactive = self.aInactive.isChecked()
|
||||
SHARED.project.options.setValue("GuiDocViewerPanel", "colWidths", colWidths)
|
||||
SHARED.project.options.setValue("GuiDocViewerPanel", "hideInactive", hideInactive)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -145,7 +144,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
self.tabBackRefs.clearContent()
|
||||
for cTab in self.kwTabs.values():
|
||||
cTab.clearContent()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def indexHasAppeared(self) -> None:
|
||||
@@ -153,7 +151,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
self._loadAllTags()
|
||||
self._updateTabVisibility()
|
||||
self.updateHandle(self._lastHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str, Enum)
|
||||
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
|
||||
@@ -168,14 +165,12 @@ class GuiDocViewerPanel(QWidget):
|
||||
else:
|
||||
self.kwTabs[tClass].removeEntry(key)
|
||||
self._updateTabVisibility()
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateHandle(self, tHandle: str | None) -> None:
|
||||
"""Update the document handle."""
|
||||
self._lastHandle = tHandle
|
||||
self.tabBackRefs.refreshContent(tHandle or None)
|
||||
return
|
||||
|
||||
@pyqtSlot(list, list)
|
||||
def updateChangedTags(self, updated: list[str], deleted: list[str]) -> None:
|
||||
@@ -191,14 +186,12 @@ class GuiDocViewerPanel(QWidget):
|
||||
else:
|
||||
logger.warning("Could not remove tag '%s' from view panel", key)
|
||||
self._updateTabVisibility()
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateStatusLabels(self, kind: str) -> None:
|
||||
"""Update the importance labels."""
|
||||
if kind == "i":
|
||||
self._loadAllTags()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -212,7 +205,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
cTab.clearContent()
|
||||
self._loadAllTags()
|
||||
self._updateTabVisibility()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -222,7 +214,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
"""Hide class tabs with no content."""
|
||||
for tClass, cTab in self.kwTabs.items():
|
||||
self.mainTabs.setTabVisible(self.idTabs[tClass], cTab.countEntries() > 0)
|
||||
return
|
||||
|
||||
def _loadAllTags(self) -> None:
|
||||
"""Load all tags into the tabs."""
|
||||
@@ -230,7 +221,6 @@ class GuiDocViewerPanel(QWidget):
|
||||
for key, name, tClass, iItem, hItem in data:
|
||||
if tClass in self.kwTabs and iItem and hItem:
|
||||
self.kwTabs[tClass].addUpdateEntry(key, name, iItem, hItem)
|
||||
return
|
||||
|
||||
|
||||
class _ViewPanelBackRefs(QTreeWidget):
|
||||
@@ -278,8 +268,6 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
self.clicked.connect(self._treeItemClicked)
|
||||
self.doubleClicked.connect(self._treeItemDoubleClicked)
|
||||
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
self._editIcon = SHARED.theme.getIcon("edit", "green")
|
||||
@@ -288,13 +276,11 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
if item := self.topLevelItem(i):
|
||||
item.setIcon(self.C_EDIT, self._editIcon)
|
||||
item.setIcon(self.C_VIEW, self._viewIcon)
|
||||
return
|
||||
|
||||
def clearContent(self) -> None:
|
||||
"""Clear the widget."""
|
||||
self.clear()
|
||||
self._treeMap = {}
|
||||
return
|
||||
|
||||
def refreshContent(self, dHandle: str | None) -> None:
|
||||
"""Update the content."""
|
||||
@@ -303,7 +289,6 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
refs = SHARED.project.index.getBackReferenceList(dHandle)
|
||||
for tHandle, (sTitle, hItem) in refs.items():
|
||||
self._setTreeItemValues(tHandle, sTitle, hItem)
|
||||
return
|
||||
|
||||
def refreshDocument(self, tHandle: str) -> None:
|
||||
"""Refresh document meta data."""
|
||||
@@ -311,7 +296,6 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
for sTitle, hItem in iItem.items():
|
||||
if f"{tHandle}:{sTitle}" in self._treeMap:
|
||||
self._setTreeItemValues(tHandle, sTitle, hItem)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -325,7 +309,6 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
self._parent.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, "", True)
|
||||
elif index.column() == self.C_VIEW:
|
||||
self._parent.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, "", True)
|
||||
return
|
||||
|
||||
@pyqtSlot("QModelIndex")
|
||||
def _treeItemDoubleClicked(self, index: QModelIndex) -> None:
|
||||
@@ -333,7 +316,6 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
tHandle = index.siblingAtColumn(self.C_DATA).data(self.D_HANDLE)
|
||||
if index.column() not in (self.C_EDIT, self.C_VIEW):
|
||||
self._parent.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, "", True)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -362,8 +344,6 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
self.addTopLevelItem(trItem)
|
||||
self._treeMap[tKey] = trItem
|
||||
|
||||
return
|
||||
|
||||
|
||||
class _ViewPanelKeyWords(QTreeWidget):
|
||||
|
||||
@@ -418,14 +398,11 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
self.clicked.connect(self._treeItemClicked)
|
||||
self.doubleClicked.connect(self._treeItemDoubleClicked)
|
||||
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
self._classIcon = SHARED.theme.getIcon(nwLabels.CLASS_ICON[self._class], "root")
|
||||
self._editIcon = SHARED.theme.getIcon("edit", "green")
|
||||
self._viewIcon = SHARED.theme.getIcon("view", "blue")
|
||||
return
|
||||
|
||||
def countEntries(self) -> int:
|
||||
"""Return the number of items in the list."""
|
||||
@@ -435,7 +412,6 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
"""Clear the list."""
|
||||
self._treeMap = {}
|
||||
self.clear()
|
||||
return
|
||||
|
||||
def addUpdateEntry(self, tag: str, name: str, iItem: IndexNode, hItem: IndexHeading) -> None:
|
||||
"""Add a new entry, or update an existing one."""
|
||||
@@ -470,8 +446,6 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
self.addTopLevelItem(trItem)
|
||||
self._treeMap[tag] = trItem
|
||||
|
||||
return
|
||||
|
||||
def removeEntry(self, tag: str) -> bool:
|
||||
"""Remove a tag from the list."""
|
||||
if tag in self._treeMap:
|
||||
@@ -487,7 +461,6 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
self.setColumnWidth(self.C_IMPORT, checkInt(widths[1], 100))
|
||||
self.setColumnWidth(self.C_DOC, checkInt(widths[2], 100))
|
||||
self.setColumnWidth(self.C_TITLE, checkInt(widths[3], 100))
|
||||
return
|
||||
|
||||
def getColumnWidths(self) -> list[int]:
|
||||
"""Get the widths of the user-adjustable columns."""
|
||||
@@ -510,7 +483,6 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
self._parent.loadDocumentTagRequest.emit(tag, nwDocMode.EDIT)
|
||||
elif index.column() == self.C_VIEW:
|
||||
self._parent.loadDocumentTagRequest.emit(tag, nwDocMode.VIEW)
|
||||
return
|
||||
|
||||
@pyqtSlot("QModelIndex")
|
||||
def _treeItemDoubleClicked(self, index: QModelIndex) -> None:
|
||||
@@ -518,4 +490,3 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
tag = index.siblingAtColumn(self.C_DATA).data(self.D_TAG)
|
||||
if index.column() not in (self.C_EDIT, self.C_VIEW):
|
||||
self._parent.loadDocumentTagRequest.emit(tag, nwDocMode.VIEW)
|
||||
return
|
||||
|
||||
@@ -20,7 +20,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -42,6 +42,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiTextDocument(QTextDocument):
|
||||
"""Custom: Modified QTextDocument.
|
||||
|
||||
A special text document format that incorporates a few additional
|
||||
features including spell checking.
|
||||
"""
|
||||
|
||||
def __init__(self, parent: QObject) -> None:
|
||||
super().__init__(parent=parent)
|
||||
@@ -52,11 +57,8 @@ class GuiTextDocument(QTextDocument):
|
||||
|
||||
logger.debug("Ready: GuiTextDocument")
|
||||
|
||||
return
|
||||
|
||||
def __del__(self) -> None: # pragma: no cover
|
||||
logger.debug("Delete: GuiTextDocument")
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
@@ -96,8 +98,6 @@ class GuiTextDocument(QTextDocument):
|
||||
logger.debug("Loaded %d text blocks in %.3f ms", count, 1000*(tMid - tStart))
|
||||
logger.debug("Highlighted document in %.3f ms", 1000*(tEnd - tMid))
|
||||
|
||||
return
|
||||
|
||||
def metaDataAtPos(self, pos: int) -> tuple[str, str]:
|
||||
"""Check if there is meta data available at a given position in
|
||||
the document, and if so, return it.
|
||||
@@ -146,4 +146,3 @@ class GuiTextDocument(QTextDocument):
|
||||
def setSpellCheckState(self, state: bool) -> None:
|
||||
"""Set the spell check state of the syntax highlighter."""
|
||||
self._syntax.setSpellCheck(state)
|
||||
return
|
||||
|
||||
@@ -20,7 +20,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -43,6 +43,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiItemDetails(QWidget):
|
||||
"""GUI: Project Item Details Panel."""
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
@@ -190,8 +191,6 @@ class GuiItemDetails(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiItemDetails")
|
||||
|
||||
return
|
||||
|
||||
###
|
||||
# Class Methods
|
||||
##
|
||||
@@ -210,7 +209,6 @@ class GuiItemDetails(QWidget):
|
||||
self.cCountData.clear()
|
||||
self.wCountData.clear()
|
||||
self.pCountData.clear()
|
||||
return
|
||||
|
||||
def refreshDetails(self) -> None:
|
||||
"""Reload the content of the details panel."""
|
||||
@@ -219,7 +217,6 @@ class GuiItemDetails(QWidget):
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
self.updateViewBox(self._handle)
|
||||
return
|
||||
|
||||
def updateViewBox(self, tHandle: str | None) -> None:
|
||||
"""Populate the details box from a given handle."""
|
||||
@@ -283,4 +280,3 @@ class GuiItemDetails(QWidget):
|
||||
self.updateViewBox(tHandle)
|
||||
elif change == nwChange.DELETE:
|
||||
self.updateViewBox(None)
|
||||
return
|
||||
|
||||
@@ -20,7 +20,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -82,8 +82,6 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
logger.debug("Ready: GuiMainMenu")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
##
|
||||
@@ -92,7 +90,6 @@ class GuiMainMenu(QMenuBar):
|
||||
def setSpellCheckState(self, state: bool) -> None:
|
||||
"""Forward spell check check state to its action."""
|
||||
self.aSpellCheck.setChecked(state)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -105,21 +102,18 @@ class GuiMainMenu(QMenuBar):
|
||||
decision, just pass a None to the function and let it decide.
|
||||
"""
|
||||
self.mainGui.docEditor.toggleSpellCheck(None)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _openUserManualFile(self) -> None:
|
||||
"""Open the documentation in PDF format."""
|
||||
if isinstance(CONFIG.pdfDocs, Path):
|
||||
openExternalPath(CONFIG.pdfDocs)
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _changeSpelling(self, language: str) -> None:
|
||||
"""Change the spell check language."""
|
||||
SHARED.project.data.setSpellLang(language)
|
||||
SHARED.updateSpellCheckLanguage()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -188,8 +182,6 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aExitNW.triggered.connect(qtLambda(self.mainGui.closeMain))
|
||||
self.mainGui.addAction(self.aExitNW)
|
||||
|
||||
return
|
||||
|
||||
def _buildDocumentMenu(self) -> None:
|
||||
"""Assemble the Document menu."""
|
||||
# Document
|
||||
@@ -236,8 +228,6 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aImportFile = qtAddAction(self.docuMenu, self.tr("Import Text from File"))
|
||||
self.aImportFile.triggered.connect(qtLambda(self.mainGui.importDocument))
|
||||
|
||||
return
|
||||
|
||||
def _buildEditMenu(self) -> None:
|
||||
"""Assemble the Edit menu."""
|
||||
# Edit
|
||||
@@ -305,8 +295,6 @@ class GuiMainMenu(QMenuBar):
|
||||
)
|
||||
self.mainGui.addAction(self.aSelectPar)
|
||||
|
||||
return
|
||||
|
||||
def _buildViewMenu(self) -> None:
|
||||
"""Assemble the View menu."""
|
||||
# View
|
||||
@@ -367,8 +355,6 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFullScreen.triggered.connect(self.mainGui.toggleFullScreenMode)
|
||||
self.mainGui.addAction(self.aFullScreen)
|
||||
|
||||
return
|
||||
|
||||
def _buildInsertMenu(self) -> None:
|
||||
"""Assemble the Insert menu."""
|
||||
# Insert
|
||||
@@ -646,8 +632,6 @@ class GuiMainMenu(QMenuBar):
|
||||
lambda: self.requestDocInsert.emit(nwDocInsert.FOOTNOTE)
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def _buildFormatMenu(self) -> None:
|
||||
"""Assemble the Format menu."""
|
||||
# Format
|
||||
@@ -901,8 +885,6 @@ class GuiMainMenu(QMenuBar):
|
||||
lambda: self.requestDocAction.emit(nwDocAction.RM_BREAKS)
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def _buildSearchMenu(self) -> None:
|
||||
"""Assemble the Search menu."""
|
||||
# Search
|
||||
@@ -948,8 +930,6 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFindProj.setShortcut("Ctrl+Shift+F")
|
||||
self.aFindProj.triggered.connect(qtLambda(self.requestViewChange.emit, nwView.SEARCH))
|
||||
|
||||
return
|
||||
|
||||
def _buildToolsMenu(self) -> None:
|
||||
"""Assemble the Tools menu."""
|
||||
# Tools
|
||||
@@ -1019,8 +999,6 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aPreferences.triggered.connect(self.mainGui.showPreferencesDialog)
|
||||
self.mainGui.addAction(self.aPreferences)
|
||||
|
||||
return
|
||||
|
||||
def _buildHelpMenu(self) -> None:
|
||||
"""Assemble the Help menu."""
|
||||
# Help
|
||||
@@ -1066,5 +1044,3 @@ class GuiMainMenu(QMenuBar):
|
||||
# Document > Main Website
|
||||
self.aWebsite = qtAddAction(self.helpMenu, self.tr("The novelWriter Website"))
|
||||
self.aWebsite.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_WEB))
|
||||
|
||||
return
|
||||
|
||||
@@ -24,7 +24,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -55,6 +55,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiNovelView(QWidget):
|
||||
"""GUI: Novel View Panel."""
|
||||
|
||||
# Signals for user interaction with the novel tree
|
||||
selectedItemChanged = pyqtSignal(str)
|
||||
@@ -82,8 +83,6 @@ class GuiNovelView(QWidget):
|
||||
self.getSelectedHandle = self.novelTree.getSelectedHandle
|
||||
self.refreshCurrentTree = self.novelBar.forceRefreshNovelTree
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -91,19 +90,16 @@ class GuiNovelView(QWidget):
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
self.novelBar.updateTheme()
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Initialise GUI elements that depend on specific settings."""
|
||||
self.novelTree.initSettings()
|
||||
return
|
||||
|
||||
def clearNovelView(self) -> None:
|
||||
"""Clear project-related GUI content."""
|
||||
self.novelBar.clearContent()
|
||||
self.novelBar.setEnabled(False)
|
||||
self.novelTree.clearContent()
|
||||
return
|
||||
|
||||
def openProjectTasks(self) -> None:
|
||||
"""Run open project tasks."""
|
||||
@@ -125,8 +121,6 @@ class GuiNovelView(QWidget):
|
||||
|
||||
self.novelTree.setLastColSize(lastColSize)
|
||||
|
||||
return
|
||||
|
||||
def closeProjectTasks(self) -> None:
|
||||
"""Run closing project tasks."""
|
||||
logger.debug("Saving State: GuiNovelView")
|
||||
@@ -140,12 +134,9 @@ class GuiNovelView(QWidget):
|
||||
|
||||
self.clearNovelView()
|
||||
|
||||
return
|
||||
|
||||
def setTreeFocus(self) -> None:
|
||||
"""Set the focus to the tree widget."""
|
||||
self.novelTree.setFocus()
|
||||
return
|
||||
|
||||
def treeHasFocus(self) -> bool:
|
||||
"""Check if the novel tree has focus."""
|
||||
@@ -159,22 +150,20 @@ class GuiNovelView(QWidget):
|
||||
def setCurrentNovel(self, rootHandle: str | None) -> None:
|
||||
"""Set the current novel to display."""
|
||||
self.novelTree.setNovelModel(rootHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def setActiveHandle(self, tHandle: str) -> None:
|
||||
"""Highlight the rows associated with a given handle."""
|
||||
self.novelTree.setActiveHandle(tHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str, Enum)
|
||||
def updateRootItem(self, tHandle: str, change: nwChange) -> None:
|
||||
"""If any root item changes, rebuild the novel root menu."""
|
||||
self.novelBar.buildNovelRootMenu()
|
||||
return
|
||||
|
||||
|
||||
class GuiNovelToolBar(QWidget):
|
||||
"""GUI: Novel View Panel ToolBar."""
|
||||
|
||||
def __init__(self, novelView: GuiNovelView) -> None:
|
||||
super().__init__(parent=novelView)
|
||||
@@ -249,8 +238,6 @@ class GuiNovelToolBar(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiNovelToolBar")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -277,20 +264,16 @@ class GuiNovelToolBar(QWidget):
|
||||
|
||||
self.forceRefreshNovelTree()
|
||||
|
||||
return
|
||||
|
||||
def clearContent(self) -> None:
|
||||
"""Run clearing project tasks."""
|
||||
self.novelValue.clear()
|
||||
self.novelValue.setToolTip("")
|
||||
return
|
||||
|
||||
def buildNovelRootMenu(self) -> None:
|
||||
"""Build the novel root menu."""
|
||||
self.novelValue.refreshNovelList()
|
||||
self.novelView.setCurrentNovel(self.novelValue.handle)
|
||||
self.tbNovel.setVisible(self.novelValue.count() > 1)
|
||||
return
|
||||
|
||||
def setCurrentRoot(self, rootHandle: str | None) -> None:
|
||||
"""Set the current active root handle."""
|
||||
@@ -300,7 +283,6 @@ class GuiNovelToolBar(QWidget):
|
||||
SHARED.project.data.setLastHandle(rootHandle, "novel")
|
||||
self.novelView.setCurrentNovel(rootHandle)
|
||||
self.novelView.novelTree.setAccessibleName(self.novelValue.currentText())
|
||||
return
|
||||
|
||||
def setLastColType(self, colType: nwNovelExtra, doRefresh: bool = True) -> None:
|
||||
"""Set the last column type."""
|
||||
@@ -309,7 +291,6 @@ class GuiNovelToolBar(QWidget):
|
||||
if doRefresh:
|
||||
self.forceRefreshNovelTree()
|
||||
self.novelView.novelTree.resizeColumns()
|
||||
return
|
||||
|
||||
def setActive(self, state: bool) -> None:
|
||||
"""Set the widget active state, which enables automatic tree
|
||||
@@ -322,7 +303,6 @@ class GuiNovelToolBar(QWidget):
|
||||
and self._refresh.get(handle, False)
|
||||
):
|
||||
self._refreshNovelTree(self.novelValue.handle)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -335,7 +315,6 @@ class GuiNovelToolBar(QWidget):
|
||||
self.novelView.setCurrentNovel(tHandle)
|
||||
SHARED.project.index.refreshNovelModel(tHandle)
|
||||
self._refresh[tHandle] = False
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -349,7 +328,6 @@ class GuiNovelToolBar(QWidget):
|
||||
self._refresh[tHandle] = False
|
||||
else:
|
||||
self._refresh[tHandle] = True
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectLastColumnSize(self) -> None:
|
||||
@@ -361,7 +339,6 @@ class GuiNovelToolBar(QWidget):
|
||||
if isOk:
|
||||
self.novelView.novelTree.setLastColSize(newSize)
|
||||
self.novelView.novelTree.resizeColumns()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -374,10 +351,10 @@ class GuiNovelToolBar(QWidget):
|
||||
aLast.setActionGroup(self.gLastCol)
|
||||
aLast.triggered.connect(qtLambda(self.setLastColType, colType))
|
||||
self.aLastCol[colType] = aLast
|
||||
return
|
||||
|
||||
|
||||
class GuiNovelTree(NTreeView):
|
||||
"""GUI: Novel View Panel Tree."""
|
||||
|
||||
def __init__(self, novelView: GuiNovelView) -> None:
|
||||
super().__init__(parent=novelView)
|
||||
@@ -414,8 +391,6 @@ class GuiNovelTree(NTreeView):
|
||||
|
||||
logger.debug("Ready: GuiNovelTree")
|
||||
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Set or update tree widget settings."""
|
||||
if CONFIG.hideVScroll:
|
||||
@@ -426,7 +401,6 @@ class GuiNovelTree(NTreeView):
|
||||
self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
|
||||
else:
|
||||
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
@@ -466,25 +440,21 @@ class GuiNovelTree(NTreeView):
|
||||
self.resizeColumns()
|
||||
else:
|
||||
self.clearContent()
|
||||
return
|
||||
|
||||
def setActiveHandle(self, tHandle: str | None) -> None:
|
||||
"""Set the handle to be highlighted."""
|
||||
self._actHandle = tHandle
|
||||
if viewport := self.viewport():
|
||||
viewport.repaint()
|
||||
return
|
||||
|
||||
def setLastColType(self, colType: nwNovelExtra) -> None:
|
||||
"""Set the extra column type."""
|
||||
self._lastColType = colType
|
||||
SHARED.project.index.setNovelModelExtraColumn(colType)
|
||||
return
|
||||
|
||||
def setLastColSize(self, colSize: int) -> None:
|
||||
"""Set the extra column size between 15% and 75%."""
|
||||
self._lastColSize = minmax(colSize, 15, 75)/100.0
|
||||
return
|
||||
|
||||
##
|
||||
# Class Methods
|
||||
@@ -493,7 +463,6 @@ class GuiNovelTree(NTreeView):
|
||||
def clearContent(self) -> None:
|
||||
"""Clear the tree view."""
|
||||
self.setModel(None)
|
||||
return
|
||||
|
||||
def resizeColumns(self) -> None:
|
||||
"""Set the correct column sizes."""
|
||||
@@ -506,7 +475,6 @@ class GuiNovelTree(NTreeView):
|
||||
if model.columns == 4:
|
||||
header.setSectionResizeMode(3, QtHeaderToContents)
|
||||
header.setMaximumSectionSize(int(self._lastColSize * vp.width()))
|
||||
return
|
||||
|
||||
##
|
||||
# Overloads
|
||||
@@ -517,7 +485,6 @@ class GuiNovelTree(NTreeView):
|
||||
if (model := self._getModel()) and model.handle(index) == self._actHandle:
|
||||
painter.fillRect(opt.rect, self.palette().alternateBase())
|
||||
super().drawRow(painter, opt, index)
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
@@ -527,7 +494,6 @@ class GuiNovelTree(NTreeView):
|
||||
"""Process size changed."""
|
||||
super().resizeEvent(event)
|
||||
self.resizeColumns()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -535,36 +501,33 @@ class GuiNovelTree(NTreeView):
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def _onSingleClick(self, index: QModelIndex) -> None:
|
||||
"""The user single-clicked an index."""
|
||||
"""Process user single-click on an index."""
|
||||
if index.isValid() and (model := self._getModel()):
|
||||
if (tHandle := model.handle(index)) and (sTitle := model.key(index)):
|
||||
self.novelView.selectedItemChanged.emit(tHandle)
|
||||
if index.column() == model.columnCount(index) - 1:
|
||||
pos = self.mapToGlobal(self.visualRect(index).topRight())
|
||||
self._popMetaBox(pos, tHandle, sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def _onDoubleClick(self, index: QModelIndex) -> None:
|
||||
"""The user double-clicked an index."""
|
||||
"""Process user double-click on an index."""
|
||||
if (
|
||||
(model := self._getModel())
|
||||
and (tHandle := model.handle(index))
|
||||
and (sTitle := model.key(index))
|
||||
):
|
||||
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, sTitle, False)
|
||||
return
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def _onMiddleClick(self, index: QModelIndex) -> None:
|
||||
"""The user middle-clicked an index."""
|
||||
"""Process user middle-click on an index."""
|
||||
if (
|
||||
(model := self._getModel())
|
||||
and (tHandle := model.handle(index))
|
||||
and (sTitle := model.key(index))
|
||||
):
|
||||
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, sTitle, False)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -582,7 +545,6 @@ class GuiNovelTree(NTreeView):
|
||||
"""Generate a reference list for a given reference key."""
|
||||
if tags := ", ".join(refs.get(key, [])):
|
||||
lines.append(f"<b>{trConst(nwLabels.KEY_NAME[key])}:</b> {tags}")
|
||||
return
|
||||
|
||||
if head := SHARED.project.index.getItemHeading(tHandle, sTitle):
|
||||
logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
|
||||
@@ -610,4 +572,3 @@ class GuiNovelTree(NTreeView):
|
||||
text = f"<p>{refs}</p>"
|
||||
if tooltip := (text + synopsis or self.tr("No meta data")):
|
||||
QToolTip.showText(qPos, tooltip)
|
||||
return
|
||||
|
||||
+10
-57
@@ -24,7 +24,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
@@ -58,6 +58,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiOutlineView(QWidget):
|
||||
"""GUI: Project Outline Panel."""
|
||||
|
||||
loadDocumentTagRequest = pyqtSignal(str, Enum)
|
||||
openDocumentRequest = pyqtSignal(str, Enum, str, bool)
|
||||
@@ -96,8 +97,6 @@ class GuiOutlineView(QWidget):
|
||||
# Function Mappings
|
||||
self.getSelectedHandle = self.outlineTree.getSelectedHandle
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -109,24 +108,20 @@ class GuiOutlineView(QWidget):
|
||||
self.outlineTree.refreshTree(
|
||||
rootHandle=SHARED.project.data.getLastHandle("outline"), overRide=True
|
||||
)
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Initialise GUI elements that depend on specific settings."""
|
||||
self.outlineTree.initSettings()
|
||||
self.outlineData.initSettings()
|
||||
return
|
||||
|
||||
def refreshTree(self) -> None:
|
||||
"""Refresh the current tree."""
|
||||
self.outlineTree.refreshTree(rootHandle=SHARED.project.data.getLastHandle("outline"))
|
||||
return
|
||||
|
||||
def clearOutline(self) -> None:
|
||||
"""Clear project-related GUI content."""
|
||||
self.outlineData.clearDetails()
|
||||
self.outlineBar.setEnabled(False)
|
||||
return
|
||||
|
||||
def openProjectTasks(self) -> None:
|
||||
"""Run open project tasks."""
|
||||
@@ -142,8 +137,6 @@ class GuiOutlineView(QWidget):
|
||||
self.outlineBar.setEnabled(True)
|
||||
self.outlineData.loadGuiSettings()
|
||||
|
||||
return
|
||||
|
||||
def closeProjectTasks(self) -> None:
|
||||
"""Run closing project tasks."""
|
||||
if self.outlineTree.wasRendered:
|
||||
@@ -152,7 +145,6 @@ class GuiOutlineView(QWidget):
|
||||
self.outlineTree.closeProjectTasks()
|
||||
self.outlineData.updateClasses()
|
||||
self.clearOutline()
|
||||
return
|
||||
|
||||
def splitSizes(self) -> list[int]:
|
||||
"""Get the sizes of the splitter widget."""
|
||||
@@ -175,7 +167,6 @@ class GuiOutlineView(QWidget):
|
||||
"""Handle tasks whenever a root folders changes."""
|
||||
self.outlineBar.populateNovelList()
|
||||
self.outlineData.updateClasses()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -188,23 +179,21 @@ class GuiOutlineView(QWidget):
|
||||
of columns has changed.
|
||||
"""
|
||||
self.outlineBar.setColumnHiddenState(self.outlineTree.hiddenColumns)
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _tagClicked(self, link: str) -> None:
|
||||
"""Capture the click of a tag in the details panel."""
|
||||
if link:
|
||||
self.loadDocumentTagRequest.emit(link, nwDocMode.VIEW)
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _rootItemChanged(self, tHandle: str) -> None:
|
||||
"""Handle root novel changed or needs to be refreshed."""
|
||||
self.outlineTree.refreshTree(rootHandle=(tHandle or None), overRide=True)
|
||||
return
|
||||
|
||||
|
||||
class GuiOutlineToolBar(QToolBar):
|
||||
"""GUI: Project Outline Panel ToolBar."""
|
||||
|
||||
loadNovelRootRequest = pyqtSignal(str)
|
||||
outlineExportRequest = pyqtSignal()
|
||||
@@ -263,8 +252,6 @@ class GuiOutlineToolBar(QToolBar):
|
||||
|
||||
logger.debug("Ready: GuiOutlineToolBar")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -278,22 +265,18 @@ class GuiOutlineToolBar(QToolBar):
|
||||
self.tbColumns.setIcon(SHARED.theme.getIcon("more_vertical"))
|
||||
self.tbColumns.setStyleSheet("QToolButton::menu-indicator {image: none;}")
|
||||
self.novelLabel.setTextColors(color=self.palette().windowText().color())
|
||||
return
|
||||
|
||||
def populateNovelList(self) -> None:
|
||||
"""Reload the content of the novel list."""
|
||||
self.novelValue.refreshNovelList()
|
||||
return
|
||||
|
||||
def setCurrentRoot(self, rootHandle: str | None) -> None:
|
||||
"""Set the current active root handle."""
|
||||
self.novelValue.setHandle(rootHandle)
|
||||
return
|
||||
|
||||
def setColumnHiddenState(self, hiddenState: dict[nwOutline, bool]) -> None:
|
||||
"""Forward the change of column hidden states to the menu."""
|
||||
self.mColumns.setHiddenState(hiddenState)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -303,22 +286,20 @@ class GuiOutlineToolBar(QToolBar):
|
||||
def _novelValueChanged(self, tHandle: str) -> None:
|
||||
"""Emit a signal containing the handle of the selected item."""
|
||||
self.loadNovelRootRequest.emit(tHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _refreshRequested(self) -> None:
|
||||
"""Emit a signal containing the handle of the selected item."""
|
||||
self.loadNovelRootRequest.emit(self.novelValue.handle)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _exportRequested(self) -> None:
|
||||
"""Emit a signal that an export of the outline was requested."""
|
||||
self.outlineExportRequest.emit()
|
||||
return
|
||||
|
||||
|
||||
class GuiOutlineTree(QTreeWidget):
|
||||
"""GUI: Project Outline Panel Tree."""
|
||||
|
||||
DEF_WIDTH: Final[dict[nwOutline, int]] = {
|
||||
nwOutline.TITLE: 200,
|
||||
@@ -422,8 +403,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
logger.debug("Ready: GuiOutlineTree")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
@@ -451,7 +430,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
|
||||
else:
|
||||
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
|
||||
return
|
||||
|
||||
def clearContent(self) -> None:
|
||||
"""Clear the tree and header and set the default values for the
|
||||
@@ -474,8 +452,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
self._treeNCols = len(self._treeOrder)
|
||||
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
iType = nwItemType.FILE
|
||||
@@ -488,15 +464,14 @@ class GuiOutlineTree(QTreeWidget):
|
||||
"H3": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H3"),
|
||||
"H4": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H4"),
|
||||
}
|
||||
return
|
||||
|
||||
def refreshTree(
|
||||
self, rootHandle: str | None = None,
|
||||
overRide: bool = False, novelChanged: bool = False
|
||||
) -> None:
|
||||
"""Called whenever the Outline tab is activated and controls
|
||||
what data to load, and if necessary, force a rebuild of the
|
||||
tree.
|
||||
"""Refresh the outline tree. Called whenever the Outline tab is
|
||||
activated and controls what data to load, and if necessary,
|
||||
force a rebuild of the tree.
|
||||
"""
|
||||
# If it's the first time, we always build
|
||||
if self._firstView or (self._firstView and overRide):
|
||||
@@ -518,11 +493,10 @@ class GuiOutlineTree(QTreeWidget):
|
||||
return
|
||||
|
||||
def closeProjectTasks(self) -> None:
|
||||
"""Called before a project is closed."""
|
||||
"""Call before a project is closed."""
|
||||
self._saveHeaderState()
|
||||
self.clearContent()
|
||||
self._firstView = True
|
||||
return
|
||||
|
||||
def getSelectedHandle(self) -> tuple[str | None, str | None]:
|
||||
"""Get the currently selected handle. If multiple items are
|
||||
@@ -546,7 +520,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
if hItem in self._colIdx:
|
||||
self.setColumnHidden(self._colIdx[hItem], not isChecked)
|
||||
self._saveHeaderState()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def exportOutline(self) -> None:
|
||||
@@ -562,7 +535,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
writer.writerows(
|
||||
self._dumpNovelData(self.outlineView.outlineBar.novelValue.handle)
|
||||
)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -577,7 +549,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
tHandle, sTitle = self.getSelectedHandle()
|
||||
if tHandle:
|
||||
self.outlineView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, sTitle or "", True)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _onItemSelectionChanged(self) -> None:
|
||||
@@ -588,7 +559,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
tHandle = items[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
|
||||
sTitle = items[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
|
||||
self.activeItemChanged.emit(tHandle, sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot(int, int, int)
|
||||
def _columnMoved(self, logIdx: int, oldVisualIdx: int, newVisualIdx: int) -> None:
|
||||
@@ -597,7 +567,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
"""
|
||||
self._treeOrder.insert(newVisualIdx, self._treeOrder.pop(oldVisualIdx))
|
||||
self._saveHeaderState()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -637,8 +606,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
self.hiddenStateChanged.emit()
|
||||
|
||||
return
|
||||
|
||||
def _saveHeaderState(self) -> None:
|
||||
"""Save the state of the main tree header, that is, column
|
||||
order, column width and column hidden state. We don't want to
|
||||
@@ -661,7 +628,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
pOptions = SHARED.project.options
|
||||
pOptions.setValue("GuiOutline", "columnState", colState)
|
||||
pOptions.saveSettings()
|
||||
return
|
||||
|
||||
def _populateTree(self, rootHandle: str | None) -> None:
|
||||
"""Build the tree based on the project index, and the header
|
||||
@@ -746,8 +712,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
self._lastBuild = time()
|
||||
logger.debug("Project outline built in %.3f ms", 1000.0*(time() - tStart))
|
||||
|
||||
return
|
||||
|
||||
def _dumpNovelData(self, rootHandle: str | None) -> list[list[str | int]]:
|
||||
"""Dump all novel data into a table."""
|
||||
sLabel = SHARED.project.localLookup("Story Structure")
|
||||
@@ -821,6 +785,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
|
||||
class GuiOutlineHeaderMenu(QMenu):
|
||||
"""GUI: Project Outline Panel Header Selection Menu."""
|
||||
|
||||
columnToggled = pyqtSignal(bool, Enum)
|
||||
|
||||
@@ -844,8 +809,6 @@ class GuiOutlineHeaderMenu(QMenu):
|
||||
)
|
||||
self.addAction(self.actionMap[hItem])
|
||||
|
||||
return
|
||||
|
||||
def setHiddenState(self, hiddenState: dict[nwOutline, bool]) -> None:
|
||||
"""Overwrite the checked state of the columns as the inverse of
|
||||
the hidden state. Skip the TITLE column as it cannot be hidden.
|
||||
@@ -859,10 +822,9 @@ class GuiOutlineHeaderMenu(QMenu):
|
||||
|
||||
self.acceptToggle = True
|
||||
|
||||
return
|
||||
|
||||
|
||||
class GuiOutlineDetails(QScrollArea):
|
||||
"""GUI: Project Outline Panel Details View."""
|
||||
|
||||
LVL_MAP: Final[dict[str, str]] = {
|
||||
"H1": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Title"),
|
||||
@@ -1007,8 +969,6 @@ class GuiOutlineDetails(QScrollArea):
|
||||
|
||||
logger.debug("Ready: GuiOutlineDetails")
|
||||
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Set or update outline settings."""
|
||||
if CONFIG.hideVScroll:
|
||||
@@ -1020,7 +980,6 @@ class GuiOutlineDetails(QScrollArea):
|
||||
else:
|
||||
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
|
||||
self.updateClasses()
|
||||
return
|
||||
|
||||
def loadGuiSettings(self) -> None:
|
||||
"""Run open project tasks."""
|
||||
@@ -1031,7 +990,6 @@ class GuiOutlineDetails(QScrollArea):
|
||||
pOptions.getInt("GuiOutlineDetails", "detailsWidth", width//3),
|
||||
pOptions.getInt("GuiOutlineDetails", "tagsWidth", 2*width//3),
|
||||
])
|
||||
return
|
||||
|
||||
def saveGuiSettings(self) -> None:
|
||||
"""Run close project tasks."""
|
||||
@@ -1040,7 +998,6 @@ class GuiOutlineDetails(QScrollArea):
|
||||
pOptions = SHARED.project.options
|
||||
pOptions.setValue("GuiOutlineDetails", "detailsWidth", mainSplit[0])
|
||||
pOptions.setValue("GuiOutlineDetails", "tagsWidth", mainSplit[1])
|
||||
return
|
||||
|
||||
def clearDetails(self) -> None:
|
||||
"""Clear all the data labels."""
|
||||
@@ -1057,7 +1014,6 @@ class GuiOutlineDetails(QScrollArea):
|
||||
value.clear()
|
||||
|
||||
self.updateClasses()
|
||||
return
|
||||
|
||||
##
|
||||
# Slots
|
||||
@@ -1090,8 +1046,6 @@ class GuiOutlineDetails(QScrollArea):
|
||||
for key, (_, value) in self.tagValues.items():
|
||||
value.setText(self._formatTags(novRefs, key))
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def updateClasses(self) -> None:
|
||||
"""Update the visibility status of class details."""
|
||||
@@ -1102,7 +1056,6 @@ class GuiOutlineDetails(QScrollArea):
|
||||
label, value = self.tagValues[key]
|
||||
label.setVisible(visible)
|
||||
value.setVisible(visible)
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def _formatTags(refs: dict[str, list[str]], key: str) -> str:
|
||||
|
||||
@@ -25,7 +25,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -61,7 +61,9 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiProjectView(QWidget):
|
||||
"""This is a wrapper class holding all the elements of the project
|
||||
"""GUI: Project View.
|
||||
|
||||
This is a wrapper class holding all the elements of the project
|
||||
tree. The core object is the project tree itself. Most methods
|
||||
available are mapped through to the project tree class.
|
||||
"""
|
||||
@@ -130,8 +132,6 @@ class GuiProjectView(QWidget):
|
||||
# Function Mappings
|
||||
self.getSelectedHandle = self.projTree.getSelectedHandle
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -139,19 +139,16 @@ class GuiProjectView(QWidget):
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
self.projBar.updateTheme()
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Initialise GUI elements that depend on specific settings."""
|
||||
self.projTree.initSettings()
|
||||
return
|
||||
|
||||
def closeProjectTasks(self) -> None:
|
||||
"""Clear project-related GUI content."""
|
||||
self.projBar.clearContent()
|
||||
self.projBar.setEnabled(False)
|
||||
self.projTree.clearTree()
|
||||
return
|
||||
|
||||
def openProjectTasks(self) -> None:
|
||||
"""Run open project tasks."""
|
||||
@@ -159,26 +156,23 @@ class GuiProjectView(QWidget):
|
||||
self.projBar.buildTemplatesMenu()
|
||||
self.projBar.buildQuickLinksMenu()
|
||||
self.projBar.setEnabled(True)
|
||||
return
|
||||
|
||||
def setTreeFocus(self) -> None:
|
||||
"""Forward the set focus call to the tree widget."""
|
||||
self.projTree.setFocus()
|
||||
return
|
||||
|
||||
def treeHasFocus(self) -> bool:
|
||||
"""Check if the project tree has focus."""
|
||||
return self.projTree.hasFocus()
|
||||
|
||||
def connectMenuActions(self, rename: QAction, delete: QAction, trash: QAction) -> None:
|
||||
"""Main menu actions passed to the project tree."""
|
||||
"""Connect main menu actions passed to the project tree."""
|
||||
self.projTree.addAction(rename)
|
||||
self.projTree.addAction(delete)
|
||||
self.projTree.addAction(trash)
|
||||
rename.triggered.connect(self.renameTreeItem)
|
||||
delete.triggered.connect(self.projTree.processDeleteRequest)
|
||||
trash.triggered.connect(self.projTree.emptyTrash)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -197,41 +191,36 @@ class GuiProjectView(QWidget):
|
||||
if dlgOk:
|
||||
nwItem.setName(newLabel)
|
||||
nwItem.notifyToRefresh()
|
||||
return
|
||||
|
||||
@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 setActiveHandle(self, tHandle: str | None) -> None:
|
||||
"""Highlight the active handle."""
|
||||
self.projTree.setActiveHandle(tHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str, Enum)
|
||||
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
|
||||
"""Refresh other content when project item changed."""
|
||||
self.projBar.processTemplateDocuments(tHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def createFileFromTemplate(self, tHandle: str) -> None:
|
||||
"""Create a new document from a template."""
|
||||
logger.debug("Template selected: '%s'", tHandle)
|
||||
self.projTree.newTreeItem(nwItemType.FILE, copyDoc=tHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str, Enum)
|
||||
def updateRootItem(self, tHandle: str, change: nwChange) -> None:
|
||||
"""Process root item changes."""
|
||||
self.projBar.buildQuickLinksMenu()
|
||||
return
|
||||
|
||||
|
||||
class GuiProjectToolBar(QWidget):
|
||||
"""GUI> Project View ToolBar."""
|
||||
|
||||
newDocumentFromTemplate = pyqtSignal(str)
|
||||
|
||||
@@ -351,8 +340,6 @@ class GuiProjectToolBar(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiProjectToolBar")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -383,13 +370,10 @@ class GuiProjectToolBar(QWidget):
|
||||
self.buildQuickLinksMenu()
|
||||
self._buildRootMenu()
|
||||
|
||||
return
|
||||
|
||||
def clearContent(self) -> None:
|
||||
"""Clear dynamic content on the tool bar."""
|
||||
self.mQuick.clear()
|
||||
self.mTemplates.clearMenu()
|
||||
return
|
||||
|
||||
def buildQuickLinksMenu(self) -> None:
|
||||
"""Build the quick link menu."""
|
||||
@@ -402,14 +386,12 @@ class GuiProjectToolBar(QWidget):
|
||||
action.triggered.connect(
|
||||
qtLambda(self.projView.setSelectedHandle, tHandle, doScroll=True)
|
||||
)
|
||||
return
|
||||
|
||||
def buildTemplatesMenu(self) -> None:
|
||||
"""Build the templates menu."""
|
||||
for tHandle, _ in SHARED.project.tree.iterRoots(nwItemClass.TEMPLATE):
|
||||
for dHandle in SHARED.project.tree.subTree(tHandle):
|
||||
self.processTemplateDocuments(dHandle)
|
||||
return
|
||||
|
||||
def processTemplateDocuments(self, tHandle: str) -> None:
|
||||
"""Process change in tree items to update menu content."""
|
||||
@@ -418,7 +400,6 @@ class GuiProjectToolBar(QWidget):
|
||||
self.mTemplates.addUpdate(tHandle, item.itemName, item.getMainIcon())
|
||||
elif tHandle in self.mTemplates:
|
||||
self.mTemplates.remove(tHandle)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -436,7 +417,6 @@ class GuiProjectToolBar(QWidget):
|
||||
self.aAddChap.setVisible(allowDoc)
|
||||
self.aAddPart.setVisible(allowDoc)
|
||||
self.aAddEmpty.setVisible(allowDoc)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -451,7 +431,6 @@ class GuiProjectToolBar(QWidget):
|
||||
qtLambda(self.projTree.newTreeItem, nwItemType.ROOT, itemClass)
|
||||
)
|
||||
self.mAddRoot.addAction(aNew)
|
||||
return
|
||||
|
||||
self.mAddRoot.clear()
|
||||
addClass(nwItemClass.NOVEL)
|
||||
@@ -467,10 +446,9 @@ class GuiProjectToolBar(QWidget):
|
||||
addClass(nwItemClass.ARCHIVE)
|
||||
addClass(nwItemClass.TEMPLATE)
|
||||
|
||||
return
|
||||
|
||||
|
||||
class GuiProjectTree(QTreeView):
|
||||
"""GUI: Project View Tree."""
|
||||
|
||||
def __init__(self, projView: GuiProjectView) -> None:
|
||||
super().__init__(parent=projView)
|
||||
@@ -520,8 +498,6 @@ class GuiProjectTree(QTreeView):
|
||||
|
||||
logger.debug("Ready: GuiProjectTree")
|
||||
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Set or update tree widget settings."""
|
||||
if CONFIG.hideVScroll:
|
||||
@@ -532,7 +508,6 @@ class GuiProjectTree(QTreeView):
|
||||
self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
|
||||
else:
|
||||
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
|
||||
return
|
||||
|
||||
##
|
||||
# External Methods
|
||||
@@ -541,7 +516,6 @@ class GuiProjectTree(QTreeView):
|
||||
def setActiveHandle(self, tHandle: str | None) -> None:
|
||||
"""Set the handle to be highlighted."""
|
||||
self._actHandle = tHandle
|
||||
return
|
||||
|
||||
def getSelectedHandle(self) -> str | None:
|
||||
"""Get the currently selected handle."""
|
||||
@@ -556,7 +530,6 @@ class GuiProjectTree(QTreeView):
|
||||
def clearTree(self) -> None:
|
||||
"""Clear the tree view."""
|
||||
self.setModel(None)
|
||||
return
|
||||
|
||||
def loadModel(self) -> None:
|
||||
"""Load and prepare a new project model."""
|
||||
@@ -583,8 +556,6 @@ class GuiProjectTree(QTreeView):
|
||||
|
||||
self.restoreExpandedState()
|
||||
|
||||
return
|
||||
|
||||
def restoreExpandedState(self) -> None:
|
||||
"""Expand all nodes that were previously expanded."""
|
||||
if model := self._getModel():
|
||||
@@ -592,7 +563,6 @@ class GuiProjectTree(QTreeView):
|
||||
for index in model.allExpanded():
|
||||
self.setExpanded(index, True)
|
||||
self.blockSignals(False)
|
||||
return
|
||||
|
||||
def setSelectedHandle(self, tHandle: str | None, doScroll: bool = False) -> None:
|
||||
"""Set a specific handle as the selected item."""
|
||||
@@ -601,7 +571,6 @@ class GuiProjectTree(QTreeView):
|
||||
if doScroll:
|
||||
self.scrollTo(index, QAbstractItemView.ScrollHint.PositionAtCenter)
|
||||
self.projView.selectedItemChanged.emit(tHandle)
|
||||
return
|
||||
|
||||
def newTreeItem(
|
||||
self, itemType: nwItemType, itemClass: nwItemClass | None = None,
|
||||
@@ -805,7 +774,6 @@ class GuiProjectTree(QTreeView):
|
||||
SHARED.warn(self.tr("Could not duplicate all items."))
|
||||
self.setEnabled(True)
|
||||
self.restoreExpandedState()
|
||||
return
|
||||
|
||||
##
|
||||
# Events and Overloads
|
||||
@@ -825,14 +793,12 @@ class GuiProjectTree(QTreeView):
|
||||
self.projView.openDocumentRequest.emit(
|
||||
node.item.itemHandle, nwDocMode.VIEW, "", False
|
||||
)
|
||||
return
|
||||
|
||||
def drawRow(self, painter: QPainter, opt: QStyleOptionViewItem, index: QModelIndex) -> None:
|
||||
"""Draw a box on the active row."""
|
||||
if (node := self._getNode(index)) and node.item.itemHandle == self._actHandle:
|
||||
painter.fillRect(opt.rect, self.palette().alternateBase())
|
||||
super().drawRow(painter, opt, index)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -843,14 +809,12 @@ class GuiProjectTree(QTreeView):
|
||||
"""Move an item up in the tree."""
|
||||
if model := self._getModel():
|
||||
model.internalMove(self.currentIndex(), -1)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def moveItemDown(self) -> None:
|
||||
"""Move an item down in the tree."""
|
||||
if model := self._getModel():
|
||||
model.internalMove(self.currentIndex(), 1)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def goToSiblingUp(self) -> None:
|
||||
@@ -858,7 +822,6 @@ class GuiProjectTree(QTreeView):
|
||||
if (node := self._getNode(self.currentIndex())) and (parent := node.parent()):
|
||||
if (move := parent.child(node.row() - 1)) and (model := self._getModel()):
|
||||
self.setCurrentIndex(model.indexFromNode(move))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def goToSiblingDown(self) -> None:
|
||||
@@ -866,7 +829,6 @@ class GuiProjectTree(QTreeView):
|
||||
if (node := self._getNode(self.currentIndex())) and (parent := node.parent()):
|
||||
if (move := parent.child(node.row() + 1)) and (model := self._getModel()):
|
||||
self.setCurrentIndex(model.indexFromNode(move))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def goToParent(self) -> None:
|
||||
@@ -877,7 +839,6 @@ class GuiProjectTree(QTreeView):
|
||||
and (parent := node.parent())
|
||||
):
|
||||
self.setCurrentIndex(model.indexFromNode(parent))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def goToFirstChild(self) -> None:
|
||||
@@ -888,13 +849,11 @@ class GuiProjectTree(QTreeView):
|
||||
and (child := node.child(0))
|
||||
):
|
||||
self.setCurrentIndex(model.indexFromNode(child))
|
||||
return
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def expandFromIndex(self, index: QModelIndex) -> None:
|
||||
"""Expand all nodes from index."""
|
||||
self.expandRecursively(index)
|
||||
return
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def collapseFromIndex(self, index: QModelIndex) -> None:
|
||||
@@ -902,7 +861,6 @@ class GuiProjectTree(QTreeView):
|
||||
if (model := self._getModel()) and (node := model.node(index)):
|
||||
for child in node.allChildren():
|
||||
self.setExpanded(model.indexFromNode(child), False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def processDeleteRequest(
|
||||
@@ -968,9 +926,7 @@ class GuiProjectTree(QTreeView):
|
||||
@pyqtSlot()
|
||||
@pyqtSlot("QPoint")
|
||||
def openContextMenu(self, point: QPoint | None = None) -> None:
|
||||
"""The user right clicked an element in the project tree, so we
|
||||
open a context menu in-place.
|
||||
"""
|
||||
"""Open a context menu in-place where the user clicked."""
|
||||
if model := self._getModel():
|
||||
if point is None:
|
||||
point = self.visualRect(self.currentIndex()).center()
|
||||
@@ -987,7 +943,6 @@ class GuiProjectTree(QTreeView):
|
||||
if viewport := self.viewport():
|
||||
ctxMenu.exec(viewport.mapToGlobal(point))
|
||||
ctxMenu.setParent(None)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -995,10 +950,9 @@ class GuiProjectTree(QTreeView):
|
||||
|
||||
@pyqtSlot(QModelIndex, QModelIndex)
|
||||
def _onSelectionChange(self, current: QModelIndex, previous: QModelIndex) -> None:
|
||||
"""The user changed which item is selected."""
|
||||
"""Process user changing which item is selected."""
|
||||
if node := self._getNode(current):
|
||||
self.projView.selectedItemChanged.emit(node.item.itemHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def _onDoubleClick(self, index: QModelIndex) -> None:
|
||||
@@ -1012,21 +966,18 @@ class GuiProjectTree(QTreeView):
|
||||
)
|
||||
else:
|
||||
self.setExpanded(index, not self.isExpanded(index))
|
||||
return
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def _onNodeCollapsed(self, index: QModelIndex) -> None:
|
||||
"""Capture a node collapse, and pass it to the model."""
|
||||
if node := self._getNode(index):
|
||||
node.setExpanded(False)
|
||||
return
|
||||
|
||||
@pyqtSlot(QModelIndex)
|
||||
def _onNodeExpanded(self, index: QModelIndex) -> None:
|
||||
"""Capture a node expand, and pass it to the model."""
|
||||
if node := self._getNode(index):
|
||||
node.setExpanded(True)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -1038,7 +989,6 @@ class GuiProjectTree(QTreeView):
|
||||
if model := self.selectionModel():
|
||||
# Selection model can be None (#2173)
|
||||
model.clearCurrentIndex()
|
||||
return
|
||||
|
||||
def _selectedRows(self) -> list[QModelIndex]:
|
||||
"""Return all column 0 indexes."""
|
||||
@@ -1066,7 +1016,6 @@ class _UpdatableMenu(QMenu):
|
||||
self._map: dict[str, QAction] = {}
|
||||
self.setTitle(self.tr("From Template"))
|
||||
self.triggered.connect(self._actionTriggered)
|
||||
return
|
||||
|
||||
def __contains__(self, tHandle: str) -> bool:
|
||||
"""Look up a handle in the menu."""
|
||||
@@ -1088,7 +1037,6 @@ class _UpdatableMenu(QMenu):
|
||||
self.addAction(action)
|
||||
self._map[tHandle] = action
|
||||
self.setActionsVisible(True)
|
||||
return
|
||||
|
||||
def remove(self, tHandle: str) -> None:
|
||||
"""Remove a template item."""
|
||||
@@ -1096,19 +1044,16 @@ class _UpdatableMenu(QMenu):
|
||||
self.removeAction(action)
|
||||
if not self._map:
|
||||
self.setActionsVisible(False)
|
||||
return
|
||||
|
||||
def clearMenu(self) -> None:
|
||||
"""Clear all menu content."""
|
||||
self._map.clear()
|
||||
self.clear()
|
||||
return
|
||||
|
||||
def setActionsVisible(self, value: bool) -> None:
|
||||
"""Set the visibility of root action."""
|
||||
if action := self.menuAction():
|
||||
action.setVisible(value)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -1118,7 +1063,6 @@ class _UpdatableMenu(QMenu):
|
||||
def _actionTriggered(self, action: QAction) -> None:
|
||||
"""Translate the menu trigger into an item trigger."""
|
||||
self.menuItemTriggered.emit(str(action.data()))
|
||||
return
|
||||
|
||||
|
||||
class _TreeContextMenu(QMenu):
|
||||
@@ -1139,11 +1083,9 @@ class _TreeContextMenu(QMenu):
|
||||
self._indices = indices
|
||||
self._children = node.childCount() > 0
|
||||
logger.debug("Ready: _TreeContextMenu")
|
||||
return
|
||||
|
||||
def __del__(self) -> None: # pragma: no cover
|
||||
logger.debug("Delete: _TreeContextMenu")
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
@@ -1155,7 +1097,6 @@ class _TreeContextMenu(QMenu):
|
||||
action.triggered.connect(self._tree.emptyTrash)
|
||||
if self._children:
|
||||
self._expandCollapse()
|
||||
return
|
||||
|
||||
def buildSingleSelectMenu(self) -> None:
|
||||
"""Build the single-select menu."""
|
||||
@@ -1191,15 +1132,12 @@ class _TreeContextMenu(QMenu):
|
||||
action.triggered.connect(qtLambda(self._tree.duplicateFromHandle, self._handle))
|
||||
self._deleteOrTrash()
|
||||
|
||||
return
|
||||
|
||||
def buildMultiSelectMenu(self) -> None:
|
||||
"""Build the multi-select menu."""
|
||||
self._itemActive()
|
||||
self._itemStatusImport(True)
|
||||
self.addSeparator()
|
||||
self._deleteOrTrash()
|
||||
return
|
||||
|
||||
##
|
||||
# Menu Builders
|
||||
@@ -1217,7 +1155,6 @@ class _TreeContextMenu(QMenu):
|
||||
self._view.openDocumentRequest.emit,
|
||||
self._handle, nwDocMode.VIEW, "", False
|
||||
))
|
||||
return
|
||||
|
||||
def _itemCreation(self) -> None:
|
||||
"""Add create item actions."""
|
||||
@@ -1228,7 +1165,6 @@ class _TreeContextMenu(QMenu):
|
||||
menu.addAction(self._view.projBar.aAddEmpty)
|
||||
menu.addAction(self._view.projBar.aAddNote)
|
||||
menu.addAction(self._view.projBar.aAddFolder)
|
||||
return
|
||||
|
||||
def _itemHeader(self) -> None:
|
||||
"""Check if there is a header that can be used for rename."""
|
||||
@@ -1238,7 +1174,6 @@ class _TreeContextMenu(QMenu):
|
||||
action.triggered.connect(
|
||||
qtLambda(self._view.renameTreeItem, self._handle, hItem.title)
|
||||
)
|
||||
return
|
||||
|
||||
def _itemActive(self) -> None:
|
||||
"""Add Active/Inactive actions."""
|
||||
@@ -1253,7 +1188,6 @@ class _TreeContextMenu(QMenu):
|
||||
else:
|
||||
action = qtAddAction(self, self.tr("Toggle Active"))
|
||||
action.triggered.connect(self._toggleItemActive)
|
||||
return
|
||||
|
||||
def _itemStatusImport(self, multi: bool) -> None:
|
||||
"""Add actions for changing status or importance."""
|
||||
@@ -1295,7 +1229,6 @@ class _TreeContextMenu(QMenu):
|
||||
self._view.projectSettingsRequest.emit,
|
||||
GuiProjectSettings.PAGE_IMPORT
|
||||
))
|
||||
return
|
||||
|
||||
def _itemTransform(self, isFile: bool, isFolder: bool) -> None:
|
||||
"""Add actions for the Transform menu."""
|
||||
@@ -1338,15 +1271,12 @@ class _TreeContextMenu(QMenu):
|
||||
action = qtAddAction(menu, self.tr("Split Document by Headings"))
|
||||
action.triggered.connect(qtLambda(self._tree.splitDocument, self._handle))
|
||||
|
||||
return
|
||||
|
||||
def _expandCollapse(self) -> None:
|
||||
"""Add actions for expand and collapse."""
|
||||
action = qtAddAction(self, self.tr("Expand All"))
|
||||
action.triggered.connect(qtLambda(self._tree.expandFromIndex, self._indices[0]))
|
||||
action = qtAddAction(self, self.tr("Collapse All"))
|
||||
action.triggered.connect(qtLambda(self._tree.collapseFromIndex, self._indices[0]))
|
||||
return
|
||||
|
||||
def _deleteOrTrash(self) -> None:
|
||||
"""Add move to Trash action."""
|
||||
@@ -1359,7 +1289,6 @@ class _TreeContextMenu(QMenu):
|
||||
text = self.tr("Move to Trash")
|
||||
action = qtAddAction(self, text)
|
||||
action.triggered.connect(self._tree.processDeleteRequest)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -1371,7 +1300,6 @@ class _TreeContextMenu(QMenu):
|
||||
if self._item.isFileType():
|
||||
self._item.setActive(not self._item.isActive)
|
||||
self._item.notifyToRefresh()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -1385,13 +1313,11 @@ class _TreeContextMenu(QMenu):
|
||||
node.item.setActive(state)
|
||||
refresh.append(node.item.itemHandle)
|
||||
SHARED.project.tree.refreshItems(refresh)
|
||||
return
|
||||
|
||||
def _changeItemStatus(self, key: str) -> None:
|
||||
"""Set a new status value of an item."""
|
||||
self._item.setStatus(key)
|
||||
self._item.notifyToRefresh()
|
||||
return
|
||||
|
||||
def _iterSetItemStatus(self, key: str) -> None:
|
||||
"""Change the status value for multiple items."""
|
||||
@@ -1401,13 +1327,11 @@ class _TreeContextMenu(QMenu):
|
||||
node.item.setStatus(key)
|
||||
refresh.append(node.item.itemHandle)
|
||||
SHARED.project.tree.refreshItems(refresh)
|
||||
return
|
||||
|
||||
def _changeItemImport(self, key: str) -> None:
|
||||
"""Set a new importance value of an item."""
|
||||
self._item.setImport(key)
|
||||
self._item.notifyToRefresh()
|
||||
return
|
||||
|
||||
def _iterSetItemImport(self, key: str) -> None:
|
||||
"""Change the status value for multiple items."""
|
||||
@@ -1417,7 +1341,6 @@ class _TreeContextMenu(QMenu):
|
||||
node.item.setImport(key)
|
||||
refresh.append(node.item.itemHandle)
|
||||
SHARED.project.tree.refreshItems(refresh)
|
||||
return
|
||||
|
||||
def _changeItemLayout(self, itemLayout: nwItemLayout) -> None:
|
||||
"""Set a new item layout value of an item."""
|
||||
@@ -1428,7 +1351,6 @@ class _TreeContextMenu(QMenu):
|
||||
elif itemLayout == nwItemLayout.NOTE:
|
||||
self._item.setLayout(nwItemLayout.NOTE)
|
||||
self._item.notifyToRefresh()
|
||||
return
|
||||
|
||||
def _convertFolderToFile(self, itemLayout: nwItemLayout) -> None:
|
||||
"""Convert a folder to a note or document."""
|
||||
@@ -1448,4 +1370,3 @@ class _TreeContextMenu(QMenu):
|
||||
self._item.notifyToRefresh()
|
||||
else:
|
||||
logger.info("Folder conversion cancelled")
|
||||
return
|
||||
|
||||
@@ -20,7 +20,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -50,6 +50,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiProjectSearch(QWidget):
|
||||
"""GUI: Project Search Panel."""
|
||||
|
||||
C_NAME = 0
|
||||
C_RESULT = 0
|
||||
@@ -151,8 +152,6 @@ class GuiProjectSearch(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiProjectSearch")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -174,8 +173,6 @@ class GuiProjectSearch(QWidget):
|
||||
self.toggleWord.setIcon(SHARED.theme.getIcon("search_word"))
|
||||
self.toggleRegEx.setIcon(SHARED.theme.getIcon("search_regex"))
|
||||
|
||||
return
|
||||
|
||||
def processReturn(self) -> None:
|
||||
"""Process a return keypress forwarded from the main GUI."""
|
||||
if self.searchText.hasFocus():
|
||||
@@ -189,7 +186,6 @@ class GuiProjectSearch(QWidget):
|
||||
self.openDocumentSelectRequest.emit(
|
||||
str(data[0]), checkInt(data[1], -1), checkInt(data[2], -1), False
|
||||
)
|
||||
return
|
||||
|
||||
def beginSearch(self, text: str = "") -> None:
|
||||
"""Focus the search box and select its text, if any."""
|
||||
@@ -198,20 +194,17 @@ class GuiProjectSearch(QWidget):
|
||||
if text:
|
||||
self.searchText.setText(text.partition("\n")[0])
|
||||
self.searchText.selectAll()
|
||||
return
|
||||
|
||||
def closeProjectTasks(self) -> None:
|
||||
"""Run close project tasks."""
|
||||
self._map = {}
|
||||
self.searchText.clear()
|
||||
self.searchResult.clear()
|
||||
return
|
||||
|
||||
def refreshCurrentSearch(self) -> None:
|
||||
"""Refresh the search if there is one."""
|
||||
if self.searchResult.topLevelItemCount() > 0:
|
||||
self._processSearch()
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
@@ -238,7 +231,6 @@ class GuiProjectSearch(QWidget):
|
||||
self.searchText.setFocus()
|
||||
else:
|
||||
super().keyPressEvent(event)
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -252,7 +244,6 @@ class GuiProjectSearch(QWidget):
|
||||
results, capped = self._search.searchText(SHARED.mainGui.docEditor.getText())
|
||||
self._displayResultSet(SHARED.project.tree[tHandle], results, capped)
|
||||
logger.debug("Updated search for '%s' in %.3f ms", tHandle, 1000*(time() - start))
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -278,7 +269,6 @@ class GuiProjectSearch(QWidget):
|
||||
self._time = time()
|
||||
QApplication.restoreOverrideCursor()
|
||||
self._blocked = False
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _searchResultSelected(self) -> None:
|
||||
@@ -288,7 +278,6 @@ class GuiProjectSearch(QWidget):
|
||||
self.selectedItemChanged.emit(str(data[0]))
|
||||
elif data := items[0].data(0, self.D_HANDLE):
|
||||
self.selectedItemChanged.emit(str(data))
|
||||
return
|
||||
|
||||
@pyqtSlot("QTreeWidgetItem*", int)
|
||||
def _searchResultDoubleClicked(self, item: QTreeWidgetItem, column: int) -> None:
|
||||
@@ -297,28 +286,24 @@ class GuiProjectSearch(QWidget):
|
||||
self.openDocumentSelectRequest.emit(
|
||||
str(data[0]), checkInt(data[1], -1), checkInt(data[2], -1), True
|
||||
)
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _toggleCase(self, state: bool) -> None:
|
||||
"""Enable/disable case sensitive mode."""
|
||||
CONFIG.searchProjCase = state
|
||||
self.refreshCurrentSearch()
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _toggleWord(self, state: bool) -> None:
|
||||
"""Enable/disable whole word search mode."""
|
||||
CONFIG.searchProjWord = state
|
||||
self.refreshCurrentSearch()
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _toggleRegEx(self, state: bool) -> None:
|
||||
"""Enable/disable regular expression search mode."""
|
||||
CONFIG.searchProjRegEx = state
|
||||
self.refreshCurrentSearch()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -360,5 +345,3 @@ class GuiProjectSearch(QWidget):
|
||||
self.searchResult.setFirstColumnSpanned(i, parent, True)
|
||||
|
||||
QApplication.processEvents()
|
||||
|
||||
return
|
||||
|
||||
@@ -20,7 +20,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -45,6 +45,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiSideBar(QWidget):
|
||||
"""GUI: Main Window SideBar."""
|
||||
|
||||
requestViewChange = pyqtSignal(nwView)
|
||||
|
||||
@@ -126,8 +127,6 @@ class GuiSideBar(QWidget):
|
||||
|
||||
logger.debug("Ready: GuiSideBar")
|
||||
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Initialise GUI elements that depend on specific settings."""
|
||||
buttonStyle = SHARED.theme.getStyleSheet(STYLES_BIG_TOOLBUTTON)
|
||||
@@ -153,8 +152,6 @@ class GuiSideBar(QWidget):
|
||||
|
||||
self._setThemeModeIcon()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
@@ -171,7 +168,6 @@ class GuiSideBar(QWidget):
|
||||
CONFIG.themeMode = nwTheme.AUTO
|
||||
self.mainGui.checkThemeUpdate()
|
||||
self._setThemeModeIcon()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -181,7 +177,6 @@ class GuiSideBar(QWidget):
|
||||
"""Set the theme button icon."""
|
||||
self.tbTheme.setThemeIcon(nwLabels.THEME_MODE_ICON[CONFIG.themeMode])
|
||||
self.tbTheme.setToolTip(trConst(nwLabels.THEME_MODE_LABEL[CONFIG.themeMode]))
|
||||
return
|
||||
|
||||
|
||||
class _PopRightMenu(QMenu):
|
||||
|
||||
@@ -20,7 +20,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -41,6 +41,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiMainStatus(QStatusBar):
|
||||
"""GUI: Main Window Status Bar."""
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
@@ -112,8 +113,6 @@ class GuiMainStatus(QStatusBar):
|
||||
self.updateTheme()
|
||||
self.clearStatus()
|
||||
|
||||
return
|
||||
|
||||
def initSettings(self) -> None:
|
||||
"""Apply user settings."""
|
||||
if CONFIG.useCharCount:
|
||||
@@ -122,7 +121,6 @@ class GuiMainStatus(QStatusBar):
|
||||
else:
|
||||
self._trStatsCount = trStats(nwLabels.STATS_DISPLAY[nwStats.WORDS])
|
||||
self._trStatsTip = self.tr("Total word count (session change)")
|
||||
return
|
||||
|
||||
def clearStatus(self) -> None:
|
||||
"""Reset all widgets on the status bar to default values."""
|
||||
@@ -132,7 +130,6 @@ class GuiMainStatus(QStatusBar):
|
||||
self.setProjectStatus(None)
|
||||
self.setDocumentStatus(None)
|
||||
self.updateTime()
|
||||
return
|
||||
|
||||
def updateTheme(self) -> None:
|
||||
"""Update theme elements."""
|
||||
@@ -149,8 +146,6 @@ class GuiMainStatus(QStatusBar):
|
||||
self.docIcon.setColors(colNone, colSaved, colUnsaved)
|
||||
self.projIcon.setColors(colNone, colSaved, colUnsaved)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
@@ -158,17 +153,14 @@ class GuiMainStatus(QStatusBar):
|
||||
def setRefTime(self, refTime: float) -> None:
|
||||
"""Set the reference time for the status bar clock."""
|
||||
self._refTime = refTime
|
||||
return
|
||||
|
||||
def setProjectStatus(self, state: bool | None) -> None:
|
||||
"""Set the project status colour icon."""
|
||||
self.projIcon.setState(state)
|
||||
return
|
||||
|
||||
def setDocumentStatus(self, state: bool | None) -> None:
|
||||
"""Set the document status colour icon."""
|
||||
self.docIcon.setState(state)
|
||||
return
|
||||
|
||||
def setUserIdle(self, idle: bool) -> None:
|
||||
"""Change the idle status icon."""
|
||||
@@ -180,13 +172,11 @@ class GuiMainStatus(QStatusBar):
|
||||
else:
|
||||
self.timeIcon.setPixmap(self.timePixmap)
|
||||
self._userIdle = idle
|
||||
return
|
||||
|
||||
def setProjectStats(self, pWC: int, sWC: int) -> None:
|
||||
"""Update the current project statistics."""
|
||||
self.statsText.setText(self._trStatsCount.format(f"{pWC:n}", f"{sWC:+n}"))
|
||||
self.statsText.setToolTip(self._trStatsTip)
|
||||
return
|
||||
|
||||
def updateTime(self, idleTime: float = 0.0) -> None:
|
||||
"""Update the session clock."""
|
||||
@@ -198,7 +188,6 @@ class GuiMainStatus(QStatusBar):
|
||||
else:
|
||||
sessTime = round(time() - self._refTime)
|
||||
self.timeText.setText(formatTime(sessTime))
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
@@ -209,7 +198,6 @@ class GuiMainStatus(QStatusBar):
|
||||
"""Set the status bar message to display."""
|
||||
self.showMessage(message, nwConst.STATUS_MSG_TIMEOUT)
|
||||
QApplication.processEvents()
|
||||
return
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def setLanguage(self, language: str, provider: str) -> None:
|
||||
@@ -220,19 +208,16 @@ class GuiMainStatus(QStatusBar):
|
||||
else:
|
||||
self.langText.setText(QLocale(language).nativeLanguageName().title())
|
||||
self.langText.setToolTip(f"{language} ({provider})" if provider else language)
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def updateProjectStatus(self, status: bool) -> None:
|
||||
"""Update the project status."""
|
||||
self.setProjectStatus(not status)
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def updateDocumentStatus(self, status: bool) -> None:
|
||||
"""Update the document status."""
|
||||
self.setDocumentStatus(not status)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
@@ -244,7 +229,6 @@ class GuiMainStatus(QStatusBar):
|
||||
state = not CONFIG.showSessionTime
|
||||
self.timeText.setVisible(state)
|
||||
CONFIG.showSessionTime = state
|
||||
return
|
||||
|
||||
##
|
||||
# Debug
|
||||
@@ -279,4 +263,3 @@ class GuiMainStatus(QStatusBar):
|
||||
)
|
||||
self.showMessage(f"Debug [{stamp}] {message}", 6000)
|
||||
logger.debug("[MEMINFO] %s", message)
|
||||
return
|
||||
|
||||
@@ -21,7 +21,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/>.
|
||||
"""
|
||||
""" # noqa
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -58,6 +58,7 @@ STYLES_BIG_TOOLBUTTON = "bigToolButton"
|
||||
|
||||
@dataclass
|
||||
class ThemeEntry:
|
||||
"""Theme data."""
|
||||
|
||||
name: str
|
||||
dark: bool
|
||||
@@ -65,6 +66,7 @@ class ThemeEntry:
|
||||
|
||||
|
||||
class ThemeMeta:
|
||||
"""Theme meta data."""
|
||||
|
||||
name: str = ""
|
||||
mode: str = ""
|
||||
@@ -74,6 +76,7 @@ class ThemeMeta:
|
||||
|
||||
|
||||
class IconsMeta:
|
||||
"""Icon theme meta data."""
|
||||
|
||||
name: str = ""
|
||||
author: str = ""
|
||||
@@ -81,6 +84,7 @@ class IconsMeta:
|
||||
|
||||
|
||||
class SyntaxColors:
|
||||
"""Colours for the syntax highlighter."""
|
||||
|
||||
back: QColor = QColor(255, 255, 255)
|
||||
text: QColor = QColor(0, 0, 0)
|
||||
@@ -106,7 +110,7 @@ class SyntaxColors:
|
||||
|
||||
|
||||
class GuiTheme:
|
||||
"""Gui Theme Class
|
||||
"""Gui Theme Class.
|
||||
|
||||
Handles the look and feel of novelWriter.
|
||||
"""
|
||||
@@ -190,8 +194,6 @@ class GuiTheme:
|
||||
logger.debug("Text 'N' Height: %d", self.textNHeight)
|
||||
logger.debug("Text 'N' Width: %d", self.textNWidth)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
@@ -206,7 +208,7 @@ class GuiTheme:
|
||||
##
|
||||
|
||||
def getTextWidth(self, text: str, font: QFont | None = None) -> int:
|
||||
"""Returns the width needed to contain a given piece of text in
|
||||
"""Return the width needed to contain a given piece of text in
|
||||
pixels.
|
||||
"""
|
||||
if isinstance(font, QFont):
|
||||
@@ -238,8 +240,6 @@ class GuiTheme:
|
||||
self.iconCache.initIcons()
|
||||
self.loadTheme()
|
||||
|
||||
return
|
||||
|
||||
def isDesktopDarkMode(self) -> bool:
|
||||
"""Check if the desktop is in dark mode."""
|
||||
if CONFIG.verQtValue >= 0x060500 and (hint := QGuiApplication.styleHints()):
|
||||
@@ -507,7 +507,6 @@ class GuiTheme:
|
||||
"""Set the colour for a named colour."""
|
||||
self._qColors[key] = QColor(color)
|
||||
self._svgColors[key] = color.name(QColor.NameFormat.HexRgb).encode("utf-8")
|
||||
return
|
||||
|
||||
def _resetTheme(self) -> None:
|
||||
"""Reset GUI colours to default values."""
|
||||
@@ -559,8 +558,6 @@ class GuiTheme:
|
||||
self._setBaseColor("inactive", red)
|
||||
self._setBaseColor("disabled", faded)
|
||||
|
||||
return
|
||||
|
||||
def _readColor(self, parser: ConfigParser, section: str, name: str) -> QColor:
|
||||
"""Parse a colour value from a config string."""
|
||||
return self.parseColor(parser.get(section, name, fallback="default"))
|
||||
@@ -570,7 +567,6 @@ class GuiTheme:
|
||||
) -> None:
|
||||
"""Set a palette colour value from a config string."""
|
||||
self._guiPalette.setBrush(value, self._readColor(parser, section, name))
|
||||
return
|
||||
|
||||
def _buildStyleSheets(self, palette: QPalette) -> None:
|
||||
"""Build default style sheets."""
|
||||
@@ -602,8 +598,6 @@ class GuiTheme:
|
||||
"QToolButton::menu-indicator {image: none;} "
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def _scanThemes(self, files: list[Path]) -> None:
|
||||
"""Scan the GUI themes folder and list all themes."""
|
||||
parser = ConfigParser()
|
||||
@@ -631,8 +625,6 @@ class GuiTheme:
|
||||
logger.debug("Checking theme config '%s'", key)
|
||||
self._allThemes[key] = ThemeEntry(name, dark, item)
|
||||
|
||||
return
|
||||
|
||||
|
||||
class GuiIcons:
|
||||
"""The icon class manages the content of the assets/icons folder,
|
||||
@@ -672,8 +664,6 @@ class GuiIcons:
|
||||
# None Icon
|
||||
self._noIcon = QIcon(str(CONFIG.assetPath("icons") / "none.svg"))
|
||||
|
||||
return
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Clear the icon cache."""
|
||||
self._svgData = {}
|
||||
@@ -681,7 +671,6 @@ class GuiIcons:
|
||||
self._headerDec = []
|
||||
self._headerDecNarrow = []
|
||||
self._meta = ThemeMeta()
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
@@ -703,7 +692,6 @@ class GuiIcons:
|
||||
_listContent(icons, CONFIG.assetPath("icons"), ".icons")
|
||||
_listContent(icons, CONFIG.dataPath("icons"), ".icons")
|
||||
self._scanThemes(icons)
|
||||
return
|
||||
|
||||
def loadTheme(self, theme: str) -> None:
|
||||
"""Update the theme map. This is more of an init, since many of
|
||||
@@ -781,7 +769,7 @@ class GuiIcons:
|
||||
self, tType: nwItemType, tClass: nwItemClass, tLayout: nwItemLayout, hLevel: str = "H0"
|
||||
) -> QIcon:
|
||||
"""Get the correct icon for a project item based on type, class
|
||||
and heading level
|
||||
and heading level.
|
||||
"""
|
||||
name = None
|
||||
color = "default"
|
||||
@@ -942,8 +930,6 @@ class GuiIcons:
|
||||
logger.debug("Checking icon theme '%s'", key)
|
||||
self._allThemes[key] = ThemeEntry(name, False, item)
|
||||
|
||||
return
|
||||
|
||||
|
||||
# Module Functions
|
||||
# ================
|
||||
@@ -952,4 +938,3 @@ def _listContent(data: list[Path], path: Path, extension: str) -> None:
|
||||
"""List files of a specific type and extend the list."""
|
||||
if path.is_dir():
|
||||
data.extend(n for n in path.iterdir() if n.is_file() and n.suffix == extension)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user