Add the basic structure for a novel tree

This commit is contained in:
Veronica K. B. Olsen
2020-12-20 15:50:01 +01:00
parent 597f177d5b
commit d4b26025ed
11 changed files with 206 additions and 42 deletions
+21 -8
View File
@@ -95,14 +95,15 @@ class Config:
self.lastNotes = "" # The latest release notes that have been shown self.lastNotes = "" # The latest release notes that have been shown
## Sizes ## Sizes
self.winGeometry = [1200, 650] self.winGeometry = [1200, 650]
self.treeColWidth = [200, 50, 30] self.treeColWidth = [200, 50, 30]
self.projColWidth = [200, 60, 140] self.novelColWidth = [200, 50]
self.mainPanePos = [300, 800] self.projColWidth = [200, 60, 140]
self.docPanePos = [400, 400] self.mainPanePos = [300, 800]
self.viewPanePos = [500, 150] self.docPanePos = [400, 400]
self.outlnPanePos = [500, 150] self.viewPanePos = [500, 150]
self.isFullScreen = False self.outlnPanePos = [500, 150]
self.isFullScreen = False
## Features ## Features
self.hideVScroll = False # Hide vertical scroll bars on main widgets self.hideVScroll = False # Hide vertical scroll bars on main widgets
@@ -395,6 +396,9 @@ class Config:
self.treeColWidth = self._parseLine( self.treeColWidth = self._parseLine(
cnfParse, cnfSec, "treecols", self.CNF_I_LST, self.treeColWidth cnfParse, cnfSec, "treecols", self.CNF_I_LST, self.treeColWidth
) )
self.novelColWidth = self._parseLine(
cnfParse, cnfSec, "novelcols", self.CNF_I_LST, self.novelColWidth
)
self.projColWidth = self._parseLine( self.projColWidth = self._parseLine(
cnfParse, cnfSec, "projcols", self.CNF_I_LST, self.projColWidth cnfParse, cnfSec, "projcols", self.CNF_I_LST, self.projColWidth
) )
@@ -597,6 +601,7 @@ class Config:
cnfParse.add_section(cnfSec) cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "geometry", self._packList(self.winGeometry)) cnfParse.set(cnfSec, "geometry", self._packList(self.winGeometry))
cnfParse.set(cnfSec, "treecols", self._packList(self.treeColWidth)) cnfParse.set(cnfSec, "treecols", self._packList(self.treeColWidth))
cnfParse.set(cnfSec, "novelcols", self._packList(self.novelColWidth))
cnfParse.set(cnfSec, "projcols", self._packList(self.projColWidth)) cnfParse.set(cnfSec, "projcols", self._packList(self.projColWidth))
cnfParse.set(cnfSec, "mainpane", self._packList(self.mainPanePos)) cnfParse.set(cnfSec, "mainpane", self._packList(self.mainPanePos))
cnfParse.set(cnfSec, "docpane", self._packList(self.docPanePos)) cnfParse.set(cnfSec, "docpane", self._packList(self.docPanePos))
@@ -816,6 +821,11 @@ class Config:
self.confChanged = True self.confChanged = True
return True return True
def setNovelColWidths(self, colWidths):
self.novelColWidth = [int(x/self.guiScale) for x in colWidths]
self.confChanged = True
return True
def setProjColWidths(self, colWidths): def setProjColWidths(self, colWidths):
self.projColWidth = [int(x/self.guiScale) for x in colWidths] self.projColWidth = [int(x/self.guiScale) for x in colWidths]
self.confChanged = True self.confChanged = True
@@ -872,6 +882,9 @@ class Config:
def getTreeColWidths(self): def getTreeColWidths(self):
return [int(x*self.guiScale) for x in self.treeColWidth] return [int(x*self.guiScale) for x in self.treeColWidth]
def getNovelColWidths(self):
return [int(x*self.guiScale) for x in self.novelColWidth]
def getProjColWidths(self): def getProjColWidths(self):
return [int(x*self.guiScale) for x in self.projColWidth] return [int(x*self.guiScale) for x in self.projColWidth]
+2
View File
@@ -9,6 +9,7 @@ from nw.gui.docviewer import GuiDocViewer, GuiDocViewDetails
from nw.gui.itemdetails import GuiItemDetails from nw.gui.itemdetails import GuiItemDetails
from nw.gui.itemeditor import GuiItemEditor from nw.gui.itemeditor import GuiItemEditor
from nw.gui.mainmenu import GuiMainMenu from nw.gui.mainmenu import GuiMainMenu
from nw.gui.noveltree import GuiNovelTree
from nw.gui.outline import GuiOutline from nw.gui.outline import GuiOutline
from nw.gui.outlinedetails import GuiOutlineDetails from nw.gui.outlinedetails import GuiOutlineDetails
from nw.gui.preferences import GuiPreferences from nw.gui.preferences import GuiPreferences
@@ -31,6 +32,7 @@ __all__ = [
"GuiItemDetails", "GuiItemDetails",
"GuiItemEditor", "GuiItemEditor",
"GuiMainMenu", "GuiMainMenu",
"GuiNovelTree",
"GuiMainStatus", "GuiMainStatus",
"GuiOutline", "GuiOutline",
"GuiOutlineDetails", "GuiOutlineDetails",
+119
View File
@@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
"""novelWriter GUI Novel Tree
novelWriter GUI Novel Tree
==============================
Class holding the project's novel files tree view
File History:
Created: 2020-12-20 [1.1a0]
This file is a part of novelWriter
Copyright 20182020, 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 nw
import logging
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QTreeWidget
logger = logging.getLogger(__name__)
class GuiNovelTree(QTreeWidget):
C_TITLE = 0
C_WORDS = 1
C_PAGES = 2
def __init__(self, theParent):
QTreeWidget.__init__(self, theParent)
logger.debug("Initialising GuiNovelTree ...")
self.mainConf = nw.CONFIG
self.theParent = theParent
self.theTheme = theParent.theTheme
self.theProject = theParent.theProject
self.theIndex = theParent.theIndex
# Build GUI
iPx = self.theTheme.baseIconSize
self.setIconSize(QSize(iPx, iPx))
self.setExpandsOnDoubleClick(True)
self.setIndentation(iPx)
self.setColumnCount(3)
self.setHeaderLabels(["Title", "Words", "Pages"])
# 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)
# The last column should just auto-scale
self.resizeColumnToContents(self.C_PAGES)
# Set custom settings
self.initTree()
logger.debug("GuiNovelTree initialisation complete")
# Internal Mapping
self.makeAlert = self.theParent.makeAlert
return
def initTree(self):
"""Set or update tree widget 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
##
# Class Methods
##
def clearTree(self):
"""Clear the GUI content and the related maps.
"""
self.clear()
return
def getColumnSizes(self):
"""Return the column widths for the tree columns.
"""
retVals = [
self.columnWidth(self.C_TITLE),
self.columnWidth(self.C_WORDS),
]
return retVals
##
# Slots
##
# END Class GuiNovelTree
+3 -3
View File
@@ -357,9 +357,9 @@ class GuiProjectTree(QTreeWidget):
"""Return the column widths for the tree columns. """Return the column widths for the tree columns.
""" """
retVals = [ retVals = [
self.columnWidth(0), self.columnWidth(self.C_NAME),
self.columnWidth(1), self.columnWidth(self.C_COUNT),
self.columnWidth(2), self.columnWidth(self.C_EXPORT),
] ]
return retVals return retVals
+36 -22
View File
@@ -42,9 +42,9 @@ from PyQt5.QtWidgets import (
from nw.gui import ( from nw.gui import (
GuiAbout, GuiBuildNovel, GuiDocEditor, GuiDocMerge, GuiDocSplit, GuiAbout, GuiBuildNovel, GuiDocEditor, GuiDocMerge, GuiDocSplit,
GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiItemEditor, GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiItemEditor,
GuiMainMenu, GuiMainStatus, GuiOutline, GuiOutlineDetails, GuiPreferences, GuiMainMenu, GuiMainStatus, GuiNovelTree, GuiOutline, GuiOutlineDetails,
GuiProjectLoad, GuiProjectSettings, GuiProjectTree, GuiProjectWizard, GuiPreferences, GuiProjectLoad, GuiProjectSettings, GuiProjectTree,
GuiTheme, GuiWritingStats GuiProjectWizard, GuiTheme, GuiWritingStats
) )
from nw.core import NWProject, NWDoc, NWIndex from nw.core import NWProject, NWDoc, NWIndex
from nw.constants import nwItemType, nwItemClass, nwAlert from nw.constants import nwItemType, nwItemClass, nwAlert
@@ -99,6 +99,7 @@ class GuiMain(QMainWindow):
# Main GUI Elements # Main GUI Elements
self.statusBar = GuiMainStatus(self) self.statusBar = GuiMainStatus(self)
self.treeView = GuiProjectTree(self) self.treeView = GuiProjectTree(self)
self.novelView = GuiNovelTree(self)
self.docEditor = GuiDocEditor(self) self.docEditor = GuiDocEditor(self)
self.viewMeta = GuiDocViewDetails(self) self.viewMeta = GuiDocViewDetails(self)
self.docViewer = GuiDocViewer(self) self.docViewer = GuiDocViewer(self)
@@ -111,11 +112,23 @@ class GuiMain(QMainWindow):
self.statusIcons = [] self.statusIcons = []
self.importIcons = [] self.importIcons = []
# Project Tabs : Project / Novel
self.projTabs = QTabWidget()
self.projTabs.setTabPosition(QTabWidget.South)
self.projTabs.setStyleSheet("QTabWidget::pane {border: 0;};")
self.projTabs.addTab(self.treeView, "Project")
self.projTabs.addTab(self.novelView, "Novel")
tabFont = self.projTabs.tabBar().font()
tabFont.setPointSize(round(0.9*self.theTheme.fontPointSize))
self.projTabs.tabBar().setFont(tabFont)
# Project Tree View # Project Tree View
self.treePane = QWidget() self.treePane = QWidget()
self.treeBox = QVBoxLayout() self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0, 0, 0, 0) self.treeBox.setContentsMargins(0, 0, 0, 0)
self.treeBox.addWidget(self.treeView) self.treeBox.setSpacing(0)
self.treeBox.addWidget(self.projTabs)
self.treeBox.addWidget(self.treeMeta) self.treeBox.addWidget(self.treeMeta)
self.treePane.setLayout(self.treeBox) self.treePane.setLayout(self.treeBox)
@@ -136,31 +149,31 @@ class GuiMain(QMainWindow):
self.splitOutline.addWidget(self.projMeta) self.splitOutline.addWidget(self.projMeta)
self.splitOutline.setSizes(self.mainConf.getOutlinePanePos()) self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())
# Main Tabs : Edirot / Outline # Main Tabs : Editor / Outline
self.tabWidget = QTabWidget() self.mainTabs = QTabWidget()
self.tabWidget.setTabPosition(QTabWidget.East) self.mainTabs.setTabPosition(QTabWidget.East)
self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;}") self.mainTabs.setStyleSheet("QTabWidget::pane {border: 0;}")
self.tabWidget.addTab(self.splitDocs, "Editor") self.mainTabs.addTab(self.splitDocs, "Editor")
self.tabWidget.addTab(self.splitOutline, "Outline") self.mainTabs.addTab(self.splitOutline, "Outline")
self.tabWidget.currentChanged.connect(self._mainTabChanged) self.mainTabs.currentChanged.connect(self._mainTabChanged)
# Splitter : Project Tree / Main Tabs # Splitter : Project Tree / Main Tabs
xCM = self.mainConf.pxInt(4) xCM = self.mainConf.pxInt(4)
self.splitMain = QSplitter(Qt.Horizontal) self.splitMain = QSplitter(Qt.Horizontal)
self.splitMain.setContentsMargins(xCM, xCM, xCM, xCM) self.splitMain.setContentsMargins(xCM, xCM, xCM, xCM)
self.splitMain.addWidget(self.treePane) self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.tabWidget) self.splitMain.addWidget(self.mainTabs)
self.splitMain.setSizes(self.mainConf.getMainPanePos()) self.splitMain.setSizes(self.mainConf.getMainPanePos())
# Indices of All Splitter Widgets # Indices of All Splitter Widgets
self.idxTree = self.splitMain.indexOf(self.treePane) self.idxTree = self.splitMain.indexOf(self.treePane)
self.idxMain = self.splitMain.indexOf(self.tabWidget) self.idxMain = self.splitMain.indexOf(self.mainTabs)
self.idxEditor = self.splitDocs.indexOf(self.docEditor) self.idxEditor = self.splitDocs.indexOf(self.docEditor)
self.idxViewer = self.splitDocs.indexOf(self.splitView) self.idxViewer = self.splitDocs.indexOf(self.splitView)
self.idxViewDoc = self.splitView.indexOf(self.docViewer) self.idxViewDoc = self.splitView.indexOf(self.docViewer)
self.idxViewMeta = self.splitView.indexOf(self.viewMeta) self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
self.idxTabEdit = self.tabWidget.indexOf(self.splitDocs) self.idxTabEdit = self.mainTabs.indexOf(self.splitDocs)
self.idxTabProj = self.tabWidget.indexOf(self.splitOutline) self.idxTabProj = self.mainTabs.indexOf(self.splitOutline)
# Splitter Behaviour # Splitter Behaviour
self.splitMain.setCollapsible(self.idxTree, False) self.splitMain.setCollapsible(self.idxTree, False)
@@ -355,7 +368,7 @@ class GuiMain(QMainWindow):
self.theIndex.clearIndex() self.theIndex.clearIndex()
self.clearGUI() self.clearGUI()
self.hasProject = False self.hasProject = False
self.tabWidget.setCurrentWidget(self.splitDocs) self.mainTabs.setCurrentWidget(self.splitDocs)
return saveOK return saveOK
@@ -371,7 +384,7 @@ class GuiMain(QMainWindow):
return False return False
# Switch main tab to editor view # Switch main tab to editor view
self.tabWidget.setCurrentWidget(self.splitDocs) self.mainTabs.setCurrentWidget(self.splitDocs)
# Try to open the project # Try to open the project
if not self.theProject.openProject(projFile): if not self.theProject.openProject(projFile):
@@ -490,7 +503,7 @@ class GuiMain(QMainWindow):
return False return False
self.closeDocument() self.closeDocument()
self.tabWidget.setCurrentWidget(self.splitDocs) self.mainTabs.setCurrentWidget(self.splitDocs)
if self.docEditor.loadText(tHandle, tLine): if self.docEditor.loadText(tHandle, tLine):
if changeFocus: if changeFocus:
self.docEditor.setFocus() self.docEditor.setFocus()
@@ -575,7 +588,7 @@ class GuiMain(QMainWindow):
return False return False
# Make sure main tab is in Editor view # Make sure main tab is in Editor view
self.tabWidget.setCurrentWidget(self.splitDocs) self.mainTabs.setCurrentWidget(self.splitDocs)
logger.debug("Viewing document with handle %s" % tHandle) logger.debug("Viewing document with handle %s" % tHandle)
if self.docViewer.loadText(tHandle): if self.docViewer.loadText(tHandle):
@@ -797,7 +810,7 @@ class GuiMain(QMainWindow):
return False return False
logger.verbose("Forcing a rebuild of the Project Outline") logger.verbose("Forcing a rebuild of the Project Outline")
self.tabWidget.setCurrentWidget(self.splitOutline) self.mainTabs.setCurrentWidget(self.splitOutline)
self.projView.refreshTree(overRide=True) self.projView.refreshTree(overRide=True)
return True return True
@@ -1022,6 +1035,7 @@ class GuiMain(QMainWindow):
self.mainConf.setShowRefPanel(self.viewMeta.isVisible()) self.mainConf.setShowRefPanel(self.viewMeta.isVisible())
self.mainConf.setTreeColWidths(self.treeView.getColumnSizes()) self.mainConf.setTreeColWidths(self.treeView.getColumnSizes())
self.mainConf.setNovelColWidths(self.novelView.getColumnSizes())
if not self.mainConf.isFullScreen: if not self.mainConf.isFullScreen:
self.mainConf.setWinSize(self.width(), self.height()) self.mainConf.setWinSize(self.width(), self.height())
@@ -1078,7 +1092,7 @@ class GuiMain(QMainWindow):
self.mainMenu.aFocusMode.setChecked(self.isFocusMode) self.mainMenu.aFocusMode.setChecked(self.isFocusMode)
if self.isFocusMode: if self.isFocusMode:
logger.debug("Activating Focus Mode") logger.debug("Activating Focus Mode")
self.tabWidget.setCurrentWidget(self.splitDocs) self.mainTabs.setCurrentWidget(self.splitDocs)
else: else:
logger.debug("Deactivating Focus Mode") logger.debug("Deactivating Focus Mode")
@@ -1086,7 +1100,7 @@ class GuiMain(QMainWindow):
self.treePane.setVisible(isVisible) self.treePane.setVisible(isVisible)
self.statusBar.setVisible(isVisible) self.statusBar.setVisible(isVisible)
self.mainMenu.setVisible(isVisible) self.mainMenu.setVisible(isVisible)
self.tabWidget.tabBar().setVisible(isVisible) self.mainTabs.tabBar().setVisible(isVisible)
hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter
self.docEditor.docFooter.setVisible(not hideDocFooter) self.docEditor.docFooter.setVisible(not hideDocFooter)
+4 -4
View File
@@ -1,13 +1,13 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.0rc2" hexVersion="0x010000c2" fileVersion="1.2" timeStamp="2020-12-13 20:09:24"> <novelWriterXML appVersion="1.1a0" hexVersion="0x010100a0" fileVersion="1.2" timeStamp="2020-12-20 15:44:04">
<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>810</saveCount> <saveCount>836</saveCount>
<autoCount>153</autoCount> <autoCount>155</autoCount>
<editTime>39261</editTime> <editTime>39747</editTime>
</project> </project>
<settings> <settings>
<doBackup>False</doBackup> <doBackup>False</doBackup>
@@ -11,6 +11,7 @@ lastnotes = 1.0
[Sizes] [Sizes]
geometry = 1200, 650 geometry = 1200, 650
treecols = 200, 50, 30 treecols = 200, 50, 30
novelcols = 200, 50
projcols = 200, 60, 140 projcols = 200, 60, 140
mainpane = 300, 800 mainpane = 300, 800
docpane = 400, 400 docpane = 400, 400
@@ -11,6 +11,7 @@ lastnotes = 1.0
[Sizes] [Sizes]
geometry = 1100, 650 geometry = 1100, 650
treecols = 120, 30, 50 treecols = 120, 30, 50
novelcols = 200, 50
projcols = 140, 55, 140 projcols = 140, 55, 140
mainpane = 300, 800 mainpane = 300, 800
docpane = 400, 400 docpane = 400, 400
+13
View File
@@ -304,6 +304,19 @@ def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir):
assert tmpConf.setTreeColWidths([200, 50, 30]) assert tmpConf.setTreeColWidths([200, 50, 30])
# Novel Tree Columns
tmpConf.guiScale = 2.0
assert tmpConf.setNovelColWidths([10, 20])
assert tmpConf.getNovelColWidths() == [10, 20]
assert tmpConf.novelColWidth == [5, 10]
tmpConf.guiScale = 1.0
assert tmpConf.setNovelColWidths([10, 20])
assert tmpConf.getNovelColWidths() == [10, 20]
assert tmpConf.novelColWidth == [10, 20]
assert tmpConf.setNovelColWidths([200, 50])
# Project Settings Tree Columns # Project Settings Tree Columns
tmpConf.guiScale = 2.0 tmpConf.guiScale = 2.0
assert tmpConf.setProjColWidths([10, 20, 30]) assert tmpConf.setProjColWidths([10, 20, 30])
+1 -1
View File
@@ -24,7 +24,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.mainConf.lastPath = nwLipsum nwGUI.mainConf.lastPath = nwLipsum
nwGUI.rebuildIndex() nwGUI.rebuildIndex()
nwGUI.tabWidget.setCurrentIndex(nwGUI.idxTabProj) nwGUI.mainTabs.setCurrentIndex(nwGUI.idxTabProj)
assert nwGUI.projView.topLevelItemCount() > 0 assert nwGUI.projView.topLevelItemCount() > 0
+5 -4
View File
@@ -220,10 +220,11 @@ def testGuiPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir):
compFile = os.path.join(refDir, "guiPreferences_novelwriter.conf") compFile = os.path.join(refDir, "guiPreferences_novelwriter.conf")
copyfile(projFile, testFile) copyfile(projFile, testFile)
ignoreLines = [ ignoreLines = [
2, # Timestamp 2, # Timestamp
9, # Release Notes 9, # Release Notes
12, 13, 14, 15, 16, 17, 18, # Window sizes 12, 13, 14, 15, # Window sizes
7, 28, # Fonts (depends on system default) 16, 17, 18, 19, # Window sizes
7, 29, # Fonts (depends on system default)
] ]
assert cmpFiles(testFile, compFile, ignoreLines) assert cmpFiles(testFile, compFile, ignoreLines)