Add the basic structure for a novel tree
This commit is contained in:
+21
-8
@@ -95,14 +95,15 @@ class Config:
|
||||
self.lastNotes = "" # The latest release notes that have been shown
|
||||
|
||||
## Sizes
|
||||
self.winGeometry = [1200, 650]
|
||||
self.treeColWidth = [200, 50, 30]
|
||||
self.projColWidth = [200, 60, 140]
|
||||
self.mainPanePos = [300, 800]
|
||||
self.docPanePos = [400, 400]
|
||||
self.viewPanePos = [500, 150]
|
||||
self.outlnPanePos = [500, 150]
|
||||
self.isFullScreen = False
|
||||
self.winGeometry = [1200, 650]
|
||||
self.treeColWidth = [200, 50, 30]
|
||||
self.novelColWidth = [200, 50]
|
||||
self.projColWidth = [200, 60, 140]
|
||||
self.mainPanePos = [300, 800]
|
||||
self.docPanePos = [400, 400]
|
||||
self.viewPanePos = [500, 150]
|
||||
self.outlnPanePos = [500, 150]
|
||||
self.isFullScreen = False
|
||||
|
||||
## Features
|
||||
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
||||
@@ -395,6 +396,9 @@ class Config:
|
||||
self.treeColWidth = self._parseLine(
|
||||
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(
|
||||
cnfParse, cnfSec, "projcols", self.CNF_I_LST, self.projColWidth
|
||||
)
|
||||
@@ -597,6 +601,7 @@ class Config:
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "geometry", self._packList(self.winGeometry))
|
||||
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, "mainpane", self._packList(self.mainPanePos))
|
||||
cnfParse.set(cnfSec, "docpane", self._packList(self.docPanePos))
|
||||
@@ -816,6 +821,11 @@ class Config:
|
||||
self.confChanged = 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):
|
||||
self.projColWidth = [int(x/self.guiScale) for x in colWidths]
|
||||
self.confChanged = True
|
||||
@@ -872,6 +882,9 @@ class Config:
|
||||
def getTreeColWidths(self):
|
||||
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):
|
||||
return [int(x*self.guiScale) for x in self.projColWidth]
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from nw.gui.docviewer import GuiDocViewer, GuiDocViewDetails
|
||||
from nw.gui.itemdetails import GuiItemDetails
|
||||
from nw.gui.itemeditor import GuiItemEditor
|
||||
from nw.gui.mainmenu import GuiMainMenu
|
||||
from nw.gui.noveltree import GuiNovelTree
|
||||
from nw.gui.outline import GuiOutline
|
||||
from nw.gui.outlinedetails import GuiOutlineDetails
|
||||
from nw.gui.preferences import GuiPreferences
|
||||
@@ -31,6 +32,7 @@ __all__ = [
|
||||
"GuiItemDetails",
|
||||
"GuiItemEditor",
|
||||
"GuiMainMenu",
|
||||
"GuiNovelTree",
|
||||
"GuiMainStatus",
|
||||
"GuiOutline",
|
||||
"GuiOutlineDetails",
|
||||
|
||||
@@ -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 2018–2020, 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
@@ -357,9 +357,9 @@ class GuiProjectTree(QTreeWidget):
|
||||
"""Return the column widths for the tree columns.
|
||||
"""
|
||||
retVals = [
|
||||
self.columnWidth(0),
|
||||
self.columnWidth(1),
|
||||
self.columnWidth(2),
|
||||
self.columnWidth(self.C_NAME),
|
||||
self.columnWidth(self.C_COUNT),
|
||||
self.columnWidth(self.C_EXPORT),
|
||||
]
|
||||
return retVals
|
||||
|
||||
|
||||
+36
-22
@@ -42,9 +42,9 @@ from PyQt5.QtWidgets import (
|
||||
from nw.gui import (
|
||||
GuiAbout, GuiBuildNovel, GuiDocEditor, GuiDocMerge, GuiDocSplit,
|
||||
GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiItemEditor,
|
||||
GuiMainMenu, GuiMainStatus, GuiOutline, GuiOutlineDetails, GuiPreferences,
|
||||
GuiProjectLoad, GuiProjectSettings, GuiProjectTree, GuiProjectWizard,
|
||||
GuiTheme, GuiWritingStats
|
||||
GuiMainMenu, GuiMainStatus, GuiNovelTree, GuiOutline, GuiOutlineDetails,
|
||||
GuiPreferences, GuiProjectLoad, GuiProjectSettings, GuiProjectTree,
|
||||
GuiProjectWizard, GuiTheme, GuiWritingStats
|
||||
)
|
||||
from nw.core import NWProject, NWDoc, NWIndex
|
||||
from nw.constants import nwItemType, nwItemClass, nwAlert
|
||||
@@ -99,6 +99,7 @@ class GuiMain(QMainWindow):
|
||||
# Main GUI Elements
|
||||
self.statusBar = GuiMainStatus(self)
|
||||
self.treeView = GuiProjectTree(self)
|
||||
self.novelView = GuiNovelTree(self)
|
||||
self.docEditor = GuiDocEditor(self)
|
||||
self.viewMeta = GuiDocViewDetails(self)
|
||||
self.docViewer = GuiDocViewer(self)
|
||||
@@ -111,11 +112,23 @@ class GuiMain(QMainWindow):
|
||||
self.statusIcons = []
|
||||
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
|
||||
self.treePane = QWidget()
|
||||
self.treeBox = QVBoxLayout()
|
||||
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.treePane.setLayout(self.treeBox)
|
||||
|
||||
@@ -136,31 +149,31 @@ class GuiMain(QMainWindow):
|
||||
self.splitOutline.addWidget(self.projMeta)
|
||||
self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())
|
||||
|
||||
# Main Tabs : Edirot / Outline
|
||||
self.tabWidget = QTabWidget()
|
||||
self.tabWidget.setTabPosition(QTabWidget.East)
|
||||
self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;}")
|
||||
self.tabWidget.addTab(self.splitDocs, "Editor")
|
||||
self.tabWidget.addTab(self.splitOutline, "Outline")
|
||||
self.tabWidget.currentChanged.connect(self._mainTabChanged)
|
||||
# Main Tabs : Editor / Outline
|
||||
self.mainTabs = QTabWidget()
|
||||
self.mainTabs.setTabPosition(QTabWidget.East)
|
||||
self.mainTabs.setStyleSheet("QTabWidget::pane {border: 0;}")
|
||||
self.mainTabs.addTab(self.splitDocs, "Editor")
|
||||
self.mainTabs.addTab(self.splitOutline, "Outline")
|
||||
self.mainTabs.currentChanged.connect(self._mainTabChanged)
|
||||
|
||||
# Splitter : Project Tree / Main Tabs
|
||||
xCM = self.mainConf.pxInt(4)
|
||||
self.splitMain = QSplitter(Qt.Horizontal)
|
||||
self.splitMain.setContentsMargins(xCM, xCM, xCM, xCM)
|
||||
self.splitMain.addWidget(self.treePane)
|
||||
self.splitMain.addWidget(self.tabWidget)
|
||||
self.splitMain.addWidget(self.mainTabs)
|
||||
self.splitMain.setSizes(self.mainConf.getMainPanePos())
|
||||
|
||||
# Indices of All Splitter Widgets
|
||||
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.idxViewer = self.splitDocs.indexOf(self.splitView)
|
||||
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
|
||||
self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
|
||||
self.idxTabEdit = self.tabWidget.indexOf(self.splitDocs)
|
||||
self.idxTabProj = self.tabWidget.indexOf(self.splitOutline)
|
||||
self.idxTabEdit = self.mainTabs.indexOf(self.splitDocs)
|
||||
self.idxTabProj = self.mainTabs.indexOf(self.splitOutline)
|
||||
|
||||
# Splitter Behaviour
|
||||
self.splitMain.setCollapsible(self.idxTree, False)
|
||||
@@ -355,7 +368,7 @@ class GuiMain(QMainWindow):
|
||||
self.theIndex.clearIndex()
|
||||
self.clearGUI()
|
||||
self.hasProject = False
|
||||
self.tabWidget.setCurrentWidget(self.splitDocs)
|
||||
self.mainTabs.setCurrentWidget(self.splitDocs)
|
||||
|
||||
return saveOK
|
||||
|
||||
@@ -371,7 +384,7 @@ class GuiMain(QMainWindow):
|
||||
return False
|
||||
|
||||
# Switch main tab to editor view
|
||||
self.tabWidget.setCurrentWidget(self.splitDocs)
|
||||
self.mainTabs.setCurrentWidget(self.splitDocs)
|
||||
|
||||
# Try to open the project
|
||||
if not self.theProject.openProject(projFile):
|
||||
@@ -490,7 +503,7 @@ class GuiMain(QMainWindow):
|
||||
return False
|
||||
|
||||
self.closeDocument()
|
||||
self.tabWidget.setCurrentWidget(self.splitDocs)
|
||||
self.mainTabs.setCurrentWidget(self.splitDocs)
|
||||
if self.docEditor.loadText(tHandle, tLine):
|
||||
if changeFocus:
|
||||
self.docEditor.setFocus()
|
||||
@@ -575,7 +588,7 @@ class GuiMain(QMainWindow):
|
||||
return False
|
||||
|
||||
# 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)
|
||||
if self.docViewer.loadText(tHandle):
|
||||
@@ -797,7 +810,7 @@ class GuiMain(QMainWindow):
|
||||
return False
|
||||
|
||||
logger.verbose("Forcing a rebuild of the Project Outline")
|
||||
self.tabWidget.setCurrentWidget(self.splitOutline)
|
||||
self.mainTabs.setCurrentWidget(self.splitOutline)
|
||||
self.projView.refreshTree(overRide=True)
|
||||
|
||||
return True
|
||||
@@ -1022,6 +1035,7 @@ class GuiMain(QMainWindow):
|
||||
|
||||
self.mainConf.setShowRefPanel(self.viewMeta.isVisible())
|
||||
self.mainConf.setTreeColWidths(self.treeView.getColumnSizes())
|
||||
self.mainConf.setNovelColWidths(self.novelView.getColumnSizes())
|
||||
if not self.mainConf.isFullScreen:
|
||||
self.mainConf.setWinSize(self.width(), self.height())
|
||||
|
||||
@@ -1078,7 +1092,7 @@ class GuiMain(QMainWindow):
|
||||
self.mainMenu.aFocusMode.setChecked(self.isFocusMode)
|
||||
if self.isFocusMode:
|
||||
logger.debug("Activating Focus Mode")
|
||||
self.tabWidget.setCurrentWidget(self.splitDocs)
|
||||
self.mainTabs.setCurrentWidget(self.splitDocs)
|
||||
else:
|
||||
logger.debug("Deactivating Focus Mode")
|
||||
|
||||
@@ -1086,7 +1100,7 @@ class GuiMain(QMainWindow):
|
||||
self.treePane.setVisible(isVisible)
|
||||
self.statusBar.setVisible(isVisible)
|
||||
self.mainMenu.setVisible(isVisible)
|
||||
self.tabWidget.tabBar().setVisible(isVisible)
|
||||
self.mainTabs.tabBar().setVisible(isVisible)
|
||||
|
||||
hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter
|
||||
self.docEditor.docFooter.setVisible(not hideDocFooter)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?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>
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jane Smith</author>
|
||||
<author>Jay Doh</author>
|
||||
<saveCount>810</saveCount>
|
||||
<autoCount>153</autoCount>
|
||||
<editTime>39261</editTime>
|
||||
<saveCount>836</saveCount>
|
||||
<autoCount>155</autoCount>
|
||||
<editTime>39747</editTime>
|
||||
</project>
|
||||
<settings>
|
||||
<doBackup>False</doBackup>
|
||||
|
||||
@@ -11,6 +11,7 @@ lastnotes = 1.0
|
||||
[Sizes]
|
||||
geometry = 1200, 650
|
||||
treecols = 200, 50, 30
|
||||
novelcols = 200, 50
|
||||
projcols = 200, 60, 140
|
||||
mainpane = 300, 800
|
||||
docpane = 400, 400
|
||||
|
||||
@@ -11,6 +11,7 @@ lastnotes = 1.0
|
||||
[Sizes]
|
||||
geometry = 1100, 650
|
||||
treecols = 120, 30, 50
|
||||
novelcols = 200, 50
|
||||
projcols = 140, 55, 140
|
||||
mainpane = 300, 800
|
||||
docpane = 400, 400
|
||||
|
||||
@@ -304,6 +304,19 @@ def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir):
|
||||
|
||||
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
|
||||
tmpConf.guiScale = 2.0
|
||||
assert tmpConf.setProjColWidths([10, 20, 30])
|
||||
|
||||
@@ -24,7 +24,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
|
||||
nwGUI.mainConf.lastPath = nwLipsum
|
||||
|
||||
nwGUI.rebuildIndex()
|
||||
nwGUI.tabWidget.setCurrentIndex(nwGUI.idxTabProj)
|
||||
nwGUI.mainTabs.setCurrentIndex(nwGUI.idxTabProj)
|
||||
|
||||
assert nwGUI.projView.topLevelItemCount() > 0
|
||||
|
||||
|
||||
@@ -220,10 +220,11 @@ def testGuiPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir):
|
||||
compFile = os.path.join(refDir, "guiPreferences_novelwriter.conf")
|
||||
copyfile(projFile, testFile)
|
||||
ignoreLines = [
|
||||
2, # Timestamp
|
||||
9, # Release Notes
|
||||
12, 13, 14, 15, 16, 17, 18, # Window sizes
|
||||
7, 28, # Fonts (depends on system default)
|
||||
2, # Timestamp
|
||||
9, # Release Notes
|
||||
12, 13, 14, 15, # Window sizes
|
||||
16, 17, 18, 19, # Window sizes
|
||||
7, 29, # Fonts (depends on system default)
|
||||
]
|
||||
assert cmpFiles(testFile, compFile, ignoreLines)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user