Added item status, and added icons and flags to the main treeview
This commit is contained in:
@@ -43,6 +43,7 @@ class nwItemLayout(Enum):
|
||||
PARTITION = 3
|
||||
CHAPTER = 4
|
||||
SCENE = 5
|
||||
NOTE = 6
|
||||
|
||||
# END Enum nwItemLayout
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""novelWriter GUI Document Details
|
||||
|
||||
novelWriter – GUI Document Details
|
||||
====================================
|
||||
Class holding the left side document details panel
|
||||
|
||||
File History:
|
||||
Created: 2019-04-24 [0.0.1]
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import nw
|
||||
|
||||
from os import path
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel
|
||||
|
||||
from nw.enum import nwItemType, nwItemClass, nwItemLayout
|
||||
from nw.project.item import NWItem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiDocDetails(QFrame):
|
||||
|
||||
C_NAME = 0
|
||||
C_COUNT = 1
|
||||
C_FLAGS = 2
|
||||
C_HANDLE = 3
|
||||
|
||||
def __init__(self, theProject):
|
||||
QFrame.__init__(self)
|
||||
|
||||
logger.debug("Initialising DocDetails ...")
|
||||
self.mainConf = nw.CONFIG
|
||||
self.debugGUI = self.mainConf.debugGUI
|
||||
self.theProject = theProject
|
||||
|
||||
self.mainBox = QGridLayout(self)
|
||||
self.mainBox.setVerticalSpacing(1)
|
||||
self.mainBox.setHorizontalSpacing(15)
|
||||
self.setLayout(self.mainBox)
|
||||
|
||||
self.fntOne = QFont()
|
||||
self.fntOne.setPointSize(10)
|
||||
self.fntOne.setBold(True)
|
||||
|
||||
self.fntTwo = QFont()
|
||||
self.fntTwo.setPointSize(10)
|
||||
|
||||
colOne = ["Name","Status","Class","Layout"]
|
||||
for nRow in range(4):
|
||||
lblOne = QLabel(colOne[nRow])
|
||||
lblOne.setFont(self.fntOne)
|
||||
self.mainBox.addWidget(lblOne,nRow+1,0)
|
||||
|
||||
self.mainBox.setColumnStretch(0,0)
|
||||
self.mainBox.setColumnStretch(1,1)
|
||||
|
||||
logger.debug("DocDetails initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
def buildViewBox(self, tHandle):
|
||||
|
||||
nwItem = self.theProject.getItem(tHandle)
|
||||
itemStatus = nwItem.itemStatus
|
||||
if itemStatus < 0 or itemStatus >= len(self.theProject.statusLabels):
|
||||
itemStatus = 0
|
||||
|
||||
colTwo = [
|
||||
nwItem.itemName,
|
||||
self.theProject.statusLabels[itemStatus],
|
||||
NWItem.CLASS_NAME[nwItem.itemClass],
|
||||
NWItem.LAYOUT_NAME[nwItem.itemLayout],
|
||||
]
|
||||
|
||||
for nRow in range(4):
|
||||
lblTwo = QLabel(colTwo[nRow])
|
||||
lblTwo.setFont(self.fntTwo)
|
||||
self.mainBox.addWidget(lblTwo,nRow+1,1)
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiDocDetails
|
||||
+35
-10
@@ -14,8 +14,8 @@ import logging
|
||||
import nw
|
||||
|
||||
from os import path
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtCore import Qt, QSize
|
||||
from PyQt5.QtGui import QIcon, QFont, QColor
|
||||
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, QInputDialog, QLineEdit
|
||||
|
||||
from nw.enum import nwItemType, nwItemClass
|
||||
@@ -43,10 +43,13 @@ class GuiDocTree(QTreeWidget):
|
||||
self.setExpandsOnDoubleClick(True)
|
||||
self.setIndentation(13)
|
||||
self.setColumnCount(4)
|
||||
self.setHeaderLabels(["Name","S","#","Handle"])
|
||||
self.setHeaderLabels(["Name","Count","Flags","Handle"])
|
||||
if not self.debugGUI:
|
||||
self.hideColumn(self.C_HANDLE)
|
||||
|
||||
treeHead = self.headerItem()
|
||||
treeHead.setTextAlignment(self.C_COUNT,Qt.AlignRight)
|
||||
|
||||
# Allow Move by Drag & Drop
|
||||
self.setDragEnabled(True)
|
||||
self.setDragDropMode(QAbstractItemView.InternalMove)
|
||||
@@ -54,6 +57,9 @@ class GuiDocTree(QTreeWidget):
|
||||
for colN in range(len(self.mainConf.treeColWidth)):
|
||||
self.setColumnWidth(colN,self.mainConf.treeColWidth[colN])
|
||||
|
||||
self.fontFlags = QFont("Monospace",10)
|
||||
self.fontCount = QFont("Monospace",10)
|
||||
|
||||
logger.debug("DocTree initialisation complete")
|
||||
|
||||
return
|
||||
@@ -139,34 +145,53 @@ class GuiDocTree(QTreeWidget):
|
||||
return theItem, theCount+1
|
||||
|
||||
def _addTreeItem(self, nwItem):
|
||||
|
||||
tName = nwItem.itemName
|
||||
tHandle = nwItem.itemHandle
|
||||
pHandle = nwItem.parHandle
|
||||
tStatus = 0
|
||||
tStatus = NWItem.CLASS_FLAG[nwItem.itemClass]
|
||||
if nwItem.itemType == nwItemType.FILE:
|
||||
tStatus += "."+NWItem.LAYOUT_FLAG[nwItem.itemLayout]
|
||||
nStatus = nwItem.itemStatus
|
||||
if nStatus < 0 or nStatus >= len(self.theProject.statusIcons):
|
||||
nStatus = 0
|
||||
|
||||
newItem = QTreeWidgetItem([""]*4)
|
||||
newItem.setText(self.C_NAME, tName)
|
||||
newItem.setText(self.C_FLAGS, str(tStatus))
|
||||
newItem.setText(self.C_COUNT, "0")
|
||||
|
||||
newItem.setText(self.C_NAME,tName)
|
||||
|
||||
newItem.setText(self.C_COUNT,"0")
|
||||
# newItem.setFont(self.C_COUNT,self.fontCount)
|
||||
newItem.setForeground(self.C_COUNT,QColor(0,105,135))
|
||||
newItem.setTextAlignment(self.C_COUNT,Qt.AlignRight)
|
||||
|
||||
newItem.setText(self.C_FLAGS,tStatus)
|
||||
newItem.setIcon(self.C_FLAGS,self.theProject.statusIcons[nStatus])
|
||||
newItem.setFont(self.C_FLAGS,self.fontFlags)
|
||||
|
||||
newItem.setText(self.C_HANDLE, tHandle)
|
||||
|
||||
self.theMap[tHandle] = newItem
|
||||
if pHandle is None:
|
||||
self.addTopLevelItem(newItem)
|
||||
else:
|
||||
self.theMap[pHandle].addChild(newItem)
|
||||
self.propagateCount(tHandle, nwItem.wordCount)
|
||||
newItem.setTextAlignment(self.C_COUNT,Qt.AlignRight)
|
||||
|
||||
newItem.setExpanded(nwItem.isExpanded)
|
||||
|
||||
if nwItem.itemType == nwItemType.ROOT:
|
||||
newItem.setIcon(self.C_NAME, QIcon.fromTheme("drive-harddisk"))
|
||||
elif nwItem.itemType == nwItemType.FOLDER:
|
||||
newItem.setIcon(self.C_NAME, QIcon.fromTheme("folder"))
|
||||
elif nwItem.itemType == nwItemType.FILE:
|
||||
newItem.setIcon(self.C_NAME, QIcon.fromTheme("x-office-document"))
|
||||
|
||||
return True
|
||||
|
||||
def propagateCount(self, tHandle, theCount, nDepth=0):
|
||||
tItem = self.theMap[tHandle]
|
||||
tItem.setText(self.C_COUNT,str(theCount))
|
||||
tItem.setText(self.C_COUNT,"{:n}".format(theCount))
|
||||
pItem = tItem.parent()
|
||||
if pItem is not None:
|
||||
pCount = 0
|
||||
@@ -184,7 +209,7 @@ class GuiDocTree(QTreeWidget):
|
||||
self._addTreeItem(nwItem)
|
||||
return True
|
||||
|
||||
def _getSelectedHandle(self):
|
||||
def getSelectedHandle(self):
|
||||
selItem = self.selectedItems()
|
||||
if len(selItem) == 0:
|
||||
return None
|
||||
@@ -210,7 +235,7 @@ class GuiDocTree(QTreeWidget):
|
||||
"""Overload the drop of dragged item event to check whether the drop is allowed
|
||||
or not. Disallowed drops are cancelled.
|
||||
"""
|
||||
sHandle = self._getSelectedHandle()
|
||||
sHandle = self.getSelectedHandle()
|
||||
if sHandle is None:
|
||||
return
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ class GuiDocTreeCtx(QMenu):
|
||||
return
|
||||
|
||||
def _buildSubMenuAddRoot(self, itemClass):
|
||||
mnuSub = QAction("Add "+NWItem.CLASS_NAME[itemClass], self)
|
||||
mnuSub = QAction("Add %s Root" % NWItem.CLASS_NAME[itemClass], self)
|
||||
mnuSub.triggered.connect(lambda: self._ctxSignal(
|
||||
nwItemAction.ADD_ROOT,
|
||||
itemClass,
|
||||
|
||||
+18
-3
@@ -21,6 +21,7 @@ from PyQt5.QtGui import QIcon
|
||||
from nw.gui.doctree import GuiDocTree
|
||||
from nw.gui.doctreectx import GuiDocTreeCtx
|
||||
from nw.gui.doceditor import GuiDocEditor
|
||||
from nw.gui.docdetails import GuiDocDetails
|
||||
from nw.gui.projecteditor import GuiProjectEditor
|
||||
from nw.gui.statusbar import GuiMainStatus
|
||||
from nw.project.project import NWProject
|
||||
@@ -44,8 +45,9 @@ class GuiMain(QMainWindow):
|
||||
self.setWindowIcon(QIcon(path.join(self.mainConf.appPath,"..","novelWriter.svg")))
|
||||
|
||||
# Main GUI Elements
|
||||
self.docEditor = GuiDocEditor(self)
|
||||
self.treeView = GuiDocTree(self.theProject)
|
||||
self.docEditor = GuiDocEditor(self)
|
||||
self.docDetails = GuiDocDetails(self.theProject)
|
||||
self.treeView = GuiDocTree(self.theProject)
|
||||
|
||||
# Assemble Main Window
|
||||
self.stackPane = QStackedWidget()
|
||||
@@ -53,8 +55,14 @@ class GuiMain(QMainWindow):
|
||||
self.stackDoc = self.stackPane.addWidget(self.docEditor)
|
||||
self.stackPane.setCurrentIndex(self.stackNone)
|
||||
|
||||
self.treePane = QFrame()
|
||||
self.treeBox = QVBoxLayout()
|
||||
self.treeBox.addWidget(self.treeView)
|
||||
self.treeBox.addWidget(self.docDetails)
|
||||
self.treePane.setLayout(self.treeBox)
|
||||
|
||||
self.splitMain = QSplitter(Qt.Horizontal)
|
||||
self.splitMain.addWidget(self.treeView)
|
||||
self.splitMain.addWidget(self.treePane)
|
||||
self.splitMain.addWidget(self.stackPane)
|
||||
self.splitMain.setSizes(self.mainConf.mainPanePos)
|
||||
self.splitMain.splitterMoved.connect(self._splitMainMove)
|
||||
@@ -65,6 +73,7 @@ class GuiMain(QMainWindow):
|
||||
self._buildMenu()
|
||||
self.treeView.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.treeView.customContextMenuRequested.connect(self._openDocTreeContextMenu)
|
||||
self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
|
||||
self.treeView.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||
self.treeView.buildTree()
|
||||
|
||||
@@ -159,6 +168,12 @@ class GuiMain(QMainWindow):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _treeSingleClick(self):
|
||||
sHandle = self.treeView.getSelectedHandle()
|
||||
if sHandle is not None:
|
||||
self.docDetails.buildViewBox(sHandle)
|
||||
return
|
||||
|
||||
def _treeDoubleClick(self, tItem, colNo):
|
||||
tHandle = tItem.text(3)
|
||||
logger.verbose("User double clicked tree item with handle %s" % tHandle)
|
||||
|
||||
+20
-3
@@ -25,7 +25,7 @@ class NWItem():
|
||||
|
||||
MAX_DEPTH = 8
|
||||
CLASS_NAME = {
|
||||
nwItemClass.NO_CLASS : "Folder",
|
||||
nwItemClass.NO_CLASS : "Custom",
|
||||
nwItemClass.NOVEL : "Novel",
|
||||
nwItemClass.PLOT : "Plot",
|
||||
nwItemClass.CHARACTER : "Characters",
|
||||
@@ -42,6 +42,15 @@ class NWItem():
|
||||
nwItemClass.TIMELINE : "T",
|
||||
nwItemClass.OBJECT : "O",
|
||||
}
|
||||
LAYOUT_NAME = {
|
||||
nwItemLayout.NO_LAYOUT : "None",
|
||||
nwItemLayout.TITLE_PAGE : "Title Page",
|
||||
nwItemLayout.SIMPLE_PAGE : "Simple Page",
|
||||
nwItemLayout.PARTITION : "Partition",
|
||||
nwItemLayout.CHAPTER : "Chapter",
|
||||
nwItemLayout.SCENE : "Scene",
|
||||
nwItemLayout.NOTE : "Note",
|
||||
}
|
||||
LAYOUT_FLAG = {
|
||||
nwItemLayout.NO_LAYOUT : "Xo",
|
||||
nwItemLayout.TITLE_PAGE : "Tt",
|
||||
@@ -49,6 +58,7 @@ class NWItem():
|
||||
nwItemLayout.PARTITION : "Pt",
|
||||
nwItemLayout.CHAPTER : "Ch",
|
||||
nwItemLayout.SCENE : "Sc",
|
||||
nwItemLayout.NOTE : "Nt",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
@@ -60,6 +70,7 @@ class NWItem():
|
||||
self.itemType = nwItemType.NO_TYPE
|
||||
self.itemClass = nwItemClass.NO_CLASS
|
||||
self.itemLayout = nwItemLayout.NO_LAYOUT
|
||||
self.itemStatus = 0
|
||||
self.itemDepth = None
|
||||
self.hasChildren = False
|
||||
self.isExpanded = False
|
||||
@@ -83,12 +94,12 @@ class NWItem():
|
||||
xSub = self._subPack(xPack,"name", text=str(self.itemName))
|
||||
xSub = self._subPack(xPack,"type", text=str(self.itemType.name))
|
||||
xSub = self._subPack(xPack,"class", text=str(self.itemClass.name))
|
||||
xSub = self._subPack(xPack,"status", text=str(self.itemStatus))
|
||||
xSub = self._subPack(xPack,"depth", text=str(self.itemDepth))
|
||||
xSub = self._subPack(xPack,"children", text=str(self.hasChildren))
|
||||
xSub = self._subPack(xPack,"expanded", text=str(self.isExpanded))
|
||||
if self.itemClass == nwItemClass.NOVEL and self.itemLayout is not nwItemLayout.NO_LAYOUT:
|
||||
xSub = self._subPack(xPack,"layout", text=str(self.itemLayout.name))
|
||||
if self.itemType == nwItemType.FILE:
|
||||
xSub = self._subPack(xPack,"layout", text=str(self.itemLayout.name))
|
||||
xSub = self._subPack(xPack,"charCount", text=str(self.charCount), none=False)
|
||||
xSub = self._subPack(xPack,"wordCount", text=str(self.wordCount), none=False)
|
||||
xSub = self._subPack(xPack,"paraCount", text=str(self.paraCount), none=False)
|
||||
@@ -113,6 +124,7 @@ class NWItem():
|
||||
elif tagName == "type": self.setType(tagValue)
|
||||
elif tagName == "class": self.setClass(tagValue)
|
||||
elif tagName == "layout": self.setLayout(tagValue)
|
||||
elif tagName == "status": self.setStatus(tagValue)
|
||||
elif tagName == "depth": self.setDepth(tagValue)
|
||||
elif tagName == "children": self.setChildren(tagValue)
|
||||
elif tagName == "expanded": self.setExpanded(tagValue)
|
||||
@@ -182,6 +194,11 @@ class NWItem():
|
||||
self.itemLayout = nwItemLayout.NO_LAYOUT
|
||||
return
|
||||
|
||||
def setStatus(self, theStatus):
|
||||
theStatus = self._checkInt(theStatus,0)
|
||||
self.itemStatus = theStatus
|
||||
return
|
||||
|
||||
def setDepth(self, theDepth):
|
||||
theDepth = self._checkInt(theDepth,-1)
|
||||
if theDepth >= 0 and theDepth <= self.MAX_DEPTH:
|
||||
|
||||
@@ -19,6 +19,8 @@ from hashlib import sha256
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtGui import QIcon, QPixmap, QColor
|
||||
|
||||
from nw.enum import nwItemType, nwItemClass, nwItemAction
|
||||
from nw.project.item import NWItem
|
||||
|
||||
@@ -41,6 +43,16 @@ class NWProject():
|
||||
self.bookTitle = ""
|
||||
self.bookAuthors = []
|
||||
|
||||
self.statusCols = [
|
||||
("New", 100,100,100),
|
||||
("Note", 200, 50, 0),
|
||||
("Draft", 200,150, 0),
|
||||
("Finished", 50,200, 0),
|
||||
]
|
||||
self.statusIcons = []
|
||||
self.statusLabels = []
|
||||
self._makeStatusIcons()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -79,6 +91,7 @@ class NWProject():
|
||||
self.projName = ""
|
||||
self.bookTitle = ""
|
||||
self.bookAuthors = []
|
||||
self._makeStatusIcons()
|
||||
hNovel = self.newRoot("Novel", nwItemClass.NOVEL)
|
||||
hChars = self.newRoot("Characters", nwItemClass.CHARACTER)
|
||||
hWorld = self.newRoot("World", nwItemClass.WORLD)
|
||||
@@ -147,6 +160,7 @@ class NWProject():
|
||||
nwItem.setFromTag(xValue.tag,xValue.text)
|
||||
self._appendItem(tHandle,pHandle,nwItem)
|
||||
|
||||
self._makeStatusIcons()
|
||||
self.mainConf.setRecent(self.projPath)
|
||||
|
||||
return True
|
||||
@@ -365,6 +379,16 @@ class NWProject():
|
||||
|
||||
return
|
||||
|
||||
def _makeStatusIcons(self):
|
||||
self.statusIcons = []
|
||||
self.statusLabels = []
|
||||
for sLabel, sR, sG, sB in self.statusCols:
|
||||
theIcon = QPixmap(32,32)
|
||||
theIcon.fill(QColor(sR,sG,sB))
|
||||
self.statusIcons.append(QIcon(theIcon))
|
||||
self.statusLabels.append(sLabel)
|
||||
return
|
||||
|
||||
def _makeHandle(self, addSeed=""):
|
||||
newSeed = str(time()) + addSeed
|
||||
logger.verbose("Generating handle with seed '%s'" % newSeed)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="0.0.1" fileVersion="1.0" timeStamp="2019-04-24 18:07:47">
|
||||
<novelWriterXML appVersion="0.0.1" fileVersion="1.0" timeStamp="2019-04-24 22:34:36">
|
||||
<project>
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
@@ -11,6 +11,7 @@
|
||||
<name>Novel</name>
|
||||
<type>ROOT</type>
|
||||
<class>NOVEL</class>
|
||||
<status>0</status>
|
||||
<depth>0</depth>
|
||||
<children>True</children>
|
||||
<expanded>True</expanded>
|
||||
@@ -19,6 +20,7 @@
|
||||
<name>New Chapter</name>
|
||||
<type>FOLDER</type>
|
||||
<class>NOVEL</class>
|
||||
<status>1</status>
|
||||
<depth>1</depth>
|
||||
<children>True</children>
|
||||
<expanded>True</expanded>
|
||||
@@ -27,9 +29,11 @@
|
||||
<name>New Scene</name>
|
||||
<type>FILE</type>
|
||||
<class>NOVEL</class>
|
||||
<status>2</status>
|
||||
<depth>2</depth>
|
||||
<children>False</children>
|
||||
<expanded>False</expanded>
|
||||
<layout>SCENE</layout>
|
||||
<charCount>2575</charCount>
|
||||
<wordCount>377</wordCount>
|
||||
<paraCount>5</paraCount>
|
||||
@@ -38,9 +42,11 @@
|
||||
<name>Test File</name>
|
||||
<type>FILE</type>
|
||||
<class>NOVEL</class>
|
||||
<status>1</status>
|
||||
<depth>2</depth>
|
||||
<children>False</children>
|
||||
<expanded>False</expanded>
|
||||
<layout>SCENE</layout>
|
||||
<charCount>125</charCount>
|
||||
<wordCount>24</wordCount>
|
||||
<paraCount>2</paraCount>
|
||||
@@ -49,6 +55,7 @@
|
||||
<name>Characters</name>
|
||||
<type>ROOT</type>
|
||||
<class>CHARACTER</class>
|
||||
<status>0</status>
|
||||
<depth>0</depth>
|
||||
<children>True</children>
|
||||
<expanded>True</expanded>
|
||||
@@ -57,9 +64,11 @@
|
||||
<name>Jon Smith</name>
|
||||
<type>FILE</type>
|
||||
<class>CHARACTER</class>
|
||||
<status>0</status>
|
||||
<depth>1</depth>
|
||||
<children>False</children>
|
||||
<expanded>False</expanded>
|
||||
<layout>NOTE</layout>
|
||||
<charCount>0</charCount>
|
||||
<wordCount>0</wordCount>
|
||||
<paraCount>0</paraCount>
|
||||
@@ -68,9 +77,11 @@
|
||||
<name>Jane Smith</name>
|
||||
<type>FILE</type>
|
||||
<class>CHARACTER</class>
|
||||
<status>0</status>
|
||||
<depth>1</depth>
|
||||
<children>False</children>
|
||||
<expanded>False</expanded>
|
||||
<layout>NOTE</layout>
|
||||
<charCount>0</charCount>
|
||||
<wordCount>0</wordCount>
|
||||
<paraCount>0</paraCount>
|
||||
@@ -79,6 +90,7 @@
|
||||
<name>World</name>
|
||||
<type>ROOT</type>
|
||||
<class>WORLD</class>
|
||||
<status>0</status>
|
||||
<depth>0</depth>
|
||||
<children>False</children>
|
||||
<expanded>False</expanded>
|
||||
|
||||
Reference in New Issue
Block a user