Merge branch 'main' into merge_patches
This commit is contained in:
@@ -23,12 +23,12 @@ from novelwriter.gui.doceditor import GuiDocEditor
|
||||
from novelwriter.gui.docviewer import GuiDocViewer, GuiDocViewDetails
|
||||
from novelwriter.gui.itemdetails import GuiItemDetails
|
||||
from novelwriter.gui.mainmenu import GuiMainMenu
|
||||
from novelwriter.gui.noveltree import GuiNovelTree
|
||||
from novelwriter.gui.outline import GuiOutline
|
||||
from novelwriter.gui.outlinedetails import GuiOutlineDetails
|
||||
from novelwriter.gui.projtree import GuiProjectTree
|
||||
from novelwriter.gui.noveltree import GuiNovelView
|
||||
from novelwriter.gui.outline import GuiOutlineView
|
||||
from novelwriter.gui.projtree import GuiProjectView
|
||||
from novelwriter.gui.statusbar import GuiMainStatus
|
||||
from novelwriter.gui.theme import GuiTheme
|
||||
from novelwriter.gui.viewsbar import GuiViewsBar
|
||||
|
||||
__all__ = [
|
||||
"GuiDocEditor",
|
||||
@@ -37,9 +37,9 @@ __all__ = [
|
||||
"GuiItemDetails",
|
||||
"GuiMainMenu",
|
||||
"GuiMainStatus",
|
||||
"GuiNovelTree",
|
||||
"GuiOutline",
|
||||
"GuiOutlineDetails",
|
||||
"GuiProjectTree",
|
||||
"GuiNovelView",
|
||||
"GuiOutlineView",
|
||||
"GuiProjectView",
|
||||
"GuiTheme",
|
||||
"GuiViewsBar",
|
||||
]
|
||||
|
||||
@@ -376,8 +376,8 @@ class QSwitch(QAbstractButton):
|
||||
|
||||
class PagedDialog(QDialog):
|
||||
|
||||
def __init__(self, theParent=None):
|
||||
QDialog.__init__(self, parent=theParent)
|
||||
def __init__(self, parent=None):
|
||||
QDialog.__init__(self, parent=parent)
|
||||
|
||||
self._tabBar = VerticalTabBar(self)
|
||||
self._tabBar.setExpanding(False)
|
||||
@@ -409,10 +409,10 @@ class PagedDialog(QDialog):
|
||||
|
||||
return
|
||||
|
||||
def addTab(self, tabWidget, tabLabel):
|
||||
def addTab(self, widget, label):
|
||||
"""Forwards the adding of tabs to the QTabWidget.
|
||||
"""
|
||||
self._tabBox.addTab(tabWidget, tabLabel)
|
||||
self._tabBox.addTab(widget, label)
|
||||
return
|
||||
|
||||
def addControls(self, buttonBar):
|
||||
@@ -426,20 +426,20 @@ class PagedDialog(QDialog):
|
||||
|
||||
class VerticalTabBar(QTabBar):
|
||||
|
||||
def __init__(self, theParent=None):
|
||||
QTabBar.__init__(self, parent=theParent)
|
||||
def __init__(self, parent=None):
|
||||
QTabBar.__init__(self, parent=parent)
|
||||
self._mW = novelwriter.CONFIG.pxInt(150)
|
||||
return
|
||||
|
||||
def tabSizeHint(self, theIndex):
|
||||
def tabSizeHint(self, index):
|
||||
"""Returns a transposed size hint for the rotated bar.
|
||||
"""
|
||||
tSize = QTabBar.tabSizeHint(self, theIndex)
|
||||
tSize = QTabBar.tabSizeHint(self, index)
|
||||
tSize.transpose()
|
||||
tSize.setWidth(min(tSize.width(), self._mW))
|
||||
return tSize
|
||||
|
||||
def paintEvent(self, theEvent):
|
||||
def paintEvent(self, event):
|
||||
"""Custom implementation of the label painter that rotates the
|
||||
label 90 degrees.
|
||||
"""
|
||||
|
||||
+115
-114
@@ -33,6 +33,7 @@ import bisect
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from enum import Enum
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
@@ -50,7 +51,7 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter.core import NWDoc, NWSpellEnchant, countWords
|
||||
from novelwriter.enum import nwAlert, nwDocAction, nwDocInsert, nwItemClass
|
||||
from novelwriter.enum import nwAlert, nwDocAction, nwDocInsert, nwDocMode
|
||||
from novelwriter.common import transferCase
|
||||
from novelwriter.constants import nwConst, nwKeyWords, nwUnicode
|
||||
from novelwriter.gui.dochighlight import GuiDocHighlighter
|
||||
@@ -69,18 +70,18 @@ class GuiDocEditor(QTextEdit):
|
||||
spellDictionaryChanged = pyqtSignal(str, str)
|
||||
docEditedStatusChanged = pyqtSignal(bool)
|
||||
docCountsChanged = pyqtSignal(str, int, int, int)
|
||||
loadDocumentTagRequest = pyqtSignal(str, Enum)
|
||||
|
||||
def __init__(self, theParent):
|
||||
QTextEdit.__init__(self, theParent)
|
||||
def __init__(self, mainGui):
|
||||
QTextEdit.__init__(self, mainGui)
|
||||
|
||||
logger.debug("Initialising GuiDocEditor ...")
|
||||
|
||||
# Class Variables
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theTheme = theParent.theTheme
|
||||
self.theIndex = theParent.theIndex
|
||||
self.theProject = theParent.theProject
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
|
||||
self._nwDocument = None
|
||||
self._nwItem = None
|
||||
@@ -123,7 +124,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
# Syntax
|
||||
self.spEnchant = NWSpellEnchant()
|
||||
self.highLight = GuiDocHighlighter(qDoc, self.theParent, self.spEnchant)
|
||||
self.highLight = GuiDocHighlighter(qDoc, self.mainGui, self.spEnchant)
|
||||
|
||||
# Context Menu
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
@@ -131,8 +132,9 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
# Editor Settings
|
||||
self.setMinimumWidth(self.mainConf.pxInt(300))
|
||||
self.setAutoFillBackground(True)
|
||||
self.setAcceptRichText(False)
|
||||
self.setAutoFillBackground(True)
|
||||
self.setFrameStyle(QFrame.NoFrame)
|
||||
|
||||
# Custom Shortcuts
|
||||
QShortcut(
|
||||
@@ -237,10 +239,10 @@ class GuiDocEditor(QTextEdit):
|
||||
if self.mainConf.textFont is None:
|
||||
# If none is defined, set a default font
|
||||
theFont = QFont()
|
||||
if self.mainConf.osWindows and "Arial" in self.theTheme.guiFontDB.families():
|
||||
if self.mainConf.osWindows and "Arial" in self.mainTheme.guiFontDB.families():
|
||||
theFont.setFamily("Arial")
|
||||
theFont.setPointSize(12)
|
||||
elif self.mainConf.osDarwin and "Courier" in self.theTheme.guiFontDB.families():
|
||||
elif self.mainConf.osDarwin and "Courier" in self.mainTheme.guiFontDB.families():
|
||||
theFont.setFamily("Courier")
|
||||
theFont.setPointSize(12)
|
||||
else:
|
||||
@@ -255,14 +257,14 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
# Set the widget colours to match syntax theme
|
||||
mainPalette = self.palette()
|
||||
mainPalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
self.setPalette(mainPalette)
|
||||
|
||||
docPalette = self.viewport().palette()
|
||||
docPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
self.viewport().setPalette(docPalette)
|
||||
|
||||
self.docHeader.matchColours()
|
||||
@@ -339,7 +341,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
docSize = len(theDoc)
|
||||
if docSize > nwConst.MAX_DOCSIZE:
|
||||
self.theParent.makeAlert(self.tr(
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"The document you are trying to open is too big. "
|
||||
"The document size is {0} MB. "
|
||||
"The maximum size allowed is {1} MB."
|
||||
@@ -400,7 +402,7 @@ class GuiDocEditor(QTextEdit):
|
||||
self.document().rootFrame().setFrameFormat(docFrame)
|
||||
|
||||
self.docFooter.updateLineCount()
|
||||
self._docHeaders = self.theIndex.getHandleHeaders(self._docHandle)
|
||||
self._docHeaders = self.theProject.index.getHandleHeaders(self._docHandle)
|
||||
|
||||
qApp.processEvents()
|
||||
self.document().clearUndoRedoStacks()
|
||||
@@ -415,7 +417,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
# Update the status bar
|
||||
if self._nwItem is not None:
|
||||
self.theParent.setStatus(
|
||||
self.mainGui.setStatus(
|
||||
self.tr("Opened Document: {0}").format(self._nwItem.itemName)
|
||||
)
|
||||
|
||||
@@ -440,7 +442,7 @@ class GuiDocEditor(QTextEdit):
|
||||
"""
|
||||
docSize = len(theText)
|
||||
if docSize > nwConst.MAX_DOCSIZE:
|
||||
self.theParent.makeAlert(self.tr(
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"The text you are trying to add is too big. "
|
||||
"The text size is {0} MB. "
|
||||
"The maximum size allowed is {1} MB."
|
||||
@@ -486,7 +488,7 @@ class GuiDocEditor(QTextEdit):
|
||||
if not self._nwDocument.writeDocument(docText):
|
||||
saveOk = False
|
||||
if self._nwDocument._currHash != self._nwDocument._prevHash:
|
||||
msgYes = self.theParent.askQuestion(
|
||||
msgYes = self.mainGui.askQuestion(
|
||||
self.tr("File Changed on Disk"),
|
||||
self.tr(
|
||||
"This document has been changed outside of novelWriter "
|
||||
@@ -497,7 +499,7 @@ class GuiDocEditor(QTextEdit):
|
||||
saveOk = self._nwDocument.writeDocument(docText, forceWrite=True)
|
||||
|
||||
if not saveOk:
|
||||
self.theParent.makeAlert([
|
||||
self.mainGui.makeAlert([
|
||||
self.tr("Could not save document."), self._nwDocument.getError()
|
||||
], nwAlert.ERROR)
|
||||
|
||||
@@ -505,22 +507,24 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
self.setDocumentChanged(False)
|
||||
|
||||
oldHeader = self.theIndex.getHandleHeaderLevel(tHandle)
|
||||
self.theIndex.scanText(tHandle, docText)
|
||||
newHeader = self.theIndex.getHandleHeaderLevel(tHandle)
|
||||
oldHeader = self.theProject.index.getHandleHeaderLevel(tHandle)
|
||||
self.theProject.index.scanText(tHandle, docText)
|
||||
newHeader = self.theProject.index.getHandleHeaderLevel(tHandle)
|
||||
|
||||
# ToDo: This should be a signal
|
||||
if self._updateHeaders(checkLevel=True):
|
||||
self.theParent.requestNovelTreeRefresh()
|
||||
self.mainGui.requestNovelTreeRefresh()
|
||||
else:
|
||||
self.theParent.novelView.updateWordCounts(tHandle)
|
||||
self.mainGui.novelView.updateWordCounts(tHandle)
|
||||
|
||||
# ToDo: This should be a signal
|
||||
if oldHeader != newHeader:
|
||||
self.theParent.treeView.setTreeItemValues(tHandle)
|
||||
self.theParent.treeMeta.updateViewBox(tHandle)
|
||||
self.mainGui.projView.setTreeItemValues(tHandle)
|
||||
self.mainGui.itemDetails.updateViewBox(tHandle)
|
||||
self.docFooter.updateInfo()
|
||||
|
||||
# Update the status bar
|
||||
self.theParent.setStatus(
|
||||
self.mainGui.setStatus(
|
||||
self.tr("Saved Document: {0}").format(self._nwItem.itemName)
|
||||
)
|
||||
|
||||
@@ -542,8 +546,8 @@ class GuiDocEditor(QTextEdit):
|
||||
sH = hBar.height() if hBar.isVisible() else 0
|
||||
|
||||
tM = cM
|
||||
if self.mainConf.textWidth > 0 or self.theParent.isFocusMode:
|
||||
tW = self.mainConf.getTextWidth(self.theParent.isFocusMode)
|
||||
if self.mainConf.textWidth > 0 or self.mainGui.isFocusMode:
|
||||
tW = self.mainConf.getTextWidth(self.mainGui.isFocusMode)
|
||||
tM = max((wW - sW - tW)//2, cM)
|
||||
|
||||
tB = self.frameWidth()
|
||||
@@ -567,16 +571,6 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
return
|
||||
|
||||
def updateDocInfo(self, tHandle):
|
||||
"""Called when an item label is changed to check if the document
|
||||
title bar needs updating,
|
||||
"""
|
||||
if tHandle == self._docHandle:
|
||||
self.docHeader.setTitleFromHandle(self._docHandle)
|
||||
self.docFooter.updateInfo()
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
@@ -712,7 +706,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
if not self.mainConf.hasEnchant:
|
||||
if theMode:
|
||||
self.theParent.makeAlert(self.tr(
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Spell checking requires the package PyEnchant. "
|
||||
"It does not appear to be installed."
|
||||
), nwAlert.INFO)
|
||||
@@ -722,7 +716,7 @@ class GuiDocEditor(QTextEdit):
|
||||
theMode = False
|
||||
|
||||
self._spellCheck = theMode
|
||||
self.theParent.mainMenu.setSpellCheck(theMode)
|
||||
self.mainGui.mainMenu.setSpellCheck(theMode)
|
||||
self.theProject.setSpellCheck(theMode)
|
||||
self.highLight.setSpellCheck(theMode)
|
||||
if not self._bigDoc:
|
||||
@@ -750,7 +744,7 @@ class GuiDocEditor(QTextEdit):
|
||||
qApp.restoreOverrideCursor()
|
||||
afTime = time()
|
||||
logger.debug("Document highlighted in %.3f ms", 1000*(afTime-bfTime))
|
||||
self.theParent.statusBar.setStatus(self.tr("Spell check complete"))
|
||||
self.mainGui.statusBar.setStatus(self.tr("Spell check complete"))
|
||||
|
||||
return True
|
||||
|
||||
@@ -1066,7 +1060,22 @@ class GuiDocEditor(QTextEdit):
|
||||
return
|
||||
|
||||
##
|
||||
# Slots
|
||||
# Public Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateDocInfo(self, tHandle):
|
||||
"""Called when an item label is changed to check if the document
|
||||
title bar needs updating,
|
||||
"""
|
||||
if tHandle == self._docHandle:
|
||||
self.docHeader.setTitleFromHandle(self._docHandle)
|
||||
self.docFooter.updateInfo()
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(int, int, int)
|
||||
@@ -1078,7 +1087,7 @@ class GuiDocEditor(QTextEdit):
|
||||
self._lastFind = None
|
||||
|
||||
if self.document().characterCount() > nwConst.MAX_DOCSIZE:
|
||||
self.theParent.makeAlert(self.tr(
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"The document has grown too big and you cannot add more text to it. "
|
||||
"The maximum size of a single novelWriter document is {0} MB."
|
||||
).format(
|
||||
@@ -1238,7 +1247,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
if time() - self._lastEdit < 5 * self.wcInterval:
|
||||
logger.verbose("Running word counter")
|
||||
self.theParent.threadPool.start(self.wCounterDoc)
|
||||
self.mainGui.threadPool.start(self.wCounterDoc)
|
||||
|
||||
return
|
||||
|
||||
@@ -1295,7 +1304,7 @@ class GuiDocEditor(QTextEdit):
|
||||
logger.verbose("Selection word counter is busy")
|
||||
return
|
||||
|
||||
self.theParent.threadPool.start(self.wCounterSel)
|
||||
self.mainGui.threadPool.start(self.wCounterSel)
|
||||
|
||||
return
|
||||
|
||||
@@ -1374,7 +1383,7 @@ class GuiDocEditor(QTextEdit):
|
||||
self.docSearch.setResultCount(0, 0)
|
||||
self._lastFind = None
|
||||
if self.docSearch.doNextFile and not goBack:
|
||||
self.theParent.openNextDocument(
|
||||
self.mainGui.openNextDocument(
|
||||
self._docHandle, wrapAround=self.docSearch.doLoop
|
||||
)
|
||||
self.beginSearch()
|
||||
@@ -1394,7 +1403,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
if resIdx > maxIdx:
|
||||
if self.docSearch.doNextFile and not goBack:
|
||||
self.theParent.openNextDocument(
|
||||
self.mainGui.openNextDocument(
|
||||
self._docHandle, wrapAround=self.docSearch.doLoop
|
||||
)
|
||||
self.beginSearch()
|
||||
@@ -1638,7 +1647,7 @@ class GuiDocEditor(QTextEdit):
|
||||
"""
|
||||
theCursor = self.textCursor()
|
||||
if not theCursor.hasSelection():
|
||||
self.theParent.makeAlert(self.tr(
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Please select some text before calling replace quotes."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
@@ -1894,7 +1903,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
if loadTag:
|
||||
logger.verbose("Attempting to follow tag '%s'", theWord)
|
||||
self.theParent.docViewer.loadFromTag(theWord)
|
||||
self.loadDocumentTagRequest.emit(theWord, nwDocMode.VIEW)
|
||||
else:
|
||||
logger.verbose("Potential tag '%s'", theWord)
|
||||
|
||||
@@ -2018,7 +2027,7 @@ class GuiDocEditor(QTextEdit):
|
||||
if self._docHandle is None:
|
||||
return False
|
||||
|
||||
newHeaders = self.theIndex.getHandleHeaders(self._docHandle)
|
||||
newHeaders = self.theProject.index.getHandleHeaders(self._docHandle)
|
||||
if checkPos:
|
||||
newPos = [x[0] for x in newHeaders]
|
||||
oldPos = [x[0] for x in self._docHeaders]
|
||||
@@ -2196,9 +2205,9 @@ class GuiDocEditSearch(QFrame):
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.docEditor = docEditor
|
||||
self.theParent = docEditor.theParent
|
||||
self.mainGui = docEditor.mainGui
|
||||
self.theProject = docEditor.theProject
|
||||
self.theTheme = docEditor.theTheme
|
||||
self.mainTheme = docEditor.mainTheme
|
||||
|
||||
self.repVisible = False
|
||||
self.isCaseSense = self.mainConf.searchCase
|
||||
@@ -2209,9 +2218,9 @@ class GuiDocEditSearch(QFrame):
|
||||
self.doMatchCap = self.mainConf.searchMatchCap
|
||||
|
||||
mPx = self.mainConf.pxInt(6)
|
||||
tPx = int(0.8*self.theTheme.fontPixelSize)
|
||||
self.boxFont = self.theTheme.guiFont
|
||||
self.boxFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
|
||||
tPx = int(0.8*self.mainTheme.fontPixelSize)
|
||||
self.boxFont = self.mainTheme.guiFont
|
||||
self.boxFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setAutoFillBackground(True)
|
||||
@@ -2245,38 +2254,38 @@ class GuiDocEditSearch(QFrame):
|
||||
|
||||
self.resultLabel = QLabel("?/?")
|
||||
self.resultLabel.setFont(self.boxFont)
|
||||
self.resultLabel.setMinimumWidth(self.theTheme.getTextWidth("?/?", self.boxFont))
|
||||
self.resultLabel.setMinimumWidth(self.mainTheme.getTextWidth("?/?", self.boxFont))
|
||||
|
||||
self.toggleCase = QAction(self.tr("Case Sensitive"), self)
|
||||
self.toggleCase.setIcon(self.theTheme.getIcon("search_case"))
|
||||
self.toggleCase.setIcon(self.mainTheme.getIcon("search_case"))
|
||||
self.toggleCase.setCheckable(True)
|
||||
self.toggleCase.setChecked(self.isCaseSense)
|
||||
self.toggleCase.toggled.connect(self._doToggleCase)
|
||||
self.searchOpt.addAction(self.toggleCase)
|
||||
|
||||
self.toggleWord = QAction(self.tr("Whole Words Only"), self)
|
||||
self.toggleWord.setIcon(self.theTheme.getIcon("search_word"))
|
||||
self.toggleWord.setIcon(self.mainTheme.getIcon("search_word"))
|
||||
self.toggleWord.setCheckable(True)
|
||||
self.toggleWord.setChecked(self.isWholeWord)
|
||||
self.toggleWord.toggled.connect(self._doToggleWord)
|
||||
self.searchOpt.addAction(self.toggleWord)
|
||||
|
||||
self.toggleRegEx = QAction(self.tr("RegEx Mode"), self)
|
||||
self.toggleRegEx.setIcon(self.theTheme.getIcon("search_regex"))
|
||||
self.toggleRegEx.setIcon(self.mainTheme.getIcon("search_regex"))
|
||||
self.toggleRegEx.setCheckable(True)
|
||||
self.toggleRegEx.setChecked(self.isRegEx)
|
||||
self.toggleRegEx.toggled.connect(self._doToggleRegEx)
|
||||
self.searchOpt.addAction(self.toggleRegEx)
|
||||
|
||||
self.toggleLoop = QAction(self.tr("Loop Search"), self)
|
||||
self.toggleLoop.setIcon(self.theTheme.getIcon("search_loop"))
|
||||
self.toggleLoop.setIcon(self.mainTheme.getIcon("search_loop"))
|
||||
self.toggleLoop.setCheckable(True)
|
||||
self.toggleLoop.setChecked(self.doLoop)
|
||||
self.toggleLoop.toggled.connect(self._doToggleLoop)
|
||||
self.searchOpt.addAction(self.toggleLoop)
|
||||
|
||||
self.toggleProject = QAction(self.tr("Search Next File"), self)
|
||||
self.toggleProject.setIcon(self.theTheme.getIcon("search_project"))
|
||||
self.toggleProject.setIcon(self.mainTheme.getIcon("search_project"))
|
||||
self.toggleProject.setCheckable(True)
|
||||
self.toggleProject.setChecked(self.doNextFile)
|
||||
self.toggleProject.toggled.connect(self._doToggleProject)
|
||||
@@ -2285,7 +2294,7 @@ class GuiDocEditSearch(QFrame):
|
||||
self.searchOpt.addSeparator()
|
||||
|
||||
self.toggleMatchCap = QAction(self.tr("Preserve Case"), self)
|
||||
self.toggleMatchCap.setIcon(self.theTheme.getIcon("search_preserve"))
|
||||
self.toggleMatchCap.setIcon(self.mainTheme.getIcon("search_preserve"))
|
||||
self.toggleMatchCap.setCheckable(True)
|
||||
self.toggleMatchCap.setChecked(self.doMatchCap)
|
||||
self.toggleMatchCap.toggled.connect(self._doToggleMatchCap)
|
||||
@@ -2294,7 +2303,7 @@ class GuiDocEditSearch(QFrame):
|
||||
self.searchOpt.addSeparator()
|
||||
|
||||
self.cancelSearch = QAction(self.tr("Close Search"), self)
|
||||
self.cancelSearch.setIcon(self.theTheme.getIcon("search_cancel"))
|
||||
self.cancelSearch.setIcon(self.mainTheme.getIcon("search_cancel"))
|
||||
self.cancelSearch.triggered.connect(self._doClose)
|
||||
self.searchOpt.addAction(self.cancelSearch)
|
||||
|
||||
@@ -2309,12 +2318,12 @@ class GuiDocEditSearch(QFrame):
|
||||
self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
|
||||
self.showReplace.toggled.connect(self._doToggleReplace)
|
||||
|
||||
self.searchButton = QPushButton(self.theTheme.getIcon("search"), "")
|
||||
self.searchButton = QPushButton(self.mainTheme.getIcon("search"), "")
|
||||
self.searchButton.setFixedSize(QSize(bPx, bPx))
|
||||
self.searchButton.setToolTip(self.tr("Find in current document"))
|
||||
self.searchButton.clicked.connect(self._doSearch)
|
||||
|
||||
self.replaceButton = QPushButton(self.theTheme.getIcon("search_replace"), "")
|
||||
self.replaceButton = QPushButton(self.mainTheme.getIcon("search_replace"), "")
|
||||
self.replaceButton.setFixedSize(QSize(bPx, bPx))
|
||||
self.replaceButton.setToolTip(self.tr("Find and replace in current document"))
|
||||
self.replaceButton.clicked.connect(self._doReplace)
|
||||
@@ -2433,7 +2442,7 @@ class GuiDocEditSearch(QFrame):
|
||||
"""
|
||||
currRes = "?" if currRes is None else currRes
|
||||
resCount = "?" if resCount is None else "1000+" if resCount > 1000 else resCount
|
||||
minWidth = self.theTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
|
||||
minWidth = self.mainTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
|
||||
self.resultLabel.setText(f"{currRes}/{resCount}")
|
||||
self.resultLabel.setMinimumWidth(minWidth)
|
||||
self.adjustSize()
|
||||
@@ -2584,13 +2593,13 @@ class GuiDocEditHeader(QWidget):
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.docEditor = docEditor
|
||||
self.theParent = docEditor.theParent
|
||||
self.mainGui = docEditor.mainGui
|
||||
self.theProject = docEditor.theProject
|
||||
self.theTheme = docEditor.theTheme
|
||||
self.mainTheme = docEditor.mainTheme
|
||||
|
||||
self._docHandle = None
|
||||
|
||||
fPx = int(0.9*self.theTheme.fontPixelSize)
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
hSp = self.mainConf.pxInt(6)
|
||||
|
||||
# Main Widget Settings
|
||||
@@ -2607,17 +2616,17 @@ class GuiDocEditHeader(QWidget):
|
||||
self.theTitle.setFixedHeight(fPx)
|
||||
|
||||
lblFont = self.theTitle.font()
|
||||
lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
self.theTitle.setFont(lblFont)
|
||||
|
||||
buttonStyle = (
|
||||
"QToolButton {{border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
||||
).format(*self.theTheme.colText)
|
||||
).format(*self.mainTheme.colText)
|
||||
|
||||
# Buttons
|
||||
self.editButton = QToolButton(self)
|
||||
self.editButton.setIcon(self.theTheme.getIcon("edit"))
|
||||
self.editButton.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.editButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.editButton.setIconSize(QSize(fPx, fPx))
|
||||
self.editButton.setFixedSize(fPx, fPx)
|
||||
@@ -2628,7 +2637,7 @@ class GuiDocEditHeader(QWidget):
|
||||
self.editButton.clicked.connect(self._editDocument)
|
||||
|
||||
self.searchButton = QToolButton(self)
|
||||
self.searchButton.setIcon(self.theTheme.getIcon("search"))
|
||||
self.searchButton.setIcon(self.mainTheme.getIcon("search"))
|
||||
self.searchButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.searchButton.setIconSize(QSize(fPx, fPx))
|
||||
self.searchButton.setFixedSize(fPx, fPx)
|
||||
@@ -2639,7 +2648,7 @@ class GuiDocEditHeader(QWidget):
|
||||
self.searchButton.clicked.connect(self._searchDocument)
|
||||
|
||||
self.minmaxButton = QToolButton(self)
|
||||
self.minmaxButton.setIcon(self.theTheme.getIcon("maximise"))
|
||||
self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
|
||||
self.minmaxButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.minmaxButton.setIconSize(QSize(fPx, fPx))
|
||||
self.minmaxButton.setFixedSize(fPx, fPx)
|
||||
@@ -2650,7 +2659,7 @@ class GuiDocEditHeader(QWidget):
|
||||
self.minmaxButton.clicked.connect(self._minmaxDocument)
|
||||
|
||||
self.closeButton = QToolButton(self)
|
||||
self.closeButton.setIcon(self.theTheme.getIcon("close"))
|
||||
self.closeButton.setIcon(self.mainTheme.getIcon("close"))
|
||||
self.closeButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.closeButton.setIconSize(QSize(fPx, fPx))
|
||||
self.closeButton.setFixedSize(fPx, fPx)
|
||||
@@ -2693,9 +2702,9 @@ class GuiDocEditHeader(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.theTitle.setPalette(thePalette)
|
||||
@@ -2717,15 +2726,15 @@ class GuiDocEditHeader(QWidget):
|
||||
|
||||
if self.mainConf.showFullPath:
|
||||
tTitle = []
|
||||
tTree = self.theProject.projTree.getItemPath(tHandle)
|
||||
tTree = self.theProject.tree.getItemPath(tHandle)
|
||||
for aHandle in reversed(tTree):
|
||||
nwItem = self.theProject.projTree[aHandle]
|
||||
nwItem = self.theProject.tree[aHandle]
|
||||
if nwItem is not None:
|
||||
tTitle.append(nwItem.itemName)
|
||||
sSep = " %s " % nwUnicode.U_RSAQUO
|
||||
self.theTitle.setText(sSep.join(tTitle))
|
||||
else:
|
||||
nwItem = self.theProject.projTree[tHandle]
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
if nwItem is None:
|
||||
return False
|
||||
self.theTitle.setText(nwItem.itemName)
|
||||
@@ -2742,10 +2751,10 @@ class GuiDocEditHeader(QWidget):
|
||||
This function is called by the GuiMain class via the
|
||||
toggleFocusMode function and should not be activated directly.
|
||||
"""
|
||||
if self.theParent.isFocusMode:
|
||||
self.minmaxButton.setIcon(self.theTheme.getIcon("minimise"))
|
||||
if self.mainGui.isFocusMode:
|
||||
self.minmaxButton.setIcon(self.mainTheme.getIcon("minimise"))
|
||||
else:
|
||||
self.minmaxButton.setIcon(self.theTheme.getIcon("maximise"))
|
||||
self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
|
||||
return
|
||||
|
||||
##
|
||||
@@ -2755,7 +2764,7 @@ class GuiDocEditHeader(QWidget):
|
||||
def _editDocument(self):
|
||||
"""Open the edit item dialog from the main GUI.
|
||||
"""
|
||||
self.theParent.editItem(self._docHandle)
|
||||
self.mainGui.editItemLabel(self._docHandle)
|
||||
return
|
||||
|
||||
def _searchDocument(self):
|
||||
@@ -2767,7 +2776,7 @@ class GuiDocEditHeader(QWidget):
|
||||
def _closeDocument(self):
|
||||
"""Trigger the close editor on the main window.
|
||||
"""
|
||||
self.theParent.closeDocEditor()
|
||||
self.mainGui.closeDocEditor()
|
||||
self.editButton.setVisible(False)
|
||||
self.searchButton.setVisible(False)
|
||||
self.closeButton.setVisible(False)
|
||||
@@ -2777,7 +2786,7 @@ class GuiDocEditHeader(QWidget):
|
||||
def _minmaxDocument(self):
|
||||
"""Switch on or off Focus Mode.
|
||||
"""
|
||||
self.theParent.toggleFocusMode()
|
||||
self.mainGui.toggleFocusMode()
|
||||
return
|
||||
|
||||
##
|
||||
@@ -2788,7 +2797,7 @@ class GuiDocEditHeader(QWidget):
|
||||
"""Capture a click on the title and ensure that the item is
|
||||
selected in the project tree.
|
||||
"""
|
||||
self.theParent.treeView.setSelectedHandle(self._docHandle, doScroll=True)
|
||||
self.mainGui.projView.setSelectedHandle(self._docHandle, doScroll=True)
|
||||
return
|
||||
|
||||
# END Class GuiDocEditHeader
|
||||
@@ -2808,23 +2817,22 @@ class GuiDocEditFooter(QWidget):
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.docEditor = docEditor
|
||||
self.theParent = docEditor.theParent
|
||||
self.mainGui = docEditor.mainGui
|
||||
self.theProject = docEditor.theProject
|
||||
self.theTheme = docEditor.theTheme
|
||||
self.optState = docEditor.theProject.optState
|
||||
self.mainTheme = docEditor.mainTheme
|
||||
|
||||
self._theItem = None
|
||||
self._docHandle = None
|
||||
|
||||
self._docSelection = False
|
||||
|
||||
self.sPx = int(round(0.9*self.theTheme.baseIconSize))
|
||||
fPx = int(0.9*self.theTheme.fontPixelSize)
|
||||
self.sPx = int(round(0.9*self.mainTheme.baseIconSize))
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
bSp = self.mainConf.pxInt(4)
|
||||
hSp = self.mainConf.pxInt(6)
|
||||
|
||||
lblFont = self.font()
|
||||
lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
|
||||
# Main Widget Settings
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -2847,7 +2855,7 @@ class GuiDocEditFooter(QWidget):
|
||||
|
||||
# Lines
|
||||
self.linesIcon = QLabel("")
|
||||
self.linesIcon.setPixmap(self.theTheme.getPixmap("status_lines", (self.sPx, self.sPx)))
|
||||
self.linesIcon.setPixmap(self.mainTheme.getPixmap("status_lines", (self.sPx, self.sPx)))
|
||||
self.linesIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.linesIcon.setFixedHeight(self.sPx)
|
||||
self.linesIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
@@ -2863,7 +2871,7 @@ class GuiDocEditFooter(QWidget):
|
||||
|
||||
# Words
|
||||
self.wordsIcon = QLabel("")
|
||||
self.wordsIcon.setPixmap(self.theTheme.getPixmap("status_stats", (self.sPx, self.sPx)))
|
||||
self.wordsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (self.sPx, self.sPx)))
|
||||
self.wordsIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.wordsIcon.setFixedHeight(self.sPx)
|
||||
self.wordsIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
@@ -2915,9 +2923,9 @@ class GuiDocEditFooter(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.statusText.setPalette(thePalette)
|
||||
@@ -2934,7 +2942,7 @@ class GuiDocEditFooter(QWidget):
|
||||
logger.verbose("No handle set, so clearing the editor footer")
|
||||
self._theItem = None
|
||||
else:
|
||||
self._theItem = self.theProject.projTree[self._docHandle]
|
||||
self._theItem = self.theProject.tree[self._docHandle]
|
||||
|
||||
self.setHasSelection(False)
|
||||
self.updateInfo()
|
||||
@@ -2956,17 +2964,10 @@ class GuiDocEditFooter(QWidget):
|
||||
sIcon = QPixmap()
|
||||
sText = ""
|
||||
else:
|
||||
iStatus = self._theItem.itemStatus
|
||||
if self._theItem.itemClass == nwItemClass.NOVEL:
|
||||
iStatus = self.theProject.statusItems.checkEntry(iStatus)
|
||||
theIcon = self.theParent.statusIcons[iStatus]
|
||||
else:
|
||||
iStatus = self.theProject.importItems.checkEntry(iStatus)
|
||||
theIcon = self.theParent.importIcons[iStatus]
|
||||
|
||||
theStatus, theIcon = self._theItem.getImportStatus()
|
||||
sIcon = theIcon.pixmap(self.sPx, self.sPx)
|
||||
hLevel = self.theParent.theIndex.getHandleHeaderLevel(self._docHandle)
|
||||
sText = f"{self._theItem.itemStatus} / {self._theItem.describeMe(hLevel)}"
|
||||
hLevel = self.theProject.index.getHandleHeaderLevel(self._docHandle)
|
||||
sText = f"{theStatus} / {self._theItem.describeMe(hLevel)}"
|
||||
|
||||
self.statusIcon.setPixmap(sIcon)
|
||||
self.statusText.setText(sText)
|
||||
|
||||
@@ -46,16 +46,16 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
BLOCK_META = 2
|
||||
BLOCK_TITLE = 4
|
||||
|
||||
def __init__(self, theDoc, theParent, spEnchant):
|
||||
def __init__(self, theDoc, mainGui, spEnchant):
|
||||
QSyntaxHighlighter.__init__(self, theDoc)
|
||||
|
||||
logger.debug("Initialising GuiDocHighlighter ...")
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theDoc = theDoc
|
||||
self.spEnchant = spEnchant
|
||||
self.theParent = theParent
|
||||
self.theTheme = theParent.theTheme
|
||||
self.theIndex = theParent.theIndex
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.theHandle = None
|
||||
self.spellCheck = False
|
||||
self.spellRx = None
|
||||
@@ -87,24 +87,24 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
"""
|
||||
logger.debug("Setting up highlighting rules")
|
||||
|
||||
self.colHead = QColor(*self.theTheme.colHead)
|
||||
self.colHeadH = QColor(*self.theTheme.colHeadH)
|
||||
self.colDialN = QColor(*self.theTheme.colDialN)
|
||||
self.colDialD = QColor(*self.theTheme.colDialD)
|
||||
self.colDialS = QColor(*self.theTheme.colDialS)
|
||||
self.colHidden = QColor(*self.theTheme.colHidden)
|
||||
self.colKey = QColor(*self.theTheme.colKey)
|
||||
self.colVal = QColor(*self.theTheme.colVal)
|
||||
self.colSpell = QColor(*self.theTheme.colSpell)
|
||||
self.colError = QColor(*self.theTheme.colError)
|
||||
self.colRepTag = QColor(*self.theTheme.colRepTag)
|
||||
self.colMod = QColor(*self.theTheme.colMod)
|
||||
self.colBreak = QColor(*self.theTheme.colEmph)
|
||||
self.colHead = QColor(*self.mainTheme.colHead)
|
||||
self.colHeadH = QColor(*self.mainTheme.colHeadH)
|
||||
self.colDialN = QColor(*self.mainTheme.colDialN)
|
||||
self.colDialD = QColor(*self.mainTheme.colDialD)
|
||||
self.colDialS = QColor(*self.mainTheme.colDialS)
|
||||
self.colHidden = QColor(*self.mainTheme.colHidden)
|
||||
self.colKey = QColor(*self.mainTheme.colKey)
|
||||
self.colVal = QColor(*self.mainTheme.colVal)
|
||||
self.colSpell = QColor(*self.mainTheme.colSpell)
|
||||
self.colError = QColor(*self.mainTheme.colError)
|
||||
self.colRepTag = QColor(*self.mainTheme.colRepTag)
|
||||
self.colMod = QColor(*self.mainTheme.colMod)
|
||||
self.colBreak = QColor(*self.mainTheme.colEmph)
|
||||
self.colBreak.setAlpha(64)
|
||||
|
||||
self.colEmph = None
|
||||
if self.mainConf.highlightEmph:
|
||||
self.colEmph = QColor(*self.theTheme.colEmph)
|
||||
self.colEmph = QColor(*self.mainTheme.colEmph)
|
||||
|
||||
self.hStyles = {
|
||||
"header1": self._makeFormat(self.colHead, "bold", 1.8),
|
||||
@@ -287,9 +287,10 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
|
||||
if theText.startswith("@"): # Keywords and commands
|
||||
self.setCurrentBlockState(self.BLOCK_META)
|
||||
tItem = self.theParent.theProject.projTree[self.theHandle]
|
||||
isValid, theBits, thePos = self.theIndex.scanThis(theText)
|
||||
isGood = self.theIndex.checkThese(theBits, tItem)
|
||||
pIndex = self.theProject.index
|
||||
tItem = self.mainGui.theProject.tree[self.theHandle]
|
||||
isValid, theBits, thePos = pIndex.scanThis(theText)
|
||||
isGood = pIndex.checkThese(theBits, tItem)
|
||||
if isValid:
|
||||
for n, theBit in enumerate(theBits):
|
||||
xPos = thePos[n]
|
||||
|
||||
+102
-115
@@ -30,17 +30,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from PyQt5.QtCore import Qt, QUrl, QSize, pyqtSlot
|
||||
from enum import Enum
|
||||
|
||||
from PyQt5.QtCore import Qt, QUrl, QSize, pyqtSlot, pyqtSignal
|
||||
from PyQt5.QtGui import (
|
||||
QTextOption, QFont, QPalette, QColor, QTextCursor, QIcon, QCursor
|
||||
)
|
||||
from PyQt5.QtWidgets import (
|
||||
qApp, QTextBrowser, QWidget, QScrollArea, QLabel, QHBoxLayout, QToolButton,
|
||||
QAction, QMenu
|
||||
QAction, QMenu, QFrame
|
||||
)
|
||||
|
||||
from novelwriter.core import ToHtml
|
||||
from novelwriter.enum import nwAlert, nwItemType, nwDocAction
|
||||
from novelwriter.enum import nwItemType, nwDocAction, nwDocMode
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.constants import nwUnicode
|
||||
|
||||
@@ -49,16 +51,18 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiDocViewer(QTextBrowser):
|
||||
|
||||
def __init__(self, theParent):
|
||||
QTextBrowser.__init__(self, theParent)
|
||||
loadDocumentTagRequest = pyqtSignal(str, Enum)
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QTextBrowser.__init__(self, mainGui)
|
||||
|
||||
logger.debug("Initialising GuiDocViewer ...")
|
||||
|
||||
# Class Variables
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theTheme = theParent.theTheme
|
||||
self.theProject = theParent.theProject
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
|
||||
# Internal Variables
|
||||
self._docHandle = None
|
||||
@@ -68,6 +72,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.setAutoFillBackground(True)
|
||||
self.setOpenExternalLinks(False)
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
self.setFrameStyle(QFrame.NoFrame)
|
||||
|
||||
# Document Header and Footer
|
||||
self.docHeader = GuiDocViewHeader(self)
|
||||
@@ -113,14 +118,14 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
# Set the widget colours to match syntax theme
|
||||
mainPalette = self.palette()
|
||||
mainPalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
self.setPalette(mainPalette)
|
||||
|
||||
docPalette = self.viewport().palette()
|
||||
docPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
self.viewport().setPalette(docPalette)
|
||||
|
||||
self.docHeader.matchColours()
|
||||
@@ -159,7 +164,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
def loadText(self, tHandle, updateHistory=True):
|
||||
"""Load text into the viewer from an item handle.
|
||||
"""
|
||||
if not self.theProject.projTree.checkType(tHandle, nwItemType.FILE):
|
||||
if not self.theProject.tree.checkType(tHandle, nwItemType.FILE):
|
||||
logger.warning("Item not found")
|
||||
return False
|
||||
|
||||
@@ -216,7 +221,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.updateDocMargins()
|
||||
|
||||
# Make sure the main GUI knows we changed the content
|
||||
self.theParent.viewMeta.refreshReferences(tHandle)
|
||||
self.mainGui.viewMeta.refreshReferences(tHandle)
|
||||
|
||||
# Since we change the content while it may still be rendering, we mark
|
||||
# the document dirty again to make sure it's re-rendered properly.
|
||||
@@ -238,30 +243,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
def loadFromTag(self, theTag):
|
||||
"""Load text in the document from a reference given by a meta
|
||||
tag rather than a known handle. This function depends on the
|
||||
index being up to date.
|
||||
"""
|
||||
logger.debug("Loading document from tag '%s'", theTag)
|
||||
tHandle, _, sTitle = self.theParent.theIndex.getTagSource(theTag)
|
||||
if tHandle is None:
|
||||
self.theParent.makeAlert(self.tr(
|
||||
"Could not find the reference for tag '{0}'. It either doesn't "
|
||||
"exist, or the index is out of date. The index can be updated "
|
||||
"from the Tools menu, or by pressing {1}."
|
||||
).format(
|
||||
theTag, "F9"
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
else:
|
||||
# Let the parent handle the opening as it also ensures that
|
||||
# the doc view panel is visible in case this request comes
|
||||
# from outside this class.
|
||||
logger.verbose("Tag points to '%s#%s'", tHandle, sTitle)
|
||||
self.theParent.viewDocument(tHandle, "#%s" % sTitle)
|
||||
return True
|
||||
|
||||
def docAction(self, theAction):
|
||||
"""Wrapper function for various document actions on the current
|
||||
document.
|
||||
@@ -341,15 +322,6 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
return
|
||||
|
||||
def updateDocInfo(self, tHandle):
|
||||
"""Called when an item label is changed to check if the document
|
||||
title bar needs updating,
|
||||
"""
|
||||
if tHandle == self._docHandle:
|
||||
self.docHeader.setTitleFromHandle(self._docHandle)
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
@@ -408,19 +380,33 @@ class GuiDocViewer(QTextBrowser):
|
||||
return 0
|
||||
|
||||
##
|
||||
# Slots
|
||||
# Public Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateDocInfo(self, tHandle):
|
||||
"""Called when an item label is changed to check if the document
|
||||
title bar needs updating,
|
||||
"""
|
||||
if tHandle == self._docHandle:
|
||||
self.docHeader.setTitleFromHandle(self._docHandle)
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot("QUrl")
|
||||
def _linkClicked(self, theURL):
|
||||
"""Slot for a link in the document being clicked.
|
||||
"""Process a clicked link internally in the document.
|
||||
"""
|
||||
theLink = theURL.url()
|
||||
logger.verbose("Clicked link: '%s'", theLink)
|
||||
if len(theLink) > 0:
|
||||
theBits = theLink.split("=")
|
||||
if len(theBits) == 2:
|
||||
self.loadFromTag(theBits[1])
|
||||
self.loadDocumentTagRequest.emit(theBits[1], nwDocMode.VIEW)
|
||||
return
|
||||
|
||||
@pyqtSlot("QPoint")
|
||||
@@ -553,27 +539,27 @@ class GuiDocViewer(QTextBrowser):
|
||||
" text-align: center;"
|
||||
"}}\n"
|
||||
).format(
|
||||
tColR=self.theTheme.colText[0],
|
||||
tColG=self.theTheme.colText[1],
|
||||
tColB=self.theTheme.colText[2],
|
||||
hColR=self.theTheme.colHead[0],
|
||||
hColG=self.theTheme.colHead[1],
|
||||
hColB=self.theTheme.colHead[2],
|
||||
aColR=self.theTheme.colVal[0],
|
||||
aColG=self.theTheme.colVal[1],
|
||||
aColB=self.theTheme.colVal[2],
|
||||
eColR=self.theTheme.colEmph[0],
|
||||
eColG=self.theTheme.colEmph[1],
|
||||
eColB=self.theTheme.colEmph[2],
|
||||
kColR=self.theTheme.colKey[0],
|
||||
kColG=self.theTheme.colKey[1],
|
||||
kColB=self.theTheme.colKey[2],
|
||||
cColR=self.theTheme.colHidden[0],
|
||||
cColG=self.theTheme.colHidden[1],
|
||||
cColB=self.theTheme.colHidden[2],
|
||||
mColR=self.theTheme.colMod[0],
|
||||
mColG=self.theTheme.colMod[1],
|
||||
mColB=self.theTheme.colMod[2],
|
||||
tColR=self.mainTheme.colText[0],
|
||||
tColG=self.mainTheme.colText[1],
|
||||
tColB=self.mainTheme.colText[2],
|
||||
hColR=self.mainTheme.colHead[0],
|
||||
hColG=self.mainTheme.colHead[1],
|
||||
hColB=self.mainTheme.colHead[2],
|
||||
aColR=self.mainTheme.colVal[0],
|
||||
aColG=self.mainTheme.colVal[1],
|
||||
aColB=self.mainTheme.colVal[2],
|
||||
eColR=self.mainTheme.colEmph[0],
|
||||
eColG=self.mainTheme.colEmph[1],
|
||||
eColB=self.mainTheme.colEmph[2],
|
||||
kColR=self.mainTheme.colKey[0],
|
||||
kColG=self.mainTheme.colKey[1],
|
||||
kColB=self.mainTheme.colKey[2],
|
||||
cColR=self.mainTheme.colHidden[0],
|
||||
cColG=self.mainTheme.colHidden[1],
|
||||
cColB=self.mainTheme.colHidden[2],
|
||||
mColR=self.mainTheme.colMod[0],
|
||||
mColG=self.mainTheme.colMod[1],
|
||||
mColB=self.mainTheme.colMod[2],
|
||||
)
|
||||
self.document().setDefaultStyleSheet(styleSheet)
|
||||
|
||||
@@ -728,14 +714,14 @@ class GuiDocViewHeader(QWidget):
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.docViewer = docViewer
|
||||
self.theParent = docViewer.theParent
|
||||
self.mainGui = docViewer.mainGui
|
||||
self.theProject = docViewer.theProject
|
||||
self.theTheme = docViewer.theTheme
|
||||
self.mainTheme = docViewer.mainTheme
|
||||
|
||||
# Internal Variables
|
||||
self._docHandle = None
|
||||
|
||||
fPx = int(0.9*self.theTheme.fontPixelSize)
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
hSp = self.mainConf.pxInt(6)
|
||||
|
||||
# Main Widget Settings
|
||||
@@ -752,17 +738,17 @@ class GuiDocViewHeader(QWidget):
|
||||
self.theTitle.setFixedHeight(fPx)
|
||||
|
||||
lblFont = self.theTitle.font()
|
||||
lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
self.theTitle.setFont(lblFont)
|
||||
|
||||
buttonStyle = (
|
||||
"QToolButton {{border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
||||
).format(*self.theTheme.colText)
|
||||
).format(*self.mainTheme.colText)
|
||||
|
||||
# Buttons
|
||||
self.backButton = QToolButton(self)
|
||||
self.backButton.setIcon(self.theTheme.getIcon("backward"))
|
||||
self.backButton.setIcon(self.mainTheme.getIcon("backward"))
|
||||
self.backButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.backButton.setIconSize(QSize(fPx, fPx))
|
||||
self.backButton.setFixedSize(fPx, fPx)
|
||||
@@ -773,7 +759,7 @@ class GuiDocViewHeader(QWidget):
|
||||
self.backButton.clicked.connect(self.docViewer.navBackward)
|
||||
|
||||
self.forwardButton = QToolButton(self)
|
||||
self.forwardButton.setIcon(self.theTheme.getIcon("forward"))
|
||||
self.forwardButton.setIcon(self.mainTheme.getIcon("forward"))
|
||||
self.forwardButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.forwardButton.setIconSize(QSize(fPx, fPx))
|
||||
self.forwardButton.setFixedSize(fPx, fPx)
|
||||
@@ -784,7 +770,7 @@ class GuiDocViewHeader(QWidget):
|
||||
self.forwardButton.clicked.connect(self.docViewer.navForward)
|
||||
|
||||
self.refreshButton = QToolButton(self)
|
||||
self.refreshButton.setIcon(self.theTheme.getIcon("refresh"))
|
||||
self.refreshButton.setIcon(self.mainTheme.getIcon("refresh"))
|
||||
self.refreshButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.refreshButton.setIconSize(QSize(fPx, fPx))
|
||||
self.refreshButton.setFixedSize(fPx, fPx)
|
||||
@@ -795,7 +781,7 @@ class GuiDocViewHeader(QWidget):
|
||||
self.refreshButton.clicked.connect(self._refreshDocument)
|
||||
|
||||
self.closeButton = QToolButton(self)
|
||||
self.closeButton.setIcon(self.theTheme.getIcon("close"))
|
||||
self.closeButton.setIcon(self.mainTheme.getIcon("close"))
|
||||
self.closeButton.setContentsMargins(0, 0, 0, 0)
|
||||
self.closeButton.setIconSize(QSize(fPx, fPx))
|
||||
self.closeButton.setFixedSize(fPx, fPx)
|
||||
@@ -838,9 +824,9 @@ class GuiDocViewHeader(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.theTitle.setPalette(thePalette)
|
||||
@@ -862,15 +848,15 @@ class GuiDocViewHeader(QWidget):
|
||||
|
||||
if self.mainConf.showFullPath:
|
||||
tTitle = []
|
||||
tTree = self.theProject.projTree.getItemPath(tHandle)
|
||||
tTree = self.theProject.tree.getItemPath(tHandle)
|
||||
for aHandle in reversed(tTree):
|
||||
nwItem = self.theProject.projTree[aHandle]
|
||||
nwItem = self.theProject.tree[aHandle]
|
||||
if nwItem is not None:
|
||||
tTitle.append(nwItem.itemName)
|
||||
sSep = " %s " % nwUnicode.U_RSAQUO
|
||||
self.theTitle.setText(sSep.join(tTitle))
|
||||
else:
|
||||
nwItem = self.theProject.projTree[tHandle]
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
if nwItem is None:
|
||||
return False
|
||||
self.theTitle.setText(nwItem.itemName)
|
||||
@@ -896,14 +882,14 @@ class GuiDocViewHeader(QWidget):
|
||||
def _closeDocument(self):
|
||||
"""Trigger the close editor/viewer on the main window.
|
||||
"""
|
||||
self.theParent.closeDocViewer()
|
||||
self.mainGui.closeDocViewer()
|
||||
return
|
||||
|
||||
def _refreshDocument(self):
|
||||
"""Reload the content of the document.
|
||||
"""
|
||||
if self.docViewer.docHandle() == self.theParent.docEditor.docHandle():
|
||||
self.theParent.saveDocument()
|
||||
if self.docViewer.docHandle() == self.mainGui.docEditor.docHandle():
|
||||
self.mainGui.saveDocument()
|
||||
self.docViewer.reloadText()
|
||||
return
|
||||
|
||||
@@ -915,7 +901,7 @@ class GuiDocViewHeader(QWidget):
|
||||
"""Capture a click on the title and ensure that the item is
|
||||
selected in the project tree.
|
||||
"""
|
||||
self.theParent.treeView.setSelectedHandle(self._docHandle, doScroll=True)
|
||||
self.mainGui.projView.setSelectedHandle(self._docHandle, doScroll=True)
|
||||
return
|
||||
|
||||
# END Class GuiDocViewHeader
|
||||
@@ -935,26 +921,26 @@ class GuiDocViewFooter(QWidget):
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.docViewer = docViewer
|
||||
self.theParent = docViewer.theParent
|
||||
self.theTheme = docViewer.theTheme
|
||||
self.viewMeta = docViewer.theParent.viewMeta
|
||||
self.mainGui = docViewer.mainGui
|
||||
self.mainTheme = docViewer.mainTheme
|
||||
self.viewMeta = docViewer.mainGui.viewMeta
|
||||
|
||||
# Internal Variables
|
||||
self._docHandle = None
|
||||
|
||||
fPx = int(0.9*self.theTheme.fontPixelSize)
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
bSp = self.mainConf.pxInt(2)
|
||||
hSp = self.mainConf.pxInt(8)
|
||||
|
||||
# Icons
|
||||
stickyOn = self.theTheme.getPixmap("sticky-on", (fPx, fPx))
|
||||
stickyOff = self.theTheme.getPixmap("sticky-off", (fPx, fPx))
|
||||
stickyOn = self.mainTheme.getPixmap("sticky-on", (fPx, fPx))
|
||||
stickyOff = self.mainTheme.getPixmap("sticky-off", (fPx, fPx))
|
||||
stickyIcon = QIcon()
|
||||
stickyIcon.addPixmap(stickyOn, QIcon.Normal, QIcon.On)
|
||||
stickyIcon.addPixmap(stickyOff, QIcon.Normal, QIcon.Off)
|
||||
|
||||
bulletOn = self.theTheme.getPixmap("bullet-on", (fPx, fPx))
|
||||
bulletOff = self.theTheme.getPixmap("bullet-off", (fPx, fPx))
|
||||
bulletOn = self.mainTheme.getPixmap("bullet-on", (fPx, fPx))
|
||||
bulletOff = self.mainTheme.getPixmap("bullet-off", (fPx, fPx))
|
||||
bulletIcon = QIcon()
|
||||
bulletIcon.addPixmap(bulletOn, QIcon.Normal, QIcon.On)
|
||||
bulletIcon.addPixmap(bulletOff, QIcon.Normal, QIcon.Off)
|
||||
@@ -966,13 +952,13 @@ class GuiDocViewFooter(QWidget):
|
||||
buttonStyle = (
|
||||
"QToolButton {{border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
||||
).format(*self.theTheme.colText)
|
||||
).format(*self.mainTheme.colText)
|
||||
|
||||
# Show/Hide Details
|
||||
self.showHide = QToolButton(self)
|
||||
self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
||||
self.showHide.setStyleSheet(buttonStyle)
|
||||
self.showHide.setIcon(self.theTheme.getIcon("reference"))
|
||||
self.showHide.setIcon(self.mainTheme.getIcon("reference"))
|
||||
self.showHide.setIconSize(QSize(fPx, fPx))
|
||||
self.showHide.setFixedSize(QSize(fPx, fPx))
|
||||
self.showHide.clicked.connect(self._doShowHide)
|
||||
@@ -1053,7 +1039,7 @@ class GuiDocViewFooter(QWidget):
|
||||
self.lblSynopsis.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
|
||||
lblFont = self.font()
|
||||
lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
self.lblRefs.setFont(lblFont)
|
||||
self.lblSticky.setFont(lblFont)
|
||||
self.lblComments.setFont(lblFont)
|
||||
@@ -1098,9 +1084,9 @@ class GuiDocViewFooter(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.lblRefs.setPalette(thePalette)
|
||||
@@ -1154,14 +1140,14 @@ class GuiDocViewFooter(QWidget):
|
||||
|
||||
class GuiDocViewDetails(QScrollArea):
|
||||
|
||||
def __init__(self, theParent):
|
||||
QScrollArea.__init__(self, theParent)
|
||||
def __init__(self, mainGui):
|
||||
QScrollArea.__init__(self, mainGui)
|
||||
|
||||
logger.debug("Initialising GuiDocViewDetails ...")
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theProject = theParent.theProject
|
||||
self.theTheme = theParent.theTheme
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
|
||||
self.refList = QLabel("")
|
||||
self.refList.setWordWrap(True)
|
||||
@@ -1170,7 +1156,7 @@ class GuiDocViewDetails(QScrollArea):
|
||||
self.refList.linkActivated.connect(self._linkClicked)
|
||||
|
||||
self.linkStyle = "style='color: rgb({0},{1},{2})'".format(
|
||||
*self.theTheme.colLink
|
||||
*self.mainTheme.colLink
|
||||
)
|
||||
|
||||
# Assemble
|
||||
@@ -1185,6 +1171,7 @@ class GuiDocViewDetails(QScrollArea):
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.setWidgetResizable(True)
|
||||
self.setMinimumHeight(self.mainConf.pxInt(50))
|
||||
self.setFrameStyle(QFrame.NoFrame)
|
||||
|
||||
logger.debug("GuiDocViewDetails initialisation complete")
|
||||
|
||||
@@ -1194,13 +1181,13 @@ class GuiDocViewDetails(QScrollArea):
|
||||
"""Update the current list of document references from the
|
||||
project index.
|
||||
"""
|
||||
if self.theParent.docViewer.stickyRef:
|
||||
if self.mainGui.docViewer.stickyRef:
|
||||
return
|
||||
|
||||
theRefs = self.theParent.theIndex.getBackReferenceList(tHandle)
|
||||
theRefs = self.theProject.index.getBackReferenceList(tHandle)
|
||||
theList = []
|
||||
for tHandle in theRefs:
|
||||
tItem = self.theProject.projTree[tHandle]
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
if tItem is not None:
|
||||
theList.append("<a href='%s#%s' %s>%s</a>" % (
|
||||
tHandle, theRefs[tHandle], self.linkStyle, tItem.itemName
|
||||
@@ -1222,7 +1209,7 @@ class GuiDocViewDetails(QScrollArea):
|
||||
if len(theLink) == 21:
|
||||
tHandle = theLink[:13]
|
||||
tAnchor = theLink[13:]
|
||||
self.theParent.viewDocument(tHandle, tAnchor)
|
||||
self.mainGui.viewDocument(tHandle, tAnchor)
|
||||
return
|
||||
|
||||
# END Class GuiDocViewDetails
|
||||
|
||||
@@ -30,7 +30,7 @@ from PyQt5.QtCore import Qt, pyqtSlot
|
||||
from PyQt5.QtGui import QFont, QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
|
||||
|
||||
from novelwriter.enum import nwItemClass, nwItemType
|
||||
from novelwriter.enum import nwItemType
|
||||
from novelwriter.constants import trConst, nwLabels
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -38,14 +38,14 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiItemDetails(QWidget):
|
||||
|
||||
def __init__(self, theParent):
|
||||
QWidget.__init__(self, theParent)
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
|
||||
logger.debug("Initialising GuiItemDetails ...")
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theProject = theParent.theProject
|
||||
self.theTheme = theParent.theTheme
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
|
||||
# Internal Variables
|
||||
self._itemHandle = None
|
||||
@@ -54,11 +54,11 @@ class GuiItemDetails(QWidget):
|
||||
hSp = self.mainConf.pxInt(6)
|
||||
vSp = self.mainConf.pxInt(1)
|
||||
mPx = self.mainConf.pxInt(6)
|
||||
iPx = self.theTheme.baseIconSize
|
||||
fPt = self.theTheme.fontPointSize
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
fPt = self.mainTheme.fontPointSize
|
||||
|
||||
self._expCheck = self.theTheme.getPixmap("check", (iPx, iPx))
|
||||
self._expCross = self.theTheme.getPixmap("cross", (iPx, iPx))
|
||||
self._expCheck = self.mainTheme.getPixmap("check", (iPx, iPx))
|
||||
self._expCross = self.mainTheme.getPixmap("cross", (iPx, iPx))
|
||||
|
||||
fntLabel = QFont()
|
||||
fntLabel.setBold(True)
|
||||
@@ -115,6 +115,7 @@ class GuiItemDetails(QWidget):
|
||||
self.usageData = QLabel("")
|
||||
self.usageData.setFont(fntValue)
|
||||
self.usageData.setAlignment(Qt.AlignLeft)
|
||||
self.usageData.setWordWrap(True)
|
||||
|
||||
# Character Count
|
||||
self.cCountName = QLabel(" "+self.tr("Characters"))
|
||||
@@ -180,8 +181,8 @@ class GuiItemDetails(QWidget):
|
||||
self.setLayout(self.mainBox)
|
||||
|
||||
# Make sure the columns for flags and counts don't resize too often
|
||||
flagWidth = self.theTheme.getTextWidth("Mm", fntValue)
|
||||
countWidth = self.theTheme.getTextWidth("99,999", fntValue)
|
||||
flagWidth = self.mainTheme.getTextWidth("Mm", fntValue)
|
||||
countWidth = self.mainTheme.getTextWidth("99,999", fntValue)
|
||||
self.mainBox.setColumnMinimumWidth(1, flagWidth)
|
||||
self.mainBox.setColumnMinimumWidth(4, countWidth)
|
||||
|
||||
@@ -214,6 +215,16 @@ class GuiItemDetails(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def refreshDetails(self):
|
||||
"""Reload the content of the details panel.
|
||||
"""
|
||||
self.updateViewBox(self._itemHandle)
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateViewBox(self, tHandle):
|
||||
"""Populate the details box from a given handle.
|
||||
"""
|
||||
@@ -221,13 +232,13 @@ class GuiItemDetails(QWidget):
|
||||
self.clearDetails()
|
||||
return
|
||||
|
||||
nwItem = self.theProject.projTree[tHandle]
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
if nwItem is None:
|
||||
self.clearDetails()
|
||||
return
|
||||
|
||||
self._itemHandle = tHandle
|
||||
iPx = int(round(0.8*self.theTheme.baseIconSize))
|
||||
iPx = int(round(0.8*self.mainTheme.baseIconSize))
|
||||
|
||||
# Label
|
||||
# =====
|
||||
@@ -249,29 +260,22 @@ class GuiItemDetails(QWidget):
|
||||
# Status
|
||||
# ======
|
||||
|
||||
itStatus = nwItem.itemStatus
|
||||
if nwItem.itemClass == nwItemClass.NOVEL:
|
||||
itStatus = self.theProject.statusItems.checkEntry(itStatus) # Make sure it's valid
|
||||
flagIcon = self.theParent.statusIcons[itStatus]
|
||||
else:
|
||||
itStatus = self.theProject.importItems.checkEntry(itStatus) # Make sure it's valid
|
||||
flagIcon = self.theParent.importIcons[itStatus]
|
||||
|
||||
self.statusIcon.setPixmap(flagIcon.pixmap(iPx, iPx))
|
||||
self.statusData.setText(nwItem.itemStatus)
|
||||
theStatus, theIcon = nwItem.getImportStatus()
|
||||
self.statusIcon.setPixmap(theIcon.pixmap(iPx, iPx))
|
||||
self.statusData.setText(theStatus)
|
||||
|
||||
# Class
|
||||
# =====
|
||||
|
||||
classIcon = self.theTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
|
||||
classIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
|
||||
self.classIcon.setPixmap(classIcon.pixmap(iPx, iPx))
|
||||
self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass]))
|
||||
|
||||
# Layout
|
||||
# ======
|
||||
|
||||
hLevel = self.theParent.theIndex.getHandleHeaderLevel(tHandle)
|
||||
usageIcon = self.theTheme.getItemIcon(
|
||||
hLevel = self.theProject.index.getHandleHeaderLevel(tHandle)
|
||||
usageIcon = self.mainTheme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
|
||||
)
|
||||
self.usageIcon.setPixmap(usageIcon.pixmap(iPx, iPx))
|
||||
@@ -291,12 +295,8 @@ class GuiItemDetails(QWidget):
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str, int, int, int)
|
||||
def doUpdateCounts(self, tHandle, cC, wC, pC):
|
||||
def updateCounts(self, tHandle, cC, wC, pC):
|
||||
"""Update the counts if the handle is the same as the one we're
|
||||
already showing. Otherwise, do nothing.
|
||||
"""
|
||||
|
||||
+58
-149
@@ -33,7 +33,7 @@ from PyQt5.QtCore import QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from PyQt5.QtWidgets import QMenuBar, QAction
|
||||
|
||||
from novelwriter.enum import nwItemType, nwItemClass, nwDocAction, nwDocInsert, nwWidget
|
||||
from novelwriter.enum import nwDocAction, nwDocInsert, nwWidget
|
||||
from novelwriter.constants import trConst, nwKeyWords, nwLabels, nwUnicode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -41,13 +41,13 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiMainMenu(QMenuBar):
|
||||
|
||||
def __init__(self, theParent):
|
||||
QMenuBar.__init__(self, theParent)
|
||||
def __init__(self, mainGui):
|
||||
QMenuBar.__init__(self, mainGui)
|
||||
|
||||
logger.debug("Initialising GuiMainMenu ...")
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theProject = theParent.theProject
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
|
||||
# Build Menu
|
||||
self._buildProjectMenu()
|
||||
@@ -61,34 +61,14 @@ class GuiMainMenu(QMenuBar):
|
||||
self._buildHelpMenu()
|
||||
|
||||
# Function Pointers
|
||||
self._docAction = self.theParent.passDocumentAction
|
||||
self._moveTreeItem = self.theParent.treeView.moveTreeItem
|
||||
self._newTreeItem = self.theParent.treeView.newTreeItem
|
||||
self._docInsert = self.theParent.docEditor.insertText
|
||||
self._insertKeyWord = self.theParent.docEditor.insertKeyWord
|
||||
self._docAction = self.mainGui.passDocumentAction
|
||||
self._docInsert = self.mainGui.docEditor.insertText
|
||||
self._insertKeyWord = self.mainGui.docEditor.insertKeyWord
|
||||
|
||||
logger.debug("GuiMainMenu initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def setAvailableRoot(self):
|
||||
"""Update the list of available root folders and set the ones
|
||||
that are active.
|
||||
"""
|
||||
for itemClass in nwItemClass:
|
||||
if itemClass == nwItemClass.NO_CLASS:
|
||||
continue
|
||||
if itemClass == nwItemClass.TRASH:
|
||||
continue
|
||||
self.rootItems[itemClass].setVisible(
|
||||
self.theProject.projTree.checkRootUnique(itemClass)
|
||||
)
|
||||
return
|
||||
|
||||
##
|
||||
# Update Menu on Settings Changed
|
||||
##
|
||||
@@ -99,12 +79,6 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aSpellCheck.setChecked(theMode)
|
||||
return
|
||||
|
||||
def setAutoOutline(self, theMode):
|
||||
"""Forward auto outline check state to its action.
|
||||
"""
|
||||
self.aAutoOutline.setChecked(theMode)
|
||||
return
|
||||
|
||||
def setFocusMode(self, theMode):
|
||||
"""Forward focus mode check state to its action.
|
||||
"""
|
||||
@@ -120,13 +94,7 @@ class GuiMainMenu(QMenuBar):
|
||||
flag is handled by the document editor class, so we make no
|
||||
decision, just pass a None to the function and let it decide.
|
||||
"""
|
||||
self.theParent.docEditor.toggleSpellCheck(None)
|
||||
return True
|
||||
|
||||
def _toggleAutoOutline(self, theMode):
|
||||
"""Toggle auto outline when the menu entry is checked.
|
||||
"""
|
||||
self.theProject.setAutoOutline(theMode)
|
||||
self.mainGui.docEditor.toggleSpellCheck(None)
|
||||
return True
|
||||
|
||||
def _openWebsite(self, theUrl):
|
||||
@@ -155,25 +123,25 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
# Project > New Project
|
||||
self.aNewProject = QAction(self.tr("New Project"), self)
|
||||
self.aNewProject.triggered.connect(lambda: self.theParent.newProject(None))
|
||||
self.aNewProject.triggered.connect(lambda: self.mainGui.newProject(None))
|
||||
self.projMenu.addAction(self.aNewProject)
|
||||
|
||||
# Project > Open Project
|
||||
self.aOpenProject = QAction(self.tr("Open Project"), self)
|
||||
self.aOpenProject.setShortcut("Ctrl+Shift+O")
|
||||
self.aOpenProject.triggered.connect(lambda: self.theParent.showProjectLoadDialog())
|
||||
self.aOpenProject.triggered.connect(lambda: self.mainGui.showProjectLoadDialog())
|
||||
self.projMenu.addAction(self.aOpenProject)
|
||||
|
||||
# Project > Save Project
|
||||
self.aSaveProject = QAction(self.tr("Save Project"), self)
|
||||
self.aSaveProject.setShortcut("Ctrl+Shift+S")
|
||||
self.aSaveProject.triggered.connect(lambda: self.theParent.saveProject())
|
||||
self.aSaveProject.triggered.connect(lambda: self.mainGui.saveProject())
|
||||
self.projMenu.addAction(self.aSaveProject)
|
||||
|
||||
# Project > Close Project
|
||||
self.aCloseProject = QAction(self.tr("Close Project"), self)
|
||||
self.aCloseProject.setShortcut("Ctrl+Shift+W")
|
||||
self.aCloseProject.triggered.connect(lambda: self.theParent.closeProject(False))
|
||||
self.aCloseProject.triggered.connect(lambda: self.mainGui.closeProject(False))
|
||||
self.projMenu.addAction(self.aCloseProject)
|
||||
|
||||
# Project > Separator
|
||||
@@ -182,78 +150,33 @@ class GuiMainMenu(QMenuBar):
|
||||
# Project > Project Settings
|
||||
self.aProjectSettings = QAction(self.tr("Project Settings"), self)
|
||||
self.aProjectSettings.setShortcut("Ctrl+Shift+,")
|
||||
self.aProjectSettings.triggered.connect(lambda: self.theParent.showProjectSettingsDialog())
|
||||
self.aProjectSettings.triggered.connect(lambda: self.mainGui.showProjectSettingsDialog())
|
||||
self.projMenu.addAction(self.aProjectSettings)
|
||||
|
||||
# Project > Project Details
|
||||
self.aProjectDetails = QAction(self.tr("Project Details"), self)
|
||||
self.aProjectDetails.setShortcut("Shift+F6")
|
||||
self.aProjectDetails.triggered.connect(lambda: self.theParent.showProjectDetailsDialog())
|
||||
self.aProjectDetails.triggered.connect(lambda: self.mainGui.showProjectDetailsDialog())
|
||||
self.projMenu.addAction(self.aProjectDetails)
|
||||
|
||||
# Project > Separator
|
||||
self.projMenu.addSeparator()
|
||||
|
||||
# Project > New Root
|
||||
self.rootMenu = self.projMenu.addMenu(self.tr("Create Root Folder"))
|
||||
self.rootItems = {}
|
||||
self.rootItems[nwItemClass.NOVEL] = QAction(self.tr("Novel Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.PLOT] = QAction(self.tr("Plot Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.CHARACTER] = QAction(self.tr("Character Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.WORLD] = QAction(self.tr("Location Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.TIMELINE] = QAction(self.tr("Timeline Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.OBJECT] = QAction(self.tr("Object Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.ENTITY] = QAction(self.tr("Entity Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.CUSTOM] = QAction(self.tr("Custom Root"), self.rootMenu)
|
||||
self.rootItems[nwItemClass.ARCHIVE] = QAction(self.tr("Archive Root"), self.rootMenu)
|
||||
for n, itemClass in enumerate(self.rootItems.keys()):
|
||||
self.rootItems[itemClass].triggered.connect(
|
||||
lambda n, itemClass=itemClass: self._newTreeItem(nwItemType.ROOT, itemClass)
|
||||
)
|
||||
self.rootMenu.addAction(self.rootItems[itemClass])
|
||||
|
||||
# Project > New Folder
|
||||
self.aCreateFolder = QAction(self.tr("Create Folder"), self)
|
||||
self.aCreateFolder.setShortcut("Ctrl+Shift+N")
|
||||
self.aCreateFolder.triggered.connect(lambda: self._newTreeItem(nwItemType.FOLDER, None))
|
||||
self.projMenu.addAction(self.aCreateFolder)
|
||||
|
||||
# Project > Separator
|
||||
self.projMenu.addSeparator()
|
||||
|
||||
# Project > Edit
|
||||
self.aEditItem = QAction(self.tr("Edit Item"), self)
|
||||
self.aEditItem.setShortcuts(["Ctrl+E", "F2"])
|
||||
self.aEditItem.triggered.connect(lambda: self.theParent.editItem(None))
|
||||
self.aEditItem = QAction(self.tr("Rename Item"), self)
|
||||
self.aEditItem.setShortcuts(["F2"])
|
||||
self.aEditItem.triggered.connect(lambda: self.mainGui.editItemLabel(None))
|
||||
self.projMenu.addAction(self.aEditItem)
|
||||
|
||||
# Project > Delete
|
||||
self.aDeleteItem = QAction(self.tr("Delete Item"), self)
|
||||
self.aDeleteItem.setShortcut("Ctrl+Shift+Del")
|
||||
self.aDeleteItem.triggered.connect(lambda: self.theParent.treeView.deleteItem(None))
|
||||
self.aDeleteItem.triggered.connect(lambda: self.mainGui.projView.deleteItem(None))
|
||||
self.projMenu.addAction(self.aDeleteItem)
|
||||
|
||||
# Project > Move Up
|
||||
self.aMoveUp = QAction(self.tr("Move Item Up"), self)
|
||||
self.aMoveUp.setShortcut("Ctrl+Up")
|
||||
self.aMoveUp.triggered.connect(lambda: self._moveTreeItem(-1))
|
||||
self.projMenu.addAction(self.aMoveUp)
|
||||
|
||||
# Project > Move Down
|
||||
self.aMoveDown = QAction(self.tr("Move Item Down"), self)
|
||||
self.aMoveDown.setShortcut("Ctrl+Down")
|
||||
self.aMoveDown.triggered.connect(lambda: self._moveTreeItem(1))
|
||||
self.projMenu.addAction(self.aMoveDown)
|
||||
|
||||
# Project > Undo Last Action
|
||||
self.aMoveUndo = QAction(self.tr("Undo Last Move"), self)
|
||||
self.aMoveUndo.setShortcut("Ctrl+Shift+Z")
|
||||
self.aMoveUndo.triggered.connect(lambda: self.theParent.treeView.undoLastMove())
|
||||
self.projMenu.addAction(self.aMoveUndo)
|
||||
|
||||
# Project > Empty Trash
|
||||
self.aEmptyTrash = QAction(self.tr("Empty Trash"), self)
|
||||
self.aEmptyTrash.triggered.connect(lambda: self.theParent.treeView.emptyTrash())
|
||||
self.aEmptyTrash.triggered.connect(lambda: self.mainGui.projView.emptyTrash())
|
||||
self.projMenu.addAction(self.aEmptyTrash)
|
||||
|
||||
# Project > Separator
|
||||
@@ -263,7 +186,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aExitNW = QAction(self.tr("Exit"), self)
|
||||
self.aExitNW.setShortcut("Ctrl+Q")
|
||||
self.aExitNW.setMenuRole(QAction.QuitRole)
|
||||
self.aExitNW.triggered.connect(lambda: self.theParent.closeMain())
|
||||
self.aExitNW.triggered.connect(lambda: self.mainGui.closeMain())
|
||||
self.projMenu.addAction(self.aExitNW)
|
||||
|
||||
return
|
||||
@@ -274,28 +197,22 @@ class GuiMainMenu(QMenuBar):
|
||||
# Document
|
||||
self.docuMenu = self.addMenu(self.tr("&Document"))
|
||||
|
||||
# Document > New
|
||||
self.aNewDoc = QAction(self.tr("New Document"), self)
|
||||
self.aNewDoc.setShortcut("Ctrl+N")
|
||||
self.aNewDoc.triggered.connect(lambda: self._newTreeItem(nwItemType.FILE, None))
|
||||
self.docuMenu.addAction(self.aNewDoc)
|
||||
|
||||
# Document > Open
|
||||
self.aOpenDoc = QAction(self.tr("Open Document"), self)
|
||||
self.aOpenDoc.setShortcut("Ctrl+O")
|
||||
self.aOpenDoc.triggered.connect(lambda: self.theParent.openSelectedItem())
|
||||
self.aOpenDoc.triggered.connect(lambda: self.mainGui.openSelectedItem())
|
||||
self.docuMenu.addAction(self.aOpenDoc)
|
||||
|
||||
# Document > Save
|
||||
self.aSaveDoc = QAction(self.tr("Save Document"), self)
|
||||
self.aSaveDoc.setShortcut("Ctrl+S")
|
||||
self.aSaveDoc.triggered.connect(lambda: self.theParent.saveDocument())
|
||||
self.aSaveDoc.triggered.connect(lambda: self.mainGui.saveDocument())
|
||||
self.docuMenu.addAction(self.aSaveDoc)
|
||||
|
||||
# Document > Close
|
||||
self.aCloseDoc = QAction(self.tr("Close Document"), self)
|
||||
self.aCloseDoc.setShortcut("Ctrl+W")
|
||||
self.aCloseDoc.triggered.connect(lambda: self.theParent.closeDocEditor())
|
||||
self.aCloseDoc.triggered.connect(lambda: self.mainGui.closeDocEditor())
|
||||
self.docuMenu.addAction(self.aCloseDoc)
|
||||
|
||||
# Document > Separator
|
||||
@@ -304,13 +221,13 @@ class GuiMainMenu(QMenuBar):
|
||||
# Document > Preview
|
||||
self.aViewDoc = QAction(self.tr("View Document"), self)
|
||||
self.aViewDoc.setShortcut("Ctrl+R")
|
||||
self.aViewDoc.triggered.connect(lambda: self.theParent.viewDocument(None))
|
||||
self.aViewDoc.triggered.connect(lambda: self.mainGui.viewDocument(None))
|
||||
self.docuMenu.addAction(self.aViewDoc)
|
||||
|
||||
# Document > Close Preview
|
||||
self.aCloseView = QAction(self.tr("Close Document View"), self)
|
||||
self.aCloseView.setShortcut("Ctrl+Shift+R")
|
||||
self.aCloseView.triggered.connect(lambda: self.theParent.closeDocViewer())
|
||||
self.aCloseView.triggered.connect(lambda: self.mainGui.closeDocViewer())
|
||||
self.docuMenu.addAction(self.aCloseView)
|
||||
|
||||
# Document > Separator
|
||||
@@ -318,23 +235,23 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
# Document > Show File Details
|
||||
self.aFileDetails = QAction(self.tr("Show File Details"), self)
|
||||
self.aFileDetails.triggered.connect(lambda: self.theParent.docEditor.revealLocation())
|
||||
self.aFileDetails.triggered.connect(lambda: self.mainGui.docEditor.revealLocation())
|
||||
self.docuMenu.addAction(self.aFileDetails)
|
||||
|
||||
# Document > Import From File
|
||||
self.aImportFile = QAction(self.tr("Import Text from File"), self)
|
||||
self.aImportFile.setShortcut("Ctrl+Shift+I")
|
||||
self.aImportFile.triggered.connect(lambda: self.theParent.importDocument())
|
||||
self.aImportFile.triggered.connect(lambda: self.mainGui.importDocument())
|
||||
self.docuMenu.addAction(self.aImportFile)
|
||||
|
||||
# Document > Merge Documents
|
||||
self.aMergeDocs = QAction(self.tr("Merge Folder to Document"), self)
|
||||
self.aMergeDocs.triggered.connect(lambda: self.theParent.mergeDocuments())
|
||||
self.aMergeDocs.triggered.connect(lambda: self.mainGui.mergeDocuments())
|
||||
self.docuMenu.addAction(self.aMergeDocs)
|
||||
|
||||
# Document > Split Document
|
||||
self.aSplitDoc = QAction(self.tr("Split Document to Folder"), self)
|
||||
self.aSplitDoc.triggered.connect(lambda: self.theParent.splitDocument())
|
||||
self.aSplitDoc.triggered.connect(lambda: self.mainGui.splitDocument())
|
||||
self.docuMenu.addAction(self.aSplitDoc)
|
||||
|
||||
return
|
||||
@@ -407,7 +324,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFocusTree.setShortcut("Ctrl+Alt+1")
|
||||
else:
|
||||
self.aFocusTree.setShortcut("Alt+1")
|
||||
self.aFocusTree.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.TREE))
|
||||
self.aFocusTree.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.TREE))
|
||||
self.viewMenu.addAction(self.aFocusTree)
|
||||
|
||||
# View > Document Pane 1
|
||||
@@ -416,7 +333,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFocusEditor.setShortcut("Ctrl+Alt+2")
|
||||
else:
|
||||
self.aFocusEditor.setShortcut("Alt+2")
|
||||
self.aFocusEditor.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.EDITOR))
|
||||
self.aFocusEditor.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.EDITOR))
|
||||
self.viewMenu.addAction(self.aFocusEditor)
|
||||
|
||||
# View > Document Pane 2
|
||||
@@ -425,7 +342,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFocusView.setShortcut("Ctrl+Alt+3")
|
||||
else:
|
||||
self.aFocusView.setShortcut("Alt+3")
|
||||
self.aFocusView.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.VIEWER))
|
||||
self.aFocusView.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.VIEWER))
|
||||
self.viewMenu.addAction(self.aFocusView)
|
||||
|
||||
# View > Outline
|
||||
@@ -434,7 +351,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFocusOutline.setShortcut("Ctrl+Alt+4")
|
||||
else:
|
||||
self.aFocusOutline.setShortcut("Alt+4")
|
||||
self.aFocusOutline.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.OUTLINE))
|
||||
self.aFocusOutline.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.OUTLINE))
|
||||
self.viewMenu.addAction(self.aFocusOutline)
|
||||
|
||||
# View > Separator
|
||||
@@ -443,13 +360,13 @@ class GuiMainMenu(QMenuBar):
|
||||
# View > Go Backward
|
||||
self.aViewPrev = QAction(self.tr("Navigate Backward"), self)
|
||||
self.aViewPrev.setShortcut("Alt+Left")
|
||||
self.aViewPrev.triggered.connect(lambda: self.theParent.docViewer.navBackward())
|
||||
self.aViewPrev.triggered.connect(lambda: self.mainGui.docViewer.navBackward())
|
||||
self.viewMenu.addAction(self.aViewPrev)
|
||||
|
||||
# View > Go Forward
|
||||
self.aViewNext = QAction(self.tr("Navigate Forward"), self)
|
||||
self.aViewNext.setShortcut("Alt+Right")
|
||||
self.aViewNext.triggered.connect(lambda: self.theParent.docViewer.navForward())
|
||||
self.aViewNext.triggered.connect(lambda: self.mainGui.docViewer.navForward())
|
||||
self.viewMenu.addAction(self.aViewNext)
|
||||
|
||||
# View > Separator
|
||||
@@ -459,14 +376,14 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFocusMode = QAction(self.tr("Focus Mode"), self)
|
||||
self.aFocusMode.setShortcut("F8")
|
||||
self.aFocusMode.setCheckable(True)
|
||||
self.aFocusMode.setChecked(self.theParent.isFocusMode)
|
||||
self.aFocusMode.triggered.connect(lambda: self.theParent.toggleFocusMode())
|
||||
self.aFocusMode.setChecked(self.mainGui.isFocusMode)
|
||||
self.aFocusMode.triggered.connect(lambda: self.mainGui.toggleFocusMode())
|
||||
self.viewMenu.addAction(self.aFocusMode)
|
||||
|
||||
# View > Toggle Full Screen
|
||||
self.aFullScreen = QAction(self.tr("Full Screen Mode"), self)
|
||||
self.aFullScreen.setShortcut("F11")
|
||||
self.aFullScreen.triggered.connect(lambda: self.theParent.toggleFullScreenMode())
|
||||
self.aFullScreen.triggered.connect(lambda: self.mainGui.toggleFullScreenMode())
|
||||
self.viewMenu.addAction(self.aFullScreen)
|
||||
|
||||
return
|
||||
@@ -669,6 +586,11 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aInsVSpaceM.triggered.connect(lambda: self._docInsert(nwDocInsert.VSPACE_M))
|
||||
self.mInsBreaks.addAction(self.aInsVSpaceM)
|
||||
|
||||
# Insert > Placeholder Text
|
||||
self.aLipsumText = QAction(self.tr("Placeholder Text"), self)
|
||||
self.aLipsumText.triggered.connect(lambda: self.mainGui.showLoremIpsumDialog())
|
||||
self.insertMenu.addAction(self.aLipsumText)
|
||||
|
||||
return
|
||||
|
||||
def _buildFormatMenu(self):
|
||||
@@ -830,7 +752,7 @@ class GuiMainMenu(QMenuBar):
|
||||
# Search > Find
|
||||
self.aFind = QAction(self.tr("Find"), self)
|
||||
self.aFind.setShortcut("Ctrl+F")
|
||||
self.aFind.triggered.connect(lambda: self.theParent.docEditor.beginSearch())
|
||||
self.aFind.triggered.connect(lambda: self.mainGui.docEditor.beginSearch())
|
||||
self.srcMenu.addAction(self.aFind)
|
||||
|
||||
# Search > Replace
|
||||
@@ -839,7 +761,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aReplace.setShortcut("Ctrl+=")
|
||||
else:
|
||||
self.aReplace.setShortcut("Ctrl+H")
|
||||
self.aReplace.triggered.connect(lambda: self.theParent.docEditor.beginReplace())
|
||||
self.aReplace.triggered.connect(lambda: self.mainGui.docEditor.beginReplace())
|
||||
self.srcMenu.addAction(self.aReplace)
|
||||
|
||||
# Search > Find Next
|
||||
@@ -848,7 +770,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFindNext.setShortcuts(["Ctrl+G", "F3"])
|
||||
else:
|
||||
self.aFindNext.setShortcuts(["F3", "Ctrl+G"])
|
||||
self.aFindNext.triggered.connect(lambda: self.theParent.docEditor.findNext())
|
||||
self.aFindNext.triggered.connect(lambda: self.mainGui.docEditor.findNext())
|
||||
self.srcMenu.addAction(self.aFindNext)
|
||||
|
||||
# Search > Find Prev
|
||||
@@ -857,13 +779,13 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFindPrev.setShortcuts(["Ctrl+Shift+G", "Shift+F3"])
|
||||
else:
|
||||
self.aFindPrev.setShortcuts(["Shift+F3", "Ctrl+Shift+G"])
|
||||
self.aFindPrev.triggered.connect(lambda: self.theParent.docEditor.findNext(goBack=True))
|
||||
self.aFindPrev.triggered.connect(lambda: self.mainGui.docEditor.findNext(goBack=True))
|
||||
self.srcMenu.addAction(self.aFindPrev)
|
||||
|
||||
# Search > Replace Next
|
||||
self.aReplaceNext = QAction(self.tr("Replace Next"), self)
|
||||
self.aReplaceNext.setShortcut("Ctrl+Shift+1")
|
||||
self.aReplaceNext.triggered.connect(lambda: self.theParent.docEditor.replaceNext())
|
||||
self.aReplaceNext.triggered.connect(lambda: self.mainGui.docEditor.replaceNext())
|
||||
self.srcMenu.addAction(self.aReplaceNext)
|
||||
|
||||
return
|
||||
@@ -885,12 +807,12 @@ class GuiMainMenu(QMenuBar):
|
||||
# Tools > Re-Run Spell Check
|
||||
self.aReRunSpell = QAction(self.tr("Re-Run Spell Check"), self)
|
||||
self.aReRunSpell.setShortcut("F7")
|
||||
self.aReRunSpell.triggered.connect(lambda: self.theParent.docEditor.spellCheckDocument())
|
||||
self.aReRunSpell.triggered.connect(lambda: self.mainGui.docEditor.spellCheckDocument())
|
||||
self.toolsMenu.addAction(self.aReRunSpell)
|
||||
|
||||
# Tools > Project Word List
|
||||
self.aEditWordList = QAction(self.tr("Project Word List"), self)
|
||||
self.aEditWordList.triggered.connect(lambda: self.theParent.showProjectWordListDialog())
|
||||
self.aEditWordList.triggered.connect(lambda: self.mainGui.showProjectWordListDialog())
|
||||
self.toolsMenu.addAction(self.aEditWordList)
|
||||
|
||||
# Tools > Separator
|
||||
@@ -899,22 +821,9 @@ class GuiMainMenu(QMenuBar):
|
||||
# Tools > Rebuild Indices
|
||||
self.aRebuildIndex = QAction(self.tr("Rebuild Index"), self)
|
||||
self.aRebuildIndex.setShortcut("F9")
|
||||
self.aRebuildIndex.triggered.connect(lambda: self.theParent.rebuildIndex())
|
||||
self.aRebuildIndex.triggered.connect(lambda: self.mainGui.rebuildIndex())
|
||||
self.toolsMenu.addAction(self.aRebuildIndex)
|
||||
|
||||
# Tools > Rebuild Outline
|
||||
self.aRebuildOutline = QAction(self.tr("Rebuild Outline"), self)
|
||||
self.aRebuildOutline.setShortcut("F10")
|
||||
self.aRebuildOutline.triggered.connect(lambda: self.theParent.rebuildOutline())
|
||||
self.toolsMenu.addAction(self.aRebuildOutline)
|
||||
|
||||
# Tools > Toggle Auto Build Outline
|
||||
self.aAutoOutline = QAction(self.tr("Auto-Update Outline"), self)
|
||||
self.aAutoOutline.setCheckable(True)
|
||||
self.aAutoOutline.toggled.connect(self._toggleAutoOutline)
|
||||
self.aAutoOutline.setShortcut("Ctrl+F10")
|
||||
self.toolsMenu.addAction(self.aAutoOutline)
|
||||
|
||||
# Tools > Separator
|
||||
self.toolsMenu.addSeparator()
|
||||
|
||||
@@ -926,20 +835,20 @@ class GuiMainMenu(QMenuBar):
|
||||
# Tools > Export Project
|
||||
self.aBuildProject = QAction(self.tr("Build Novel Project"), self)
|
||||
self.aBuildProject.setShortcut("F5")
|
||||
self.aBuildProject.triggered.connect(lambda: self.theParent.showBuildProjectDialog())
|
||||
self.aBuildProject.triggered.connect(lambda: self.mainGui.showBuildProjectDialog())
|
||||
self.toolsMenu.addAction(self.aBuildProject)
|
||||
|
||||
# Tools > Writing Stats
|
||||
self.aWritingStats = QAction(self.tr("Writing Statistics"), self)
|
||||
self.aWritingStats.setShortcut("F6")
|
||||
self.aWritingStats.triggered.connect(lambda: self.theParent.showWritingStatsDialog())
|
||||
self.aWritingStats.triggered.connect(lambda: self.mainGui.showWritingStatsDialog())
|
||||
self.toolsMenu.addAction(self.aWritingStats)
|
||||
|
||||
# Tools > Settings
|
||||
self.aPreferences = QAction(self.tr("Preferences"), self)
|
||||
self.aPreferences.setShortcut("Ctrl+,")
|
||||
self.aPreferences.setMenuRole(QAction.PreferencesRole)
|
||||
self.aPreferences.triggered.connect(lambda: self.theParent.showPreferencesDialog())
|
||||
self.aPreferences.triggered.connect(lambda: self.mainGui.showPreferencesDialog())
|
||||
self.toolsMenu.addAction(self.aPreferences)
|
||||
|
||||
return
|
||||
@@ -953,13 +862,13 @@ class GuiMainMenu(QMenuBar):
|
||||
# Help > About
|
||||
self.aAboutNW = QAction(self.tr("About novelWriter"), self)
|
||||
self.aAboutNW.setMenuRole(QAction.AboutRole)
|
||||
self.aAboutNW.triggered.connect(lambda: self.theParent.showAboutNWDialog())
|
||||
self.aAboutNW.triggered.connect(lambda: self.mainGui.showAboutNWDialog())
|
||||
self.helpMenu.addAction(self.aAboutNW)
|
||||
|
||||
# Help > About Qt5
|
||||
self.aAboutQt = QAction(self.tr("About Qt5"), self)
|
||||
self.aAboutQt.setMenuRole(QAction.AboutQtRole)
|
||||
self.aAboutQt.triggered.connect(lambda: self.theParent.showAboutQtDialog())
|
||||
self.aAboutQt.triggered.connect(lambda: self.mainGui.showAboutQtDialog())
|
||||
self.helpMenu.addAction(self.aAboutQt)
|
||||
|
||||
# Help > Separator
|
||||
@@ -1006,7 +915,7 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
# Document > Check for Updates
|
||||
self.aUpdates = QAction(self.tr("Check for New Release"), self)
|
||||
self.aUpdates.triggered.connect(lambda: self.theParent.showUpdatesDialog())
|
||||
self.aUpdates.triggered.connect(lambda: self.mainGui.showUpdatesDialog())
|
||||
self.helpMenu.addAction(self.aUpdates)
|
||||
|
||||
return
|
||||
|
||||
+525
-130
@@ -4,7 +4,9 @@ novelWriter – GUI Novel Tree
|
||||
GUI classe for the main window novel tree
|
||||
|
||||
File History:
|
||||
Created: 2020-12-20 [1.1a0]
|
||||
Created: 2020-12-20 [1.1a0] GuiNovelTree
|
||||
Created: 2022-06-12 [1.7b1] GuiNovelView
|
||||
Created: 2022-06-12 [1.7b1] GuiNovelToolBar
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2020, Veronica Berglyd Olsen
|
||||
@@ -26,82 +28,390 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from enum import Enum
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtCore import Qt, QSize
|
||||
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView
|
||||
from PyQt5.QtGui import QPalette
|
||||
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
|
||||
QMenu, QSizePolicy, QToolButton, QToolTip, QTreeWidget, QTreeWidgetItem,
|
||||
QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
|
||||
from novelwriter.common import checkInt
|
||||
from novelwriter.constants import nwKeyWords
|
||||
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NovelTreeColumn(Enum):
|
||||
|
||||
HIDDEN = 0
|
||||
POV = 1
|
||||
FOCUS = 2
|
||||
PLOT = 3
|
||||
|
||||
# END Enum NovelTreeColumn
|
||||
|
||||
|
||||
class GuiNovelView(QWidget):
|
||||
|
||||
# Signals for user interaction with the novel tree
|
||||
selectedItemChanged = pyqtSignal(str)
|
||||
openDocumentRequest = pyqtSignal(str, Enum, int, str)
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
|
||||
# Build GUI
|
||||
self.novelBar = GuiNovelToolBar(self)
|
||||
self.novelTree = GuiNovelTree(self)
|
||||
|
||||
# Assemble
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.addWidget(self.novelBar, 0)
|
||||
self.outerBox.addWidget(self.novelTree, 1)
|
||||
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
||||
self.outerBox.setSpacing(0)
|
||||
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
# Function Mappings
|
||||
self.updateWordCounts = self.novelTree.updateWordCounts
|
||||
self.getSelectedHandle = self.novelTree.getSelectedHandle
|
||||
self.setActiveHandle = self.novelTree.setActiveHandle
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def initSettings(self):
|
||||
"""Initialise GUI elements that depend on specific settings.
|
||||
"""
|
||||
self.novelTree.initSettings()
|
||||
return
|
||||
|
||||
def refreshTree(self):
|
||||
"""Refresh the current tree.
|
||||
"""
|
||||
self.novelTree.refreshTree(rootHandle=self.theProject.lastNovel)
|
||||
return
|
||||
|
||||
def clearProject(self):
|
||||
"""Clear project-related GUI content.
|
||||
"""
|
||||
self.novelTree.clearContent()
|
||||
self.novelBar.clearContent()
|
||||
return
|
||||
|
||||
def openProjectTasks(self):
|
||||
"""Run open project tasks.
|
||||
"""
|
||||
lastNovel = self.theProject.lastNovel
|
||||
if lastNovel not in self.theProject.tree:
|
||||
lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||
|
||||
logger.debug("Setting novel tree to root item '%s'", lastNovel)
|
||||
|
||||
lastCol = self.theProject.options.getEnum(
|
||||
"GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.HIDDEN
|
||||
)
|
||||
|
||||
self.clearProject()
|
||||
self.novelBar.buildNovelRootMenu()
|
||||
self.novelBar.setLastColType(lastCol, doRefresh=False)
|
||||
self.novelBar.setCurrentRoot(lastNovel)
|
||||
|
||||
return
|
||||
|
||||
def closeProjectTasks(self):
|
||||
"""Run closing project tasks.
|
||||
"""
|
||||
lastColType = self.novelTree.lastColType
|
||||
self.theProject.options.setValue("GuiNovelView", "lastCol", lastColType)
|
||||
return
|
||||
|
||||
def setTreeFocus(self):
|
||||
"""Set the focus to the tree widget.
|
||||
"""
|
||||
self.novelTree.setFocus()
|
||||
return
|
||||
|
||||
def treeHasFocus(self):
|
||||
"""Check if the novel tree has focus.
|
||||
"""
|
||||
return self.novelTree.hasFocus()
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateRootItem(self, tHandle):
|
||||
"""If any root item changes, rebuild the novel root menu.
|
||||
"""
|
||||
self.novelBar.buildNovelRootMenu()
|
||||
return
|
||||
|
||||
# END Class GuiNovelView
|
||||
|
||||
|
||||
class GuiNovelToolBar(QWidget):
|
||||
|
||||
def __init__(self, novelView):
|
||||
QTreeWidget.__init__(self, novelView)
|
||||
|
||||
logger.debug("Initialising GuiNovelToolBar ...")
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.novelView = novelView
|
||||
self.theProject = novelView.mainGui.theProject
|
||||
self.mainTheme = novelView.mainGui.mainTheme
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
mPx = self.mainConf.pxInt(2)
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setAutoFillBackground(True)
|
||||
|
||||
qPalette = self.palette()
|
||||
qPalette.setBrush(QPalette.Window, qPalette.base())
|
||||
self.setPalette(qPalette)
|
||||
|
||||
fadeCol = qPalette.text().color()
|
||||
buttonStyle = (
|
||||
"QToolButton {{padding: {0}px; border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
|
||||
).format(mPx, fadeCol.red(), fadeCol.green(), fadeCol.blue())
|
||||
|
||||
# Widget Label
|
||||
self.viewLabel = QLabel("<b>%s</b>" % self.tr("Novel Outline"))
|
||||
self.viewLabel.setContentsMargins(0, 0, 0, 0)
|
||||
self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
# Refresh Button
|
||||
self.tbRefresh = QToolButton(self)
|
||||
self.tbRefresh.setToolTip(self.tr("Refresh"))
|
||||
self.tbRefresh.setIcon(self.mainTheme.getIcon("refresh"))
|
||||
self.tbRefresh.setIconSize(QSize(iPx, iPx))
|
||||
self.tbRefresh.setStyleSheet(buttonStyle)
|
||||
self.tbRefresh.clicked.connect(self._refreshNovelTree)
|
||||
|
||||
# Novel Root Menu
|
||||
self.mRoot = QMenu()
|
||||
self.gRoot = QActionGroup(self.mRoot)
|
||||
self.aRoot = {}
|
||||
|
||||
self.tbRoot = QToolButton(self)
|
||||
self.tbRoot.setToolTip(self.tr("Novel Root"))
|
||||
self.tbRoot.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL]))
|
||||
self.tbRoot.setIconSize(QSize(iPx, iPx))
|
||||
self.tbRoot.setStyleSheet(buttonStyle)
|
||||
self.tbRoot.setMenu(self.mRoot)
|
||||
self.tbRoot.setPopupMode(QToolButton.InstantPopup)
|
||||
|
||||
# More Options Menu
|
||||
self.mMore = QMenu()
|
||||
|
||||
self.mLastCol = self.mMore.addMenu(self.tr("Last Column"))
|
||||
self.gLastCol = QActionGroup(self.mMore)
|
||||
self.aLastCol = {}
|
||||
self._addLastColAction(NovelTreeColumn.HIDDEN, self.tr("Hidden"))
|
||||
self._addLastColAction(NovelTreeColumn.POV, self.tr("Point of View Character"))
|
||||
self._addLastColAction(NovelTreeColumn.FOCUS, self.tr("Focus Character"))
|
||||
self._addLastColAction(NovelTreeColumn.PLOT, self.tr("Novel Plot"))
|
||||
|
||||
self.tbMore = QToolButton(self)
|
||||
self.tbMore.setToolTip(self.tr("More Options"))
|
||||
self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
|
||||
self.tbMore.setIconSize(QSize(iPx, iPx))
|
||||
self.tbMore.setStyleSheet(buttonStyle)
|
||||
self.tbMore.setMenu(self.mMore)
|
||||
self.tbMore.setPopupMode(QToolButton.InstantPopup)
|
||||
|
||||
# Assemble
|
||||
self.outerBox = QHBoxLayout()
|
||||
self.outerBox.addWidget(self.viewLabel)
|
||||
self.outerBox.addWidget(self.tbRefresh)
|
||||
self.outerBox.addWidget(self.tbRoot)
|
||||
self.outerBox.addWidget(self.tbMore)
|
||||
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
|
||||
self.outerBox.setSpacing(0)
|
||||
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
logger.debug("GuiNovelToolBar initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def clearContent(self):
|
||||
"""Run clearing project tasks.
|
||||
"""
|
||||
self.mRoot.clear()
|
||||
self.aRoot = {}
|
||||
return
|
||||
|
||||
def buildNovelRootMenu(self):
|
||||
"""Build the novel root menu.
|
||||
"""
|
||||
self.mRoot.clear()
|
||||
self.aRoot = {}
|
||||
for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(nwItemClass.NOVEL)):
|
||||
aRoot = self.mRoot.addAction(nwItem.itemName)
|
||||
aRoot.setData(tHandle)
|
||||
aRoot.setCheckable(True)
|
||||
aRoot.triggered.connect(lambda n, tHandle=tHandle: self.setCurrentRoot(tHandle))
|
||||
self.gRoot.addAction(aRoot)
|
||||
self.aRoot[tHandle] = aRoot
|
||||
|
||||
return
|
||||
|
||||
def setCurrentRoot(self, rootHandle):
|
||||
"""Set the current active root handle.
|
||||
"""
|
||||
if rootHandle in self.aRoot:
|
||||
self.aRoot[rootHandle].setChecked(True)
|
||||
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
||||
return
|
||||
|
||||
def setLastColType(self, colType, doRefresh=True):
|
||||
"""Set the last column type.
|
||||
"""
|
||||
self.aLastCol[colType].setChecked(True)
|
||||
self.novelView.novelTree.setLastColType(colType, doRefresh=doRefresh)
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def _refreshNovelTree(self):
|
||||
"""Rebuild the current tree.
|
||||
"""
|
||||
rootHandle = self.theProject.lastNovel
|
||||
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _addLastColAction(self, colType, actionLabel):
|
||||
"""Add a column selection entry to the last column menu.
|
||||
"""
|
||||
aLast = self.mLastCol.addAction(actionLabel)
|
||||
aLast.setCheckable(True)
|
||||
aLast.setActionGroup(self.gLastCol)
|
||||
aLast.triggered.connect(lambda: self.setLastColType(colType))
|
||||
self.aLastCol[colType] = aLast
|
||||
return
|
||||
|
||||
# END Class GuiNovelToolBar
|
||||
|
||||
|
||||
class GuiNovelTree(QTreeWidget):
|
||||
|
||||
C_TITLE = 0
|
||||
C_WORDS = 1
|
||||
C_POV = 2
|
||||
C_EXTRA = 2
|
||||
C_MORE = 3
|
||||
|
||||
def __init__(self, theParent):
|
||||
QTreeWidget.__init__(self, theParent)
|
||||
D_HANDLE = Qt.UserRole
|
||||
D_TITLE = Qt.UserRole + 1
|
||||
D_KEY = Qt.UserRole + 2
|
||||
|
||||
def __init__(self, novelView):
|
||||
QTreeWidget.__init__(self, novelView)
|
||||
|
||||
logger.debug("Initialising GuiNovelTree ...")
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theTheme = theParent.theTheme
|
||||
self.theProject = theParent.theProject
|
||||
self.theIndex = theParent.theIndex
|
||||
self.novelView = novelView
|
||||
self.mainGui = novelView.mainGui
|
||||
self.mainTheme = novelView.mainGui.mainTheme
|
||||
self.theProject = novelView.mainGui.theProject
|
||||
|
||||
# Internal Variables
|
||||
self._treeMap = {}
|
||||
self._lastBuild = 0
|
||||
self._lastCol = NovelTreeColumn.POV
|
||||
self._actHandle = None
|
||||
|
||||
# Cached Strings
|
||||
self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
|
||||
self._focLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
|
||||
self._pltLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])
|
||||
|
||||
# Build GUI
|
||||
iPx = self.theTheme.baseIconSize
|
||||
# =========
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
cMg = self.mainConf.pxInt(6)
|
||||
|
||||
self.setIconSize(QSize(iPx, iPx))
|
||||
self.setIndentation(iPx)
|
||||
self.setColumnCount(3)
|
||||
self.setHeaderLabels([
|
||||
self.tr("Novel Outline"),
|
||||
self.tr("Words"),
|
||||
self.tr("POV")
|
||||
])
|
||||
self.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||
self.itemSelectionChanged.connect(self._itemSelected)
|
||||
self.setFrameStyle(QFrame.NoFrame)
|
||||
self.setUniformRowHeights(True)
|
||||
self.setAllColumnsShowFocus(True)
|
||||
self.setHeaderHidden(True)
|
||||
self.setIndentation(0)
|
||||
self.setColumnCount(4)
|
||||
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.setExpandsOnDoubleClick(False)
|
||||
self.setDragEnabled(False)
|
||||
|
||||
treeHeadItem = self.headerItem()
|
||||
treeHeadItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
||||
treeHeadItem.setToolTip(self.C_TITLE, self.tr("Section title"))
|
||||
treeHeadItem.setToolTip(self.C_WORDS, self.tr("Word count"))
|
||||
treeHeadItem.setToolTip(self.C_POV, self.tr("Point-of-view character"))
|
||||
|
||||
# Lock the column sizes
|
||||
treeHeader = self.header()
|
||||
treeHeader.setStretchLastSection(True)
|
||||
treeHeader.setMinimumSectionSize(iPx + 6)
|
||||
treeHeader.setStretchLastSection(False)
|
||||
treeHeader.setMinimumSectionSize(iPx + cMg)
|
||||
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
|
||||
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
|
||||
treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeToContents)
|
||||
treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeToContents)
|
||||
|
||||
# Get user's column width preferences for NAME and COUNT
|
||||
treeColWidth = self.mainConf.getNovelColWidths()
|
||||
if len(treeColWidth) <= 3:
|
||||
for colN, colW in enumerate(treeColWidth):
|
||||
self.setColumnWidth(colN, colW)
|
||||
# Pre-Generate Tree Formatting
|
||||
fH1 = self.font()
|
||||
fH1.setBold(True)
|
||||
fH1.setUnderline(True)
|
||||
|
||||
# The last column should just auto-scale
|
||||
self.resizeColumnToContents(self.C_POV)
|
||||
fH2 = self.font()
|
||||
fH2.setBold(True)
|
||||
|
||||
self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
|
||||
self._pIndent = [
|
||||
self.mainTheme.loadDecoration("deco_doc_h0", pxH=iPx),
|
||||
self.mainTheme.loadDecoration("deco_doc_h1", pxH=iPx),
|
||||
self.mainTheme.loadDecoration("deco_doc_h2", pxH=iPx),
|
||||
self.mainTheme.loadDecoration("deco_doc_h3", pxH=iPx),
|
||||
self.mainTheme.loadDecoration("deco_doc_h4", pxH=iPx),
|
||||
]
|
||||
self._pMore = self.mainTheme.loadDecoration("deco_doc_more", pxH=iPx)
|
||||
|
||||
# Connect signals
|
||||
self.clicked.connect(self._treeItemClicked)
|
||||
self.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||
self.itemSelectionChanged.connect(self._treeSelectionChange)
|
||||
|
||||
# Set custom settings
|
||||
self.initTree()
|
||||
self.initSettings()
|
||||
|
||||
logger.debug("GuiNovelTree initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
def initTree(self):
|
||||
def initSettings(self):
|
||||
"""Set or update tree widget settings.
|
||||
"""
|
||||
# Scroll bars
|
||||
@@ -117,11 +427,19 @@ class GuiNovelTree(QTreeWidget):
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def lastColType(self):
|
||||
return self._lastCol
|
||||
|
||||
##
|
||||
# Class Methods
|
||||
##
|
||||
|
||||
def clearTree(self):
|
||||
def clearContent(self):
|
||||
"""Clear the GUI content and the related maps.
|
||||
"""
|
||||
self.clear()
|
||||
@@ -129,12 +447,15 @@ class GuiNovelTree(QTreeWidget):
|
||||
self._lastBuild = 0
|
||||
return
|
||||
|
||||
def refreshTree(self, overRide=False):
|
||||
def refreshTree(self, rootHandle=None, overRide=False):
|
||||
"""Called whenever the Novel tab is activated.
|
||||
"""
|
||||
logger.verbose("Requesting refresh of the novel tree")
|
||||
treeChanged = self.theParent.treeView.changedSince(self._lastBuild)
|
||||
indexChanged = self.theIndex.novelChangedSince(self._lastBuild)
|
||||
if rootHandle is None:
|
||||
rootHandle = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||
|
||||
treeChanged = self.mainGui.projView.changedSince(self._lastBuild)
|
||||
indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild)
|
||||
if not (treeChanged or indexChanged or overRide):
|
||||
logger.verbose("No changes have been made to the novel index")
|
||||
return
|
||||
@@ -142,10 +463,10 @@ class GuiNovelTree(QTreeWidget):
|
||||
selItem = self.selectedItems()
|
||||
titleKey = None
|
||||
if selItem:
|
||||
titleKey = selItem[0].data(self.C_TITLE, Qt.UserRole)[2]
|
||||
titleKey = selItem[0].data(self.C_TITLE, self.D_KEY)
|
||||
|
||||
self.theParent.treeView.flushTreeOrder()
|
||||
self._populateTree()
|
||||
self._populateTree(rootHandle)
|
||||
self.theProject.setLastNovelViewed(rootHandle)
|
||||
|
||||
if titleKey is not None and titleKey in self._treeMap:
|
||||
self._treeMap[titleKey].setSelected(True)
|
||||
@@ -155,21 +476,12 @@ class GuiNovelTree(QTreeWidget):
|
||||
def updateWordCounts(self, tHandle):
|
||||
"""Update the word count for a given handle.
|
||||
"""
|
||||
tHeaders = self.theIndex.getHandleWordCounts(tHandle)
|
||||
tHeaders = self.theProject.index.getHandleWordCounts(tHandle)
|
||||
for titleKey, wCount in tHeaders:
|
||||
if titleKey in self._treeMap:
|
||||
self._treeMap[titleKey].setText(self.C_WORDS, f"{wCount:n}")
|
||||
return
|
||||
|
||||
def getColumnSizes(self):
|
||||
"""Return the column widths for the tree columns.
|
||||
"""
|
||||
retVals = [
|
||||
self.columnWidth(0),
|
||||
self.columnWidth(1),
|
||||
]
|
||||
return retVals
|
||||
|
||||
def getSelectedHandle(self):
|
||||
"""Get the currently selected handle. If multiple items are
|
||||
selected, return the first.
|
||||
@@ -178,11 +490,46 @@ class GuiNovelTree(QTreeWidget):
|
||||
tHandle = None
|
||||
tLine = 0
|
||||
if selItem:
|
||||
tHandle = selItem[0].data(self.C_TITLE, Qt.UserRole)[0]
|
||||
tLine = checkInt(selItem[0].data(self.C_TITLE, Qt.UserRole)[1], 1) - 1
|
||||
tHandle = selItem[0].data(self.C_TITLE, self.D_HANDLE)
|
||||
sTitle = selItem[0].data(self.C_TITLE, self.D_TITLE)
|
||||
tLine = checkInt(sTitle[1:], 1) - 1
|
||||
|
||||
return tHandle, tLine
|
||||
|
||||
def setLastColType(self, colType, doRefresh=True):
|
||||
"""Change the content type of the last column and rebuild.
|
||||
"""
|
||||
if self._lastCol != colType:
|
||||
logger.debug("Changing last column to %s", colType.name)
|
||||
self._lastCol = colType
|
||||
self.setColumnHidden(self.C_EXTRA, colType == NovelTreeColumn.HIDDEN)
|
||||
if doRefresh:
|
||||
self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
|
||||
return
|
||||
|
||||
def setActiveHandle(self, tHandle):
|
||||
"""Highlight the rows associated with a given handle.
|
||||
"""
|
||||
tStart = time()
|
||||
|
||||
self._actHandle = tHandle
|
||||
for i in range(self.topLevelItemCount()):
|
||||
tItem = self.topLevelItem(i)
|
||||
if tItem.data(self.C_TITLE, self.D_HANDLE) == tHandle:
|
||||
tItem.setBackground(self.C_TITLE, self.palette().alternateBase())
|
||||
tItem.setBackground(self.C_WORDS, self.palette().alternateBase())
|
||||
tItem.setBackground(self.C_EXTRA, self.palette().alternateBase())
|
||||
tItem.setBackground(self.C_MORE, self.palette().alternateBase())
|
||||
else:
|
||||
tItem.setBackground(self.C_TITLE, self.palette().base())
|
||||
tItem.setBackground(self.C_WORDS, self.palette().base())
|
||||
tItem.setBackground(self.C_EXTRA, self.palette().base())
|
||||
tItem.setBackground(self.C_MORE, self.palette().base())
|
||||
|
||||
logger.verbose("Highlighted Novel Tree in %.3f ms", (time() - tStart)*1000)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
@@ -208,113 +555,161 @@ class GuiNovelTree(QTreeWidget):
|
||||
if tHandle is None:
|
||||
return
|
||||
|
||||
self.theParent.viewDocument(tHandle)
|
||||
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
|
||||
|
||||
return
|
||||
|
||||
def focusOutEvent(self, theEvent):
|
||||
"""Clear the selection when the tree no longer has focus.
|
||||
"""
|
||||
QTreeWidget.focusOutEvent(self, theEvent)
|
||||
self.clearSelection()
|
||||
return
|
||||
|
||||
##
|
||||
# Slots
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
def _treeDoubleClick(self, tItem, tCol):
|
||||
@pyqtSlot("QModelIndex")
|
||||
def _treeItemClicked(self, mIndex):
|
||||
"""The user clicked on an item in the tree.
|
||||
"""
|
||||
if mIndex.column() == self.C_MORE:
|
||||
tHandle = mIndex.siblingAtColumn(self.C_TITLE).data(self.D_HANDLE)
|
||||
sTitle = mIndex.siblingAtColumn(self.C_TITLE).data(self.D_TITLE)
|
||||
tipPos = self.mapToGlobal(self.visualRect(mIndex).topRight())
|
||||
self._popMetaBox(tipPos, tHandle, sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _treeSelectionChange(self):
|
||||
"""Extract the handle and line number of the currently selected
|
||||
title, and send it to the tree meta panel.
|
||||
"""
|
||||
tHandle, _ = self.getSelectedHandle()
|
||||
if tHandle is not None:
|
||||
self.novelView.selectedItemChanged.emit(tHandle)
|
||||
return
|
||||
|
||||
@pyqtSlot("QTreeWidgetItem*", int)
|
||||
def _treeDoubleClick(self, tItem, colNo):
|
||||
"""Extract the handle and line number of the title double-
|
||||
clicked, and send it to the main gui class for opening in the
|
||||
document editor.
|
||||
"""
|
||||
tHandle, tLine = self.getSelectedHandle()
|
||||
self.theParent.openDocument(tHandle, tLine=tLine-1, doScroll=True)
|
||||
return
|
||||
|
||||
def _itemSelected(self):
|
||||
"""Extract the handle and line number of the currently selected
|
||||
title, and send it to the tree meta panel.
|
||||
"""
|
||||
selItems = self.selectedItems()
|
||||
if selItems:
|
||||
tHandle = selItems[0].data(self.C_TITLE, Qt.UserRole)[0]
|
||||
self.theParent.treeMeta.updateViewBox(tHandle)
|
||||
|
||||
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, tLine, "")
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _populateTree(self):
|
||||
def _populateTree(self, rootHandle):
|
||||
"""Build the tree based on the project index.
|
||||
"""
|
||||
self.clearTree()
|
||||
self.clearContent()
|
||||
tStart = time()
|
||||
logger.verbose("Building novel tree for root item '%s'", rootHandle)
|
||||
|
||||
currTitle = None
|
||||
currChapter = None
|
||||
currScene = None
|
||||
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
||||
for tKey, tHandle, sTitle, novIdx in novStruct:
|
||||
|
||||
for tKey, tHandle, sTitle, novIdx in self.theIndex.novelStructure(skipExcluded=True):
|
||||
iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0)
|
||||
if iLevel == 0:
|
||||
continue
|
||||
|
||||
tItem = self._createTreeItem(tHandle, sTitle, tKey, novIdx)
|
||||
self._treeMap[tKey] = tItem
|
||||
newItem = QTreeWidgetItem()
|
||||
newItem.setData(self.C_TITLE, Qt.DecorationRole, self._pIndent[iLevel])
|
||||
newItem.setText(self.C_TITLE, novIdx.title)
|
||||
newItem.setData(self.C_TITLE, self.D_HANDLE, tHandle)
|
||||
newItem.setData(self.C_TITLE, self.D_TITLE, sTitle)
|
||||
newItem.setData(self.C_TITLE, self.D_KEY, tKey)
|
||||
newItem.setFont(self.C_TITLE, self._hFonts[iLevel])
|
||||
newItem.setText(self.C_WORDS, f"{novIdx.wordCount:n}")
|
||||
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
||||
newItem.setData(self.C_MORE, Qt.DecorationRole, self._pMore)
|
||||
|
||||
tLevel = novIdx["level"]
|
||||
if tLevel == "H1":
|
||||
self.addTopLevelItem(tItem)
|
||||
currTitle = tItem
|
||||
currChapter = None
|
||||
currScene = None
|
||||
# Custom column
|
||||
lastText, toolTip = self._getLastColumnText(tHandle, sTitle)
|
||||
newItem.setText(self.C_EXTRA, lastText)
|
||||
if lastText:
|
||||
newItem.setToolTip(self.C_EXTRA, toolTip)
|
||||
|
||||
elif tLevel == "H2":
|
||||
if currTitle is None:
|
||||
self.addTopLevelItem(tItem)
|
||||
else:
|
||||
currTitle.addChild(tItem)
|
||||
currChapter = tItem
|
||||
currScene = None
|
||||
self._treeMap[tKey] = newItem
|
||||
self.addTopLevelItem(newItem)
|
||||
|
||||
elif tLevel == "H3":
|
||||
if currChapter is None:
|
||||
if currTitle is None:
|
||||
self.addTopLevelItem(tItem)
|
||||
else:
|
||||
currTitle.addChild(tItem)
|
||||
else:
|
||||
currChapter.addChild(tItem)
|
||||
currScene = tItem
|
||||
|
||||
elif tLevel == "H4":
|
||||
if currScene is None:
|
||||
if currChapter is None:
|
||||
if currTitle is None:
|
||||
self.addTopLevelItem(tItem)
|
||||
else:
|
||||
currTitle.addChild(tItem)
|
||||
else:
|
||||
currChapter.addChild(tItem)
|
||||
else:
|
||||
currScene.addChild(tItem)
|
||||
|
||||
tItem.setExpanded(True)
|
||||
self.setActiveHandle(self._actHandle)
|
||||
|
||||
logger.verbose("Novel Tree built in %.3f ms", (time() - tStart)*1000)
|
||||
self._lastBuild = time()
|
||||
|
||||
return
|
||||
|
||||
def _createTreeItem(self, tHandle, sTitle, titleKey, novIdx):
|
||||
"""Populate a tree item with all the column values.
|
||||
def _getLastColumnText(self, tHandle, sTitle):
|
||||
"""Generate the text for the last column based on user settings.
|
||||
"""
|
||||
newItem = QTreeWidgetItem()
|
||||
hIcon = "doc_%s" % novIdx["level"].lower()
|
||||
theData = (tHandle, sTitle[1:].lstrip("0"), titleKey)
|
||||
if self._lastCol == NovelTreeColumn.HIDDEN:
|
||||
return "", ""
|
||||
|
||||
wC = int(novIdx["wCount"])
|
||||
theRefs = self.theProject.index.getReferences(tHandle, sTitle)
|
||||
if self._lastCol == NovelTreeColumn.POV:
|
||||
newText = ", ".join(theRefs[nwKeyWords.POV_KEY])
|
||||
return newText, f"{self._povLabel}: {newText}"
|
||||
|
||||
newItem.setText(self.C_TITLE, novIdx["title"])
|
||||
newItem.setData(self.C_TITLE, Qt.UserRole, theData)
|
||||
newItem.setIcon(self.C_TITLE, self.theTheme.getIcon(hIcon))
|
||||
newItem.setText(self.C_WORDS, f"{wC:n}")
|
||||
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
||||
elif self._lastCol == NovelTreeColumn.FOCUS:
|
||||
newText = ", ".join(theRefs[nwKeyWords.FOCUS_KEY])
|
||||
return newText, f"{self._focLabel}: {newText}"
|
||||
|
||||
theRefs = self.theIndex.getReferences(tHandle, sTitle)
|
||||
newItem.setText(self.C_POV, ", ".join(theRefs[nwKeyWords.POV_KEY]))
|
||||
elif self._lastCol == NovelTreeColumn.PLOT:
|
||||
newText = ", ".join(theRefs[nwKeyWords.PLOT_KEY])
|
||||
return newText, f"{self._pltLabel}: {newText}"
|
||||
|
||||
return newItem
|
||||
return "", ""
|
||||
|
||||
def _popMetaBox(self, qPos, tHandle, sTitle):
|
||||
"""Show the novel meta data box.
|
||||
"""
|
||||
logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
|
||||
|
||||
pIndex = self.theProject.index
|
||||
novIdx = pIndex.getNovelData(tHandle, sTitle)
|
||||
refTags = pIndex.getReferences(tHandle, sTitle)
|
||||
|
||||
synopText = novIdx.synopsis
|
||||
if synopText:
|
||||
synopLabel = trConst(nwLabels.OUTLINE_COLS[nwOutline.SYNOP])
|
||||
synopText = f"<p><b>{synopLabel}</b>: {synopText}</p>"
|
||||
|
||||
refLines = []
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.POV_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.FOCUS_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.CHAR_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.PLOT_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.TIME_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.WORLD_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.OBJECT_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.ENTITY_KEY, refLines)
|
||||
refLines = self._appendMetaTag(refTags, nwKeyWords.CUSTOM_KEY, refLines)
|
||||
|
||||
refText = ""
|
||||
if refLines:
|
||||
refList = "<br>".join(refLines)
|
||||
refText = f"<p>{refList}</p>"
|
||||
|
||||
ttText = refText + synopText or self.tr("No meta data")
|
||||
if ttText:
|
||||
QToolTip.showText(qPos, ttText)
|
||||
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def _appendMetaTag(refs, key, lines):
|
||||
"""Generate a reference list for a given reference key.
|
||||
"""
|
||||
tags = ", ".join(refs.get(key, []))
|
||||
if tags:
|
||||
lines.append(f"<b>{trConst(nwLabels.KEY_NAME[key])}</b>: {tags}")
|
||||
return lines
|
||||
|
||||
# END Class GuiNovelTree
|
||||
|
||||
+734
-155
File diff suppressed because it is too large
Load Diff
@@ -1,349 +0,0 @@
|
||||
"""
|
||||
novelWriter – GUI Project Outline Details
|
||||
=========================================
|
||||
GUI class for the project outline details panel
|
||||
|
||||
File History:
|
||||
Created: 2020-06-02 [0.7.0]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2022, Veronica Berglyd Olsen
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
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/>.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from PyQt5.QtCore import Qt, QT_TRANSLATE_NOOP
|
||||
from PyQt5.QtWidgets import (
|
||||
QScrollArea, QWidget, QGridLayout, QHBoxLayout, QGroupBox, QLabel
|
||||
)
|
||||
|
||||
from novelwriter.common import checkInt
|
||||
from novelwriter.constants import trConst, nwKeyWords, nwLabels
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiOutlineDetails(QScrollArea):
|
||||
|
||||
LVL_MAP = {
|
||||
"H1": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Title"),
|
||||
"H2": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Chapter"),
|
||||
"H3": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Scene"),
|
||||
"H4": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Section"),
|
||||
}
|
||||
|
||||
def __init__(self, theParent):
|
||||
QScrollArea.__init__(self, theParent)
|
||||
|
||||
logger.debug("Initialising GuiOutlineDetails ...")
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theProject = theParent.theProject
|
||||
self.theTheme = theParent.theTheme
|
||||
self.theIndex = theParent.theIndex
|
||||
self.optState = theParent.theProject.optState
|
||||
|
||||
# Sizes
|
||||
minTitle = 30*self.theTheme.textNWidth
|
||||
maxTitle = 40*self.theTheme.textNWidth
|
||||
wCount = self.theTheme.getTextWidth("999,999")
|
||||
hSpace = int(self.mainConf.pxInt(10))
|
||||
vSpace = int(self.mainConf.pxInt(4))
|
||||
|
||||
# Details Area
|
||||
self.titleLabel = QLabel("<b>%s</b>" % self.tr("Title"))
|
||||
self.fileLabel = QLabel("<b>%s</b>" % self.tr("Document"))
|
||||
self.itemLabel = QLabel("<b>%s</b>" % self.tr("Status"))
|
||||
self.titleValue = QLabel("")
|
||||
self.fileValue = QLabel("")
|
||||
self.itemValue = QLabel("")
|
||||
|
||||
self.titleValue.setMinimumWidth(minTitle)
|
||||
self.titleValue.setMaximumWidth(maxTitle)
|
||||
self.fileValue.setMinimumWidth(minTitle)
|
||||
self.fileValue.setMaximumWidth(maxTitle)
|
||||
self.itemValue.setMinimumWidth(minTitle)
|
||||
self.itemValue.setMaximumWidth(maxTitle)
|
||||
|
||||
# Stats Area
|
||||
self.cCLabel = QLabel("<b>%s</b>" % self.tr("Characters"))
|
||||
self.wCLabel = QLabel("<b>%s</b>" % self.tr("Words"))
|
||||
self.pCLabel = QLabel("<b>%s</b>" % self.tr("Paragraphs"))
|
||||
self.cCValue = QLabel("")
|
||||
self.wCValue = QLabel("")
|
||||
self.pCValue = QLabel("")
|
||||
|
||||
self.cCValue.setMinimumWidth(wCount)
|
||||
self.wCValue.setMinimumWidth(wCount)
|
||||
self.pCValue.setMinimumWidth(wCount)
|
||||
self.cCValue.setAlignment(Qt.AlignRight)
|
||||
self.wCValue.setAlignment(Qt.AlignRight)
|
||||
self.pCValue.setAlignment(Qt.AlignRight)
|
||||
|
||||
# Synopsis
|
||||
self.synopLabel = QLabel("<b>%s</b>" % self.tr("Synopsis"))
|
||||
self.synopValue = QLabel("")
|
||||
self.synopLWrap = QHBoxLayout()
|
||||
self.synopValue.setWordWrap(True)
|
||||
self.synopValue.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
self.synopLWrap.addWidget(self.synopValue, 1)
|
||||
|
||||
# Tags
|
||||
self.povKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]))
|
||||
self.focKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]))
|
||||
self.chrKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY]))
|
||||
self.pltKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]))
|
||||
self.timKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.TIME_KEY]))
|
||||
self.wldKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY]))
|
||||
self.objKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY]))
|
||||
self.entKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY]))
|
||||
self.cstKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY]))
|
||||
|
||||
self.povKeyLWrap = QHBoxLayout()
|
||||
self.focKeyLWrap = QHBoxLayout()
|
||||
self.chrKeyLWrap = QHBoxLayout()
|
||||
self.pltKeyLWrap = QHBoxLayout()
|
||||
self.timKeyLWrap = QHBoxLayout()
|
||||
self.wldKeyLWrap = QHBoxLayout()
|
||||
self.objKeyLWrap = QHBoxLayout()
|
||||
self.entKeyLWrap = QHBoxLayout()
|
||||
self.cstKeyLWrap = QHBoxLayout()
|
||||
|
||||
self.povKeyValue = QLabel("")
|
||||
self.focKeyValue = QLabel("")
|
||||
self.chrKeyValue = QLabel("")
|
||||
self.pltKeyValue = QLabel("")
|
||||
self.timKeyValue = QLabel("")
|
||||
self.wldKeyValue = QLabel("")
|
||||
self.objKeyValue = QLabel("")
|
||||
self.entKeyValue = QLabel("")
|
||||
self.cstKeyValue = QLabel("")
|
||||
|
||||
self.povKeyValue.setWordWrap(True)
|
||||
self.focKeyValue.setWordWrap(True)
|
||||
self.chrKeyValue.setWordWrap(True)
|
||||
self.pltKeyValue.setWordWrap(True)
|
||||
self.timKeyValue.setWordWrap(True)
|
||||
self.wldKeyValue.setWordWrap(True)
|
||||
self.objKeyValue.setWordWrap(True)
|
||||
self.entKeyValue.setWordWrap(True)
|
||||
self.cstKeyValue.setWordWrap(True)
|
||||
|
||||
self.povKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.focKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.chrKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.pltKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.timKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.wldKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.objKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.entKeyValue.linkActivated.connect(self._tagClicked)
|
||||
self.cstKeyValue.linkActivated.connect(self._tagClicked)
|
||||
|
||||
self.povKeyLWrap.addWidget(self.povKeyValue, 1)
|
||||
self.focKeyLWrap.addWidget(self.focKeyValue, 1)
|
||||
self.chrKeyLWrap.addWidget(self.chrKeyValue, 1)
|
||||
self.pltKeyLWrap.addWidget(self.pltKeyValue, 1)
|
||||
self.timKeyLWrap.addWidget(self.timKeyValue, 1)
|
||||
self.wldKeyLWrap.addWidget(self.wldKeyValue, 1)
|
||||
self.objKeyLWrap.addWidget(self.objKeyValue, 1)
|
||||
self.entKeyLWrap.addWidget(self.entKeyValue, 1)
|
||||
self.cstKeyLWrap.addWidget(self.cstKeyValue, 1)
|
||||
|
||||
# Selected Item Details
|
||||
self.mainGroup = QGroupBox(self.tr("Title Details"), self)
|
||||
self.mainForm = QGridLayout()
|
||||
self.mainGroup.setLayout(self.mainForm)
|
||||
|
||||
self.mainForm.addWidget(self.titleLabel, 0, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.titleValue, 0, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.cCLabel, 0, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.cCValue, 0, 3, 1, 1, Qt.AlignTop | Qt.AlignRight)
|
||||
self.mainForm.addWidget(self.fileLabel, 1, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.fileValue, 1, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.wCLabel, 1, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.wCValue, 1, 3, 1, 1, Qt.AlignTop | Qt.AlignRight)
|
||||
self.mainForm.addWidget(self.itemLabel, 2, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.itemValue, 2, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.pCLabel, 2, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addWidget(self.pCValue, 2, 3, 1, 1, Qt.AlignTop | Qt.AlignRight)
|
||||
self.mainForm.addWidget(self.synopLabel, 3, 0, 1, 4, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.mainForm.addLayout(self.synopLWrap, 4, 0, 1, 4, Qt.AlignTop | Qt.AlignLeft)
|
||||
|
||||
self.mainForm.setColumnStretch(1, 1)
|
||||
self.mainForm.setRowStretch(4, 1)
|
||||
self.mainForm.setHorizontalSpacing(hSpace)
|
||||
self.mainForm.setVerticalSpacing(vSpace)
|
||||
|
||||
# Selected Item Tags
|
||||
self.tagsGroup = QGroupBox(self.tr("Reference Tags"), self)
|
||||
self.tagsForm = QGridLayout()
|
||||
self.tagsGroup.setLayout(self.tagsForm)
|
||||
|
||||
self.tagsForm.addWidget(self.povKeyLabel, 0, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.povKeyLWrap, 0, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.focKeyLabel, 1, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.focKeyLWrap, 1, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.chrKeyLabel, 2, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.chrKeyLWrap, 2, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.pltKeyLabel, 3, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.pltKeyLWrap, 3, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.timKeyLabel, 4, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.timKeyLWrap, 4, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.wldKeyLabel, 5, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.wldKeyLWrap, 5, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.objKeyLabel, 6, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.objKeyLWrap, 6, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.entKeyLabel, 7, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.entKeyLWrap, 7, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addWidget(self.cstKeyLabel, 8, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
self.tagsForm.addLayout(self.cstKeyLWrap, 8, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
|
||||
|
||||
self.tagsForm.setColumnStretch(1, 1)
|
||||
self.tagsForm.setRowStretch(8, 1)
|
||||
self.tagsForm.setHorizontalSpacing(hSpace)
|
||||
self.tagsForm.setVerticalSpacing(vSpace)
|
||||
|
||||
# Assemble
|
||||
self.outerWidget = QWidget()
|
||||
self.outerBox = QHBoxLayout()
|
||||
self.outerBox.addWidget(self.mainGroup, 0)
|
||||
self.outerBox.addWidget(self.tagsGroup, 1)
|
||||
|
||||
self.outerWidget.setLayout(self.outerBox)
|
||||
self.setWidget(self.outerWidget)
|
||||
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.setWidgetResizable(True)
|
||||
|
||||
self.initDetails()
|
||||
|
||||
logger.debug("GuiOutlineDetails initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
def initDetails(self):
|
||||
"""Set or update outline settings.
|
||||
"""
|
||||
# Scroll bars
|
||||
if self.mainConf.hideVScroll:
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
else:
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
|
||||
if self.mainConf.hideHScroll:
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
else:
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
|
||||
return
|
||||
|
||||
def clearDetails(self):
|
||||
"""Clear all the data labels.
|
||||
"""
|
||||
self.titleLabel.setText("<b>%s</b>" % self.tr("Title"))
|
||||
self.titleValue.setText("")
|
||||
self.fileValue.setText("")
|
||||
self.itemValue.setText("")
|
||||
self.cCValue.setText("")
|
||||
self.wCValue.setText("")
|
||||
self.pCValue.setText("")
|
||||
self.synopValue.setText("")
|
||||
self.povKeyValue.setText("")
|
||||
self.focKeyValue.setText("")
|
||||
self.chrKeyValue.setText("")
|
||||
self.pltKeyValue.setText("")
|
||||
self.timKeyValue.setText("")
|
||||
self.wldKeyValue.setText("")
|
||||
self.objKeyValue.setText("")
|
||||
self.entKeyValue.setText("")
|
||||
self.cstKeyValue.setText("")
|
||||
return
|
||||
|
||||
def showItem(self, tHandle, sTitle):
|
||||
"""Update the content of the tree with the given handle and line
|
||||
number pointing to a header.
|
||||
"""
|
||||
nwItem = self.theProject.projTree[tHandle]
|
||||
novIdx = self.theIndex.getNovelData(tHandle, sTitle)
|
||||
theRefs = self.theIndex.getReferences(tHandle, sTitle)
|
||||
if nwItem is None or novIdx is None:
|
||||
return False
|
||||
|
||||
if novIdx["level"] in self.LVL_MAP:
|
||||
self.titleLabel.setText("<b>%s</b>" % self.tr(self.LVL_MAP[novIdx["level"]]))
|
||||
else:
|
||||
self.titleLabel.setText("<b>%s</b>" % self.tr("Title"))
|
||||
self.titleValue.setText(novIdx["title"])
|
||||
|
||||
self.fileValue.setText(nwItem.itemName)
|
||||
self.itemValue.setText(nwItem.itemStatus)
|
||||
|
||||
cC = checkInt(novIdx["cCount"], 0)
|
||||
wC = checkInt(novIdx["wCount"], 0)
|
||||
pC = checkInt(novIdx["pCount"], 0)
|
||||
|
||||
self.cCValue.setText(f"{cC:n}")
|
||||
self.wCValue.setText(f"{wC:n}")
|
||||
self.pCValue.setText(f"{pC:n}")
|
||||
|
||||
self.synopValue.setText(novIdx["synopsis"])
|
||||
|
||||
self.povKeyValue.setText(self._formatTags(theRefs, nwKeyWords.POV_KEY))
|
||||
self.focKeyValue.setText(self._formatTags(theRefs, nwKeyWords.FOCUS_KEY))
|
||||
self.chrKeyValue.setText(self._formatTags(theRefs, nwKeyWords.CHAR_KEY))
|
||||
self.pltKeyValue.setText(self._formatTags(theRefs, nwKeyWords.PLOT_KEY))
|
||||
self.timKeyValue.setText(self._formatTags(theRefs, nwKeyWords.TIME_KEY))
|
||||
self.wldKeyValue.setText(self._formatTags(theRefs, nwKeyWords.WORLD_KEY))
|
||||
self.objKeyValue.setText(self._formatTags(theRefs, nwKeyWords.OBJECT_KEY))
|
||||
self.entKeyValue.setText(self._formatTags(theRefs, nwKeyWords.ENTITY_KEY))
|
||||
self.cstKeyValue.setText(self._formatTags(theRefs, nwKeyWords.CUSTOM_KEY))
|
||||
|
||||
return True
|
||||
|
||||
##
|
||||
# Slots
|
||||
##
|
||||
|
||||
def _tagClicked(self, theLink):
|
||||
"""Capture the click of a tag in the right-most column.
|
||||
"""
|
||||
logger.verbose("Clicked link: '%s'", theLink)
|
||||
if len(theLink) > 0:
|
||||
theBits = theLink.split("=")
|
||||
if len(theBits) == 2:
|
||||
self.theParent.docViewer.loadFromTag(theBits[1])
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatTags(self, theRefs, theKey):
|
||||
"""Format the tags as clickable links.
|
||||
"""
|
||||
if theKey not in theRefs:
|
||||
return ""
|
||||
refTags = []
|
||||
for tTag in theRefs[theKey]:
|
||||
refTags.append("<a href='#%s=%s'>%s</a>" % (
|
||||
theKey[1:], tTag, tTag
|
||||
))
|
||||
return ", ".join(refTags)
|
||||
|
||||
# END Class GuiOutlineDetails
|
||||
+768
-633
File diff suppressed because it is too large
Load Diff
@@ -41,22 +41,22 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiMainStatus(QStatusBar):
|
||||
|
||||
def __init__(self, theParent):
|
||||
QStatusBar.__init__(self, theParent)
|
||||
def __init__(self, mainGui):
|
||||
QStatusBar.__init__(self, mainGui)
|
||||
|
||||
logger.debug("Initialising GuiMainStatus ...")
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theParent = theParent
|
||||
self.theTheme = theParent.theTheme
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.refTime = None
|
||||
self.userIdle = False
|
||||
|
||||
colNone = QColor(*self.theTheme.statNone)
|
||||
colTrue = QColor(*self.theTheme.statUnsaved)
|
||||
colFalse = QColor(*self.theTheme.statSaved)
|
||||
colNone = QColor(*self.mainTheme.statNone)
|
||||
colTrue = QColor(*self.mainTheme.statUnsaved)
|
||||
colFalse = QColor(*self.mainTheme.statSaved)
|
||||
|
||||
iPx = self.theTheme.baseIconSize
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
|
||||
# Permanent Widgets
|
||||
# =================
|
||||
@@ -66,7 +66,7 @@ class GuiMainStatus(QStatusBar):
|
||||
# The Spell Checker Language
|
||||
self.langIcon = QLabel("")
|
||||
self.langText = QLabel(self.tr("None"))
|
||||
self.langIcon.setPixmap(self.theTheme.getPixmap("status_lang", (iPx, iPx)))
|
||||
self.langIcon.setPixmap(self.mainTheme.getPixmap("status_lang", (iPx, iPx)))
|
||||
self.langIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.langText.setContentsMargins(0, 0, xM, 0)
|
||||
self.addPermanentWidget(self.langIcon)
|
||||
@@ -91,7 +91,7 @@ class GuiMainStatus(QStatusBar):
|
||||
# The Project and Session Stats
|
||||
self.statsIcon = QLabel()
|
||||
self.statsText = QLabel("")
|
||||
self.statsIcon.setPixmap(self.theTheme.getPixmap("status_stats", (iPx, iPx)))
|
||||
self.statsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (iPx, iPx)))
|
||||
self.statsIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.statsText.setContentsMargins(0, 0, xM, 0)
|
||||
self.addPermanentWidget(self.statsIcon)
|
||||
@@ -99,14 +99,14 @@ class GuiMainStatus(QStatusBar):
|
||||
|
||||
# The Session Clock
|
||||
# Set the mimimum width so the label doesn't rescale every second
|
||||
self.timePixmap = self.theTheme.getPixmap("status_time", (iPx, iPx))
|
||||
self.idlePixmap = self.theTheme.getPixmap("status_idle", (iPx, iPx))
|
||||
self.timePixmap = self.mainTheme.getPixmap("status_time", (iPx, iPx))
|
||||
self.idlePixmap = self.mainTheme.getPixmap("status_idle", (iPx, iPx))
|
||||
|
||||
self.timeIcon = QLabel()
|
||||
self.timeText = QLabel("")
|
||||
self.timeIcon.setPixmap(self.timePixmap)
|
||||
self.timeText.setToolTip(self.tr("Session Time"))
|
||||
self.timeText.setMinimumWidth(self.theTheme.getTextWidth("00:00:00:"))
|
||||
self.timeText.setMinimumWidth(self.mainTheme.getTextWidth("00:00:00:"))
|
||||
self.timeIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.timeText.setContentsMargins(0, 0, 0, 0)
|
||||
self.addPermanentWidget(self.timeIcon)
|
||||
|
||||
+32
-31
@@ -54,7 +54,7 @@ class GuiTheme:
|
||||
def __init__(self):
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theIcons = GuiIcons(self)
|
||||
self.iconCache = GuiIcons(self)
|
||||
|
||||
# Loaded Theme Settings
|
||||
# =====================
|
||||
@@ -127,13 +127,13 @@ class GuiTheme:
|
||||
|
||||
self.updateFont()
|
||||
self.updateTheme()
|
||||
self.theIcons.updateTheme()
|
||||
self.iconCache.updateTheme()
|
||||
|
||||
# Icon Functions
|
||||
self.getIcon = self.theIcons.getIcon
|
||||
self.getPixmap = self.theIcons.getPixmap
|
||||
self.getItemIcon = self.theIcons.getItemIcon
|
||||
self.loadDecoration = self.theIcons.loadDecoration
|
||||
self.getIcon = self.iconCache.getIcon
|
||||
self.getPixmap = self.iconCache.getPixmap
|
||||
self.getItemIcon = self.iconCache.getItemIcon
|
||||
self.loadDecoration = self.iconCache.loadDecoration
|
||||
|
||||
# Extract Other Info
|
||||
self.guiDPI = qApp.primaryScreen().logicalDotsPerInchX()
|
||||
@@ -456,34 +456,35 @@ class GuiIcons:
|
||||
|
||||
ICON_KEYS = {
|
||||
# Project and GUI icons
|
||||
"novelwriter", "proj_nwx",
|
||||
"cls_none", "cls_novel", "cls_plot", "cls_character", "cls_world",
|
||||
"cls_timeline", "cls_object", "cls_entity", "cls_custom", "cls_archive", "cls_trash",
|
||||
"proj_document", "proj_title", "proj_chapter", "proj_scene", "proj_note", "proj_folder",
|
||||
"status_lang", "status_time", "status_idle", "status_stats", "status_lines",
|
||||
"doc_h0", "doc_h1", "doc_h2", "doc_h3", "doc_h4",
|
||||
"search_case", "search_regex", "search_word", "search_loop", "search_project",
|
||||
"search_cancel", "search_preserve",
|
||||
"novelwriter", "cls_archive", "cls_character", "cls_custom", "cls_entity", "cls_none",
|
||||
"cls_novel", "cls_object", "cls_plot", "cls_timeline", "cls_trash", "cls_world", "doc_h0",
|
||||
"doc_h1", "doc_h2", "doc_h3", "doc_h4", "proj_chapter", "proj_details", "proj_document",
|
||||
"proj_folder", "proj_note", "proj_nwx", "proj_scene", "proj_stats", "proj_title",
|
||||
"search_cancel", "search_case", "search_loop", "search_preserve", "search_project",
|
||||
"search_regex", "search_word", "status_idle", "status_lang", "status_lines",
|
||||
"status_stats", "status_time", "view_build", "view_editor", "view_novel", "view_outline",
|
||||
|
||||
# General Button Icons
|
||||
"delete", "close", "done", "clear", "save", "add", "remove",
|
||||
"search", "search_replace", "edit", "check", "cross", "hash",
|
||||
"maximise", "minimise", "refresh", "reference", "backward",
|
||||
"forward", "settings",
|
||||
"add", "backward", "check", "clear", "close", "cross", "delete", "done", "down", "edit",
|
||||
"forward", "hash", "maximise", "menu", "minimise", "reference", "refresh", "remove",
|
||||
"save", "search_replace", "search", "settings", "up",
|
||||
|
||||
# Switches
|
||||
"sticky-on", "sticky-off",
|
||||
"bullet-on", "bullet-off",
|
||||
|
||||
# Decorations
|
||||
"deco_doc_h0", "deco_doc_h1", "deco_doc_h2", "deco_doc_h3", "deco_doc_h4", "deco_doc_more",
|
||||
}
|
||||
|
||||
DECO_MAP = {
|
||||
IMAGE_MAP = {
|
||||
"wiz-back": "wizard-back.jpg",
|
||||
}
|
||||
|
||||
def __init__(self, theTheme):
|
||||
def __init__(self, mainTheme):
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theTheme = theTheme
|
||||
self.mainTheme = mainTheme
|
||||
|
||||
# Storage
|
||||
self._qIcons = {}
|
||||
@@ -575,19 +576,22 @@ class GuiIcons:
|
||||
# Access Functions
|
||||
##
|
||||
|
||||
def loadDecoration(self, decoKey, pxW, pxH):
|
||||
def loadDecoration(self, decoKey, pxW=None, pxH=None):
|
||||
"""Load graphical decoration element based on the decoration
|
||||
map. This function always returns a QSwgWidget.
|
||||
map or the icon map. This function always returns a QPixmap.
|
||||
"""
|
||||
if decoKey not in self.DECO_MAP:
|
||||
if decoKey in self._themeMap:
|
||||
imgPath = self._themeMap[decoKey]
|
||||
elif decoKey in self.IMAGE_MAP:
|
||||
imgPath = os.path.join(
|
||||
self.mainConf.assetPath, "images", self.IMAGE_MAP[decoKey]
|
||||
)
|
||||
else:
|
||||
logger.error("Decoration with name '%s' does not exist", decoKey)
|
||||
return QPixmap()
|
||||
|
||||
imgPath = os.path.join(
|
||||
self.mainConf.assetPath, "images", self.DECO_MAP[decoKey]
|
||||
)
|
||||
if not os.path.isfile(imgPath):
|
||||
logger.error("Decoration file '%s' not in assets folder", self.DECO_MAP[decoKey])
|
||||
logger.error("Asset '%s' not found", self.IMAGE_MAP[decoKey])
|
||||
return QPixmap()
|
||||
|
||||
theDeco = QPixmap(imgPath)
|
||||
@@ -639,9 +643,6 @@ class GuiIcons:
|
||||
iconName = "proj_scene"
|
||||
elif tLayout == nwItemLayout.NOTE:
|
||||
iconName = "proj_note"
|
||||
elif tType == nwItemType.TRASH:
|
||||
iconName = nwLabels.CLASS_ICON[tClass]
|
||||
|
||||
if iconName is None:
|
||||
return QIcon()
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
"""
|
||||
novelWriter – GUI Main Window Views ToolBar
|
||||
===========================================
|
||||
GUI class for the main window "Views" toolbar
|
||||
|
||||
File History:
|
||||
Created: 2022-05-10 [1.7b1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2022, Veronica Berglyd Olsen
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
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/>.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from PyQt5.QtCore import Qt, QSize, pyqtSignal
|
||||
from PyQt5.QtWidgets import (
|
||||
QToolBar, QWidget, QSizePolicy, QAction, QMenu, QToolButton
|
||||
)
|
||||
|
||||
from novelwriter.enum import nwView
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiViewsBar(QToolBar):
|
||||
|
||||
viewChangeRequested = pyqtSignal(nwView)
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QToolBar.__init__(self, mainGui)
|
||||
|
||||
logger.debug("Initialising GuiViewsBar ...")
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
|
||||
# Style
|
||||
iPx = self.mainConf.pxInt(22)
|
||||
mPx = self.mainConf.pxInt(60)
|
||||
|
||||
lblFont = self.mainTheme.guiFont
|
||||
lblFont.setPointSizeF(0.65*self.mainTheme.fontPointSize)
|
||||
|
||||
self.setMovable(False)
|
||||
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
self.setIconSize(QSize(iPx, iPx))
|
||||
self.setMaximumWidth(mPx)
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setStyleSheet("QToolBar {border: 0px;}")
|
||||
|
||||
stretch = QWidget(self)
|
||||
stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
# Actions
|
||||
self.aProject = QAction(self.tr("Project"))
|
||||
self.aProject.setFont(lblFont)
|
||||
self.aProject.setToolTip(self.tr("Show project tree and editor"))
|
||||
self.aProject.setIcon(self.mainTheme.getIcon("view_editor"))
|
||||
self.aProject.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT))
|
||||
|
||||
self.aNovel = QAction(self.tr("Novel"))
|
||||
self.aNovel.setFont(lblFont)
|
||||
self.aNovel.setToolTip(self.tr("Show novel tree and editor"))
|
||||
self.aNovel.setIcon(self.mainTheme.getIcon("view_novel"))
|
||||
self.aNovel.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
|
||||
|
||||
self.aOutline = QAction(self.tr("Outline"))
|
||||
self.aOutline.setFont(lblFont)
|
||||
self.aOutline.setToolTip(self.tr("Show novel outline"))
|
||||
self.aOutline.setIcon(self.mainTheme.getIcon("view_outline"))
|
||||
self.aOutline.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
|
||||
|
||||
self.aBuild = QAction(self.tr("Build"))
|
||||
self.aBuild.setFont(lblFont)
|
||||
self.aBuild.setToolTip(self.tr("Build novel project"))
|
||||
self.aBuild.setIcon(self.mainTheme.getIcon("view_build"))
|
||||
self.aBuild.triggered.connect(lambda: self.mainGui.showBuildProjectDialog())
|
||||
|
||||
self.aDetails = QAction(self.tr("Details"))
|
||||
self.aDetails.setFont(lblFont)
|
||||
self.aDetails.setToolTip(self.tr("Show project details"))
|
||||
self.aDetails.setIcon(self.mainTheme.getIcon("proj_details"))
|
||||
self.aDetails.triggered.connect(lambda: self.mainGui.showProjectDetailsDialog())
|
||||
|
||||
self.aStats = QAction(self.tr("Stats"))
|
||||
self.aStats.setFont(lblFont)
|
||||
self.aStats.setToolTip(self.tr("Show project statistics"))
|
||||
self.aStats.setIcon(self.mainTheme.getIcon("proj_stats"))
|
||||
self.aStats.triggered.connect(lambda: self.mainGui.showWritingStatsDialog())
|
||||
|
||||
# Settings Menu
|
||||
self.mSettings = QMenu()
|
||||
|
||||
self.aPrjSettings = QAction(self.tr("Project Settings"))
|
||||
self.aPrjSettings.triggered.connect(lambda: self.mainGui.showProjectSettingsDialog())
|
||||
self.mSettings.addAction(self.aPrjSettings)
|
||||
|
||||
self.aPreferences = QAction(self.tr("Preferences"))
|
||||
self.aPreferences.triggered.connect(lambda: self.mainGui.showPreferencesDialog())
|
||||
self.mSettings.addAction(self.aPreferences)
|
||||
|
||||
self.tbSettings = QToolButton(self)
|
||||
self.tbSettings.setFont(lblFont)
|
||||
self.tbSettings.setText(self.tr("Settings"))
|
||||
self.tbSettings.setIcon(self.mainTheme.getIcon("settings"))
|
||||
self.tbSettings.setMenu(self.mSettings)
|
||||
self.tbSettings.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
self.tbSettings.setPopupMode(QToolButton.InstantPopup)
|
||||
|
||||
# Assemble
|
||||
self.addAction(self.aProject)
|
||||
self.addAction(self.aNovel)
|
||||
self.addAction(self.aOutline)
|
||||
self.addAction(self.aBuild)
|
||||
self.addWidget(stretch)
|
||||
self.addAction(self.aDetails)
|
||||
self.addAction(self.aStats)
|
||||
self.addWidget(self.tbSettings)
|
||||
|
||||
logger.debug("GuiViewsBar initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiViewsBar
|
||||
Reference in New Issue
Block a user