Add novel tree toolbar and connect actions
This commit is contained in:
@@ -102,6 +102,8 @@ class NWProject():
|
|||||||
self.importItems = None # Note file importance values
|
self.importItems = None # Note file importance values
|
||||||
self.lastEdited = None # The handle of the last file to be edited
|
self.lastEdited = None # The handle of the last file to be edited
|
||||||
self.lastViewed = None # The handle of the last file to be viewed
|
self.lastViewed = None # The handle of the last file to be viewed
|
||||||
|
self.lastNovel = None # The handle of the last novel root viewed
|
||||||
|
self.lastOutline = None # The handle of the last outline root viewed
|
||||||
self.lastWCount = 0 # The project word count from last session
|
self.lastWCount = 0 # The project word count from last session
|
||||||
self.lastNovelWC = 0 # The novel files word count from last session
|
self.lastNovelWC = 0 # The novel files word count from last session
|
||||||
self.lastNotesWC = 0 # The note files word count from last session
|
self.lastNotesWC = 0 # The note files word count from last session
|
||||||
@@ -612,6 +614,10 @@ class NWProject():
|
|||||||
self.lastEdited = checkString(xItem.text, None, True)
|
self.lastEdited = checkString(xItem.text, None, True)
|
||||||
elif xItem.tag == "lastViewed":
|
elif xItem.tag == "lastViewed":
|
||||||
self.lastViewed = checkString(xItem.text, None, True)
|
self.lastViewed = checkString(xItem.text, None, True)
|
||||||
|
elif xItem.tag == "lastNovel":
|
||||||
|
self.lastNovel = checkString(xItem.text, None, True)
|
||||||
|
elif xItem.tag == "lastOutline":
|
||||||
|
self.lastOutline = checkString(xItem.text, None, True)
|
||||||
elif xItem.tag == "lastWordCount":
|
elif xItem.tag == "lastWordCount":
|
||||||
self.lastWCount = checkInt(xItem.text, 0, False)
|
self.lastWCount = checkInt(xItem.text, 0, False)
|
||||||
elif xItem.tag == "novelWordCount":
|
elif xItem.tag == "novelWordCount":
|
||||||
@@ -732,6 +738,8 @@ class NWProject():
|
|||||||
self._packProjectValue(xSettings, "autoOutline", self.autoOutline)
|
self._packProjectValue(xSettings, "autoOutline", self.autoOutline)
|
||||||
self._packProjectValue(xSettings, "lastEdited", self.lastEdited)
|
self._packProjectValue(xSettings, "lastEdited", self.lastEdited)
|
||||||
self._packProjectValue(xSettings, "lastViewed", self.lastViewed)
|
self._packProjectValue(xSettings, "lastViewed", self.lastViewed)
|
||||||
|
self._packProjectValue(xSettings, "lastNovel", self.lastNovel)
|
||||||
|
self._packProjectValue(xSettings, "lastOutline", self.lastOutline)
|
||||||
self._packProjectValue(xSettings, "lastWordCount", self.currWCount)
|
self._packProjectValue(xSettings, "lastWordCount", self.currWCount)
|
||||||
self._packProjectValue(xSettings, "novelWordCount", self.currNovelWC)
|
self._packProjectValue(xSettings, "novelWordCount", self.currNovelWC)
|
||||||
self._packProjectValue(xSettings, "notesWordCount", self.currNotesWC)
|
self._packProjectValue(xSettings, "notesWordCount", self.currNotesWC)
|
||||||
@@ -1123,6 +1131,14 @@ class NWProject():
|
|||||||
self.setProjectChanged(True)
|
self.setProjectChanged(True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def setLastNovelViewed(self, tHandle):
|
||||||
|
"""Set last viewed novel root in the novel tree.
|
||||||
|
"""
|
||||||
|
if self.lastNovel != tHandle:
|
||||||
|
self.lastNovel = tHandle
|
||||||
|
self.setProjectChanged(True)
|
||||||
|
return True
|
||||||
|
|
||||||
def setStatusColours(self, newCols, delCols):
|
def setStatusColours(self, newCols, delCols):
|
||||||
"""Update the list of novel file status flags.
|
"""Update the list of novel file status flags.
|
||||||
"""
|
"""
|
||||||
|
|||||||
+174
-50
@@ -27,25 +27,34 @@ import logging
|
|||||||
import novelwriter
|
import novelwriter
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QSize
|
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
|
||||||
|
from PyQt5.QtGui import QPalette
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAbstractItemView, QFrame, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
|
||||||
|
QMenu, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
||||||
QWidget
|
QWidget
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from novelwriter.enum import nwDocMode, nwItemClass
|
||||||
from novelwriter.common import checkInt
|
from novelwriter.common import checkInt
|
||||||
from novelwriter.constants import nwKeyWords
|
from novelwriter.constants import nwKeyWords, nwLabels
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class GuiNovelView(QWidget):
|
class GuiNovelView(QWidget):
|
||||||
|
|
||||||
|
# Signals for user interaction with the novel tree
|
||||||
|
selectedItemChanged = pyqtSignal(str)
|
||||||
|
openDocumentRequest = pyqtSignal(str, Enum, int, str)
|
||||||
|
|
||||||
def __init__(self, mainGui):
|
def __init__(self, mainGui):
|
||||||
QWidget.__init__(self, mainGui)
|
QWidget.__init__(self, mainGui)
|
||||||
|
|
||||||
self.mainGui = mainGui
|
self.mainGui = mainGui
|
||||||
|
self.theProject = mainGui.theProject
|
||||||
|
|
||||||
# Build GUI
|
# Build GUI
|
||||||
self.novelTree = GuiNovelTree(self)
|
self.novelTree = GuiNovelTree(self)
|
||||||
@@ -60,6 +69,11 @@ class GuiNovelView(QWidget):
|
|||||||
|
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
|
|
||||||
|
# Connect Signals
|
||||||
|
self.novelBar.rootFolderSelectionChanged.connect(
|
||||||
|
lambda tHandle: self.novelTree.refreshTree(rootHandle=tHandle, overRide=True)
|
||||||
|
)
|
||||||
|
|
||||||
# Function Mappings
|
# Function Mappings
|
||||||
self.refreshTree = self.novelTree.refreshTree
|
self.refreshTree = self.novelTree.refreshTree
|
||||||
self.updateWordCounts = self.novelTree.updateWordCounts
|
self.updateWordCounts = self.novelTree.updateWordCounts
|
||||||
@@ -79,6 +93,21 @@ class GuiNovelView(QWidget):
|
|||||||
self.novelTree.clearTree()
|
self.novelTree.clearTree()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def openProjectTasks(self):
|
||||||
|
"""Run tasks related to opening a project.
|
||||||
|
"""
|
||||||
|
lastNovel = self.theProject.lastNovel
|
||||||
|
if lastNovel is None:
|
||||||
|
lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||||
|
|
||||||
|
logger.debug("Setting novel tree to root item '%s'", lastNovel)
|
||||||
|
|
||||||
|
self.clearProject()
|
||||||
|
self.novelBar.rebuildNovelRootMenu(selHandle=lastNovel)
|
||||||
|
self.novelTree.refreshTree(rootHandle=lastNovel, overRide=True)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
def setFocus(self):
|
def setFocus(self):
|
||||||
"""Forward the set focus call to the tree widget.
|
"""Forward the set focus call to the tree widget.
|
||||||
"""
|
"""
|
||||||
@@ -90,16 +119,114 @@ class GuiNovelView(QWidget):
|
|||||||
"""
|
"""
|
||||||
return self.novelTree.hasFocus()
|
return self.novelTree.hasFocus()
|
||||||
|
|
||||||
|
##
|
||||||
|
# Public Slots
|
||||||
|
##
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def updateRootItem(self, tHandle):
|
||||||
|
"""Should be called whenever a root folders changes.
|
||||||
|
"""
|
||||||
|
self.novelBar.rebuildNovelRootMenu()
|
||||||
|
return
|
||||||
|
|
||||||
# END Class GuiNovelView
|
# END Class GuiNovelView
|
||||||
|
|
||||||
|
|
||||||
class GuiNovelToolBar(QWidget):
|
class GuiNovelToolBar(QWidget):
|
||||||
|
|
||||||
|
rootFolderSelectionChanged = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, novelView):
|
def __init__(self, novelView):
|
||||||
QTreeWidget.__init__(self, novelView)
|
QTreeWidget.__init__(self, novelView)
|
||||||
|
|
||||||
self.mainConf = novelwriter.CONFIG
|
logger.debug("Initialising GuiNovelToolBar ...")
|
||||||
self.novelView = novelView
|
|
||||||
|
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(4)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Novel Root Menu
|
||||||
|
self.mRoot = QMenu()
|
||||||
|
|
||||||
|
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.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.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 rebuildNovelRootMenu(self, selHandle=None):
|
||||||
|
"""Build the novel root menu.
|
||||||
|
"""
|
||||||
|
self.mRoot.clear()
|
||||||
|
|
||||||
|
agRoot = QActionGroup(self.mRoot)
|
||||||
|
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.rootFolderSelectionChanged.emit(tHandle)
|
||||||
|
)
|
||||||
|
agRoot.addAction(aRoot)
|
||||||
|
|
||||||
|
if n == 0:
|
||||||
|
aRoot.setChecked(True)
|
||||||
|
if selHandle == tHandle:
|
||||||
|
aRoot.setChecked(True)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -128,41 +255,32 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
self._lastBuild = 0
|
self._lastBuild = 0
|
||||||
|
|
||||||
# Build GUI
|
# Build GUI
|
||||||
|
# =========
|
||||||
|
|
||||||
iPx = self.mainTheme.baseIconSize
|
iPx = self.mainTheme.baseIconSize
|
||||||
self.setFrameStyle(QFrame.NoFrame)
|
cMg = self.mainConf.pxInt(6)
|
||||||
|
|
||||||
self.setIconSize(QSize(iPx, iPx))
|
self.setIconSize(QSize(iPx, iPx))
|
||||||
|
self.setFrameStyle(QFrame.NoFrame)
|
||||||
|
self.setHeaderHidden(True)
|
||||||
self.setIndentation(iPx)
|
self.setIndentation(iPx)
|
||||||
self.setColumnCount(3)
|
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.setSelectionBehavior(QAbstractItemView.SelectRows)
|
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||||
self.setExpandsOnDoubleClick(False)
|
self.setExpandsOnDoubleClick(False)
|
||||||
self.setDragEnabled(False)
|
self.setDragEnabled(False)
|
||||||
|
|
||||||
treeHeadItem = self.headerItem()
|
# Lock the column sizes
|
||||||
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"))
|
|
||||||
|
|
||||||
treeHeader = self.header()
|
treeHeader = self.header()
|
||||||
treeHeader.setStretchLastSection(True)
|
treeHeader.setStretchLastSection(False)
|
||||||
treeHeader.setMinimumSectionSize(iPx + 6)
|
treeHeader.setMinimumSectionSize(iPx + cMg)
|
||||||
|
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
|
||||||
|
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
|
||||||
|
treeHeader.setSectionResizeMode(self.C_POV, QHeaderView.ResizeToContents)
|
||||||
|
|
||||||
# Get user's column width preferences for NAME and COUNT
|
# Connect signals
|
||||||
treeColWidth = self.mainConf.getNovelColWidths()
|
self.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||||
if len(treeColWidth) <= 3:
|
self.itemSelectionChanged.connect(self._treeSelectionChange)
|
||||||
for colN, colW in enumerate(treeColWidth):
|
|
||||||
self.setColumnWidth(colN, colW)
|
|
||||||
|
|
||||||
# The last column should just auto-scale
|
|
||||||
self.resizeColumnToContents(self.C_POV)
|
|
||||||
|
|
||||||
# Set custom settings
|
# Set custom settings
|
||||||
self.initSettings()
|
self.initSettings()
|
||||||
@@ -199,12 +317,15 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
self._lastBuild = 0
|
self._lastBuild = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
def refreshTree(self, overRide=False):
|
def refreshTree(self, rootHandle=None, overRide=False):
|
||||||
"""Called whenever the Novel tab is activated.
|
"""Called whenever the Novel tab is activated.
|
||||||
"""
|
"""
|
||||||
logger.verbose("Requesting refresh of the novel tree")
|
logger.verbose("Requesting refresh of the novel tree")
|
||||||
|
if rootHandle is None:
|
||||||
|
rootHandle = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||||
|
|
||||||
treeChanged = self.mainGui.projView.changedSince(self._lastBuild)
|
treeChanged = self.mainGui.projView.changedSince(self._lastBuild)
|
||||||
indexChanged = self.theProject.index.indexChangedSince(self._lastBuild)
|
indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild)
|
||||||
if not (treeChanged or indexChanged or overRide):
|
if not (treeChanged or indexChanged or overRide):
|
||||||
logger.verbose("No changes have been made to the novel index")
|
logger.verbose("No changes have been made to the novel index")
|
||||||
return
|
return
|
||||||
@@ -214,7 +335,8 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
if selItem:
|
if selItem:
|
||||||
titleKey = selItem[0].data(self.C_TITLE, Qt.UserRole)[2]
|
titleKey = selItem[0].data(self.C_TITLE, Qt.UserRole)[2]
|
||||||
|
|
||||||
self._populateTree()
|
self._populateTree(rootHandle)
|
||||||
|
self.theProject.setLastNovelViewed(rootHandle)
|
||||||
|
|
||||||
if titleKey is not None and titleKey in self._treeMap:
|
if titleKey is not None and titleKey in self._treeMap:
|
||||||
self._treeMap[titleKey].setSelected(True)
|
self._treeMap[titleKey].setSelected(True)
|
||||||
@@ -268,39 +390,39 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
if tHandle is None:
|
if tHandle is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.mainGui.viewDocument(tHandle)
|
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Slots
|
# Private Slots
|
||||||
##
|
##
|
||||||
|
|
||||||
def _treeDoubleClick(self, tItem, tCol):
|
@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-
|
"""Extract the handle and line number of the title double-
|
||||||
clicked, and send it to the main gui class for opening in the
|
clicked, and send it to the main gui class for opening in the
|
||||||
document editor.
|
document editor.
|
||||||
"""
|
"""
|
||||||
tHandle, tLine = self.getSelectedHandle()
|
tHandle, tLine = self.getSelectedHandle()
|
||||||
self.mainGui.openDocument(tHandle, tLine=tLine-1, doScroll=True)
|
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, tLine, "")
|
||||||
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.mainGui.itemDetails.updateViewBox(tHandle)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
def _populateTree(self):
|
def _populateTree(self, rootHandle):
|
||||||
"""Build the tree based on the project index.
|
"""Build the tree based on the project index.
|
||||||
"""
|
"""
|
||||||
self.clearTree()
|
self.clearTree()
|
||||||
@@ -309,7 +431,9 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
currChapter = None
|
currChapter = None
|
||||||
currScene = None
|
currScene = None
|
||||||
|
|
||||||
for tKey, tHandle, sTitle, novIdx in self.theProject.index.novelStructure(skipExcl=True):
|
logger.verbose("Building novel tree for root item '%s'", rootHandle)
|
||||||
|
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
||||||
|
for tKey, tHandle, sTitle, novIdx in novStruct:
|
||||||
|
|
||||||
tItem = self._createTreeItem(tHandle, sTitle, tKey, novIdx)
|
tItem = self._createTreeItem(tHandle, sTitle, tKey, novIdx)
|
||||||
self._treeMap[tKey] = tItem
|
self._treeMap[tKey] = tItem
|
||||||
|
|||||||
+13
-13
@@ -61,7 +61,7 @@ class GuiProjectView(QWidget):
|
|||||||
|
|
||||||
# Signals for user interaction with the project tree
|
# Signals for user interaction with the project tree
|
||||||
selectedItemChanged = pyqtSignal(str)
|
selectedItemChanged = pyqtSignal(str)
|
||||||
openDocumentRequest = pyqtSignal(str, Enum)
|
openDocumentRequest = pyqtSignal(str, Enum, int, str)
|
||||||
|
|
||||||
def __init__(self, mainGui):
|
def __init__(self, mainGui):
|
||||||
QWidget.__init__(self, mainGui)
|
QWidget.__init__(self, mainGui)
|
||||||
@@ -192,10 +192,10 @@ class GuiProjectToolBar(QWidget):
|
|||||||
"QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
|
"QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
|
||||||
).format(mPx, fadeCol.red(), fadeCol.green(), fadeCol.blue())
|
).format(mPx, fadeCol.red(), fadeCol.green(), fadeCol.blue())
|
||||||
|
|
||||||
# Tree Label
|
# Widget Label
|
||||||
self.projLabel = QLabel("<b>%s</b>" % self.tr("Project Content"))
|
self.viewLabel = QLabel("<b>%s</b>" % self.tr("Project Content"))
|
||||||
self.projLabel.setContentsMargins(0, 0, 0, 0)
|
self.viewLabel.setContentsMargins(0, 0, 0, 0)
|
||||||
self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
|
||||||
# Move Buttons
|
# Move Buttons
|
||||||
self.tbMoveU = QToolButton(self)
|
self.tbMoveU = QToolButton(self)
|
||||||
@@ -285,7 +285,7 @@ class GuiProjectToolBar(QWidget):
|
|||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
self.outerBox = QHBoxLayout()
|
self.outerBox = QHBoxLayout()
|
||||||
self.outerBox.addWidget(self.projLabel)
|
self.outerBox.addWidget(self.viewLabel)
|
||||||
self.outerBox.addWidget(self.tbMoveU)
|
self.outerBox.addWidget(self.tbMoveU)
|
||||||
self.outerBox.addWidget(self.tbMoveD)
|
self.outerBox.addWidget(self.tbMoveD)
|
||||||
self.outerBox.addWidget(self.tbAdd)
|
self.outerBox.addWidget(self.tbAdd)
|
||||||
@@ -337,9 +337,8 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
self._lastMove = {}
|
self._lastMove = {}
|
||||||
self._timeChanged = 0
|
self._timeChanged = 0
|
||||||
|
|
||||||
##
|
# Build GUI
|
||||||
# Build GUI
|
# =========
|
||||||
##
|
|
||||||
|
|
||||||
# Context Menu
|
# Context Menu
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
@@ -348,6 +347,7 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
# Tree Settings
|
# Tree Settings
|
||||||
iPx = self.mainTheme.baseIconSize
|
iPx = self.mainTheme.baseIconSize
|
||||||
cMg = self.mainConf.pxInt(6)
|
cMg = self.mainConf.pxInt(6)
|
||||||
|
|
||||||
self.setIconSize(QSize(iPx, iPx))
|
self.setIconSize(QSize(iPx, iPx))
|
||||||
self.setFrameStyle(QFrame.NoFrame)
|
self.setFrameStyle(QFrame.NoFrame)
|
||||||
self.setExpandsOnDoubleClick(False)
|
self.setExpandsOnDoubleClick(False)
|
||||||
@@ -972,7 +972,7 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if tItem.itemType == nwItemType.FILE:
|
if tItem.itemType == nwItemType.FILE:
|
||||||
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
|
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "")
|
||||||
else:
|
else:
|
||||||
trItem = self._getTreeItem(tHandle)
|
trItem = self._getTreeItem(tHandle)
|
||||||
if trItem is not None:
|
if trItem is not None:
|
||||||
@@ -1016,11 +1016,11 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
if isFile:
|
if isFile:
|
||||||
ctxMenu.addAction(
|
ctxMenu.addAction(
|
||||||
self.tr("Open Document"),
|
self.tr("Open Document"),
|
||||||
lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
|
lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "")
|
||||||
)
|
)
|
||||||
ctxMenu.addAction(
|
ctxMenu.addAction(
|
||||||
self.tr("View Document"),
|
self.tr("View Document"),
|
||||||
lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
|
lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
|
||||||
)
|
)
|
||||||
ctxMenu.addSeparator()
|
ctxMenu.addSeparator()
|
||||||
|
|
||||||
@@ -1112,7 +1112,7 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if tItem.itemType == nwItemType.FILE:
|
if tItem.itemType == nwItemType.FILE:
|
||||||
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
|
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
+12
-6
@@ -205,6 +205,10 @@ class GuiMain(QMainWindow):
|
|||||||
self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
|
self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
|
||||||
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
|
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
|
||||||
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
|
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
|
||||||
|
self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
|
||||||
|
|
||||||
|
self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
||||||
|
self.novelView.openDocumentRequest.connect(self._openDocument)
|
||||||
|
|
||||||
self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
|
self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
|
||||||
self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus)
|
self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus)
|
||||||
@@ -362,6 +366,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.saveProject()
|
self.saveProject()
|
||||||
self.docEditor.setDictionaries()
|
self.docEditor.setDictionaries()
|
||||||
self.outlineView.updateRootItem(None)
|
self.outlineView.updateRootItem(None)
|
||||||
|
self.novelView.openProjectTasks()
|
||||||
self.rebuildIndex(beQuiet=True)
|
self.rebuildIndex(beQuiet=True)
|
||||||
self.statusBar.setRefTime(self.theProject.projOpened)
|
self.statusBar.setRefTime(self.theProject.projOpened)
|
||||||
self.statusBar.setProjectStatus(nwState.GOOD)
|
self.statusBar.setProjectStatus(nwState.GOOD)
|
||||||
@@ -509,6 +514,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.docEditor.toggleSpellCheck(self.theProject.spellCheck)
|
self.docEditor.toggleSpellCheck(self.theProject.spellCheck)
|
||||||
self.statusBar.setRefTime(self.theProject.projOpened)
|
self.statusBar.setRefTime(self.theProject.projOpened)
|
||||||
self.outlineView.updateRootItem(None)
|
self.outlineView.updateRootItem(None)
|
||||||
|
self.novelView.openProjectTasks()
|
||||||
self._updateStatusWordCount()
|
self._updateStatusWordCount()
|
||||||
|
|
||||||
# Restore previously open documents, if any
|
# Restore previously open documents, if any
|
||||||
@@ -825,7 +831,7 @@ class GuiMain(QMainWindow):
|
|||||||
"""Rebuild the project tree.
|
"""Rebuild the project tree.
|
||||||
"""
|
"""
|
||||||
self.projView.populateTree()
|
self.projView.populateTree()
|
||||||
self.novelView.refreshTree()
|
# self.novelView.refreshTree()
|
||||||
return
|
return
|
||||||
|
|
||||||
def requestNovelTreeRefresh(self):
|
def requestNovelTreeRefresh(self):
|
||||||
@@ -1468,15 +1474,15 @@ class GuiMain(QMainWindow):
|
|||||||
self.viewDocument(tHandle=tHandle, tAnchor=f"#{sTitle}")
|
self.viewDocument(tHandle=tHandle, tAnchor=f"#{sTitle}")
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot(str, Enum)
|
@pyqtSlot(str, Enum, int, str)
|
||||||
def _openDocument(self, tHandle, tMode):
|
def _openDocument(self, tHandle, tMode, tLine, tAnchor):
|
||||||
"""Handle an open document request.
|
"""Handle an open document request from one of the tree views.
|
||||||
"""
|
"""
|
||||||
if tHandle is not None:
|
if tHandle is not None:
|
||||||
if tMode == nwDocMode.EDIT:
|
if tMode == nwDocMode.EDIT:
|
||||||
self.openDocument(tHandle, changeFocus=False)
|
self.openDocument(tHandle, tLine=tLine, changeFocus=False)
|
||||||
elif tMode == nwDocMode.VIEW:
|
elif tMode == nwDocMode.VIEW:
|
||||||
self.viewDocument(tHandle=tHandle)
|
self.viewDocument(tHandle=tHandle, tAnchor=(tAnchor or None))
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot(nwView)
|
@pyqtSlot(nwView)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="1.7-beta1" hexVersion="0x010700b1" fileVersion="1.4" timeStamp="2022-06-11 13:36:01">
|
<novelWriterXML appVersion="1.7-beta1" hexVersion="0x010700b1" fileVersion="1.4" timeStamp="2022-06-12 17:37:35">
|
||||||
<project>
|
<project>
|
||||||
<name>Sample Project</name>
|
<name>Sample Project</name>
|
||||||
<title>Sample Project</title>
|
<title>Sample Project</title>
|
||||||
<author>Jane Smith</author>
|
<author>Jane Smith</author>
|
||||||
<author>Jay Doh</author>
|
<author>Jay Doh</author>
|
||||||
<saveCount>1345</saveCount>
|
<saveCount>1367</saveCount>
|
||||||
<autoCount>229</autoCount>
|
<autoCount>231</autoCount>
|
||||||
<editTime>68286</editTime>
|
<editTime>68784</editTime>
|
||||||
</project>
|
</project>
|
||||||
<settings>
|
<settings>
|
||||||
<doBackup>False</doBackup>
|
<doBackup>False</doBackup>
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
<autoOutline>True</autoOutline>
|
<autoOutline>True</autoOutline>
|
||||||
<lastEdited>636b6aa9b697b</lastEdited>
|
<lastEdited>636b6aa9b697b</lastEdited>
|
||||||
<lastViewed>636b6aa9b697b</lastViewed>
|
<lastViewed>636b6aa9b697b</lastViewed>
|
||||||
|
<lastNovel>7031beac91f75</lastNovel>
|
||||||
|
<lastOutline>None</lastOutline>
|
||||||
<lastWordCount>1363</lastWordCount>
|
<lastWordCount>1363</lastWordCount>
|
||||||
<novelWordCount>954</novelWordCount>
|
<novelWordCount>954</novelWordCount>
|
||||||
<notesWordCount>409</notesWordCount>
|
<notesWordCount>409</notesWordCount>
|
||||||
@@ -70,11 +72,11 @@
|
|||||||
<name status="sf24ce6" import="ia857f0" exported="True">Chapter One</name>
|
<name status="sf24ce6" import="ia857f0" exported="True">Chapter One</name>
|
||||||
</item>
|
</item>
|
||||||
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||||
<meta expanded="False" charCount="2687" wordCount="479" paraCount="14" cursorPos="61"/>
|
<meta expanded="False" charCount="2687" wordCount="479" paraCount="14" cursorPos="2183"/>
|
||||||
<name status="s90e6c9" import="ia857f0" exported="True">Making a Scene</name>
|
<name status="s90e6c9" import="ia857f0" exported="True">Making a Scene</name>
|
||||||
</item>
|
</item>
|
||||||
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
|
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||||
<meta expanded="False" charCount="548" wordCount="108" paraCount="3" cursorPos="649"/>
|
<meta expanded="False" charCount="548" wordCount="108" paraCount="3" cursorPos="465"/>
|
||||||
<name status="s90e6c9" import="ia857f0" exported="True">Another Scene</name>
|
<name status="s90e6c9" import="ia857f0" exported="True">Another Scene</name>
|
||||||
</item>
|
</item>
|
||||||
<item handle="ba8a28a246524" parent="7031beac91f75" root="7031beac91f75" order="4" type="FILE" class="NOVEL" layout="DOCUMENT">
|
<item handle="ba8a28a246524" parent="7031beac91f75" root="7031beac91f75" order="4" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||||
@@ -86,7 +88,7 @@
|
|||||||
<name status="sf24ce6" import="ia857f0" exported="False">A Note on Structure</name>
|
<name status="sf24ce6" import="ia857f0" exported="False">A Note on Structure</name>
|
||||||
</item>
|
</item>
|
||||||
<item handle="88706ddc78b1b" parent="7031beac91f75" root="7031beac91f75" order="6" type="FILE" class="NOVEL" layout="DOCUMENT">
|
<item handle="88706ddc78b1b" parent="7031beac91f75" root="7031beac91f75" order="6" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||||
<meta expanded="True" charCount="139" wordCount="28" paraCount="1" cursorPos="343"/>
|
<meta expanded="True" charCount="139" wordCount="28" paraCount="1" cursorPos="188"/>
|
||||||
<name status="s90e6c9" import="ia857f0" exported="True">Chapter Two</name>
|
<name status="s90e6c9" import="ia857f0" exported="True">Chapter Two</name>
|
||||||
</item>
|
</item>
|
||||||
<item handle="ae7339df26ded" parent="88706ddc78b1b" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
<item handle="ae7339df26ded" parent="88706ddc78b1b" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||||
|
|||||||
Reference in New Issue
Block a user