Added some the tree building code, with the help of 3 G&Ts.

This commit is contained in:
Veronica K. B. Olsen
2018-10-27 23:54:34 +02:00
parent c8dab032b9
commit 0f8090601b
6 changed files with 314 additions and 29 deletions
+11 -2
View File
@@ -52,7 +52,8 @@ class Config:
self.confChanged = False
## General
self.winGeometry = [1100, 650]
self.winGeometry = [1100, 650]
self.treeColWidth = [120, 30, 50]
# Check if config file exists
if path.isfile(path.join(self.confPath,self.confFile)):
@@ -83,6 +84,10 @@ class Config:
self.winGeometry = self.unpackList(
confParser.get(cnfSec,"geometry"), 2, self.winGeometry
)
if confParser.has_option(cnfSec,"treecols"):
self.treeColWidth = self.unpackList(
confParser.get(cnfSec,"treecols"), 3, self.treeColWidth
)
## Path
cnfSec = "Path"
@@ -105,6 +110,7 @@ class Config:
confParser.add_section(cnfSec)
confParser.set(cnfSec,"timestamp", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
confParser.set(cnfSec,"geometry", self.packList(self.winGeometry))
confParser.set(cnfSec,"treecols", self.packList(self.treeColWidth))
## Path
cnfSec = "Path"
@@ -142,7 +148,6 @@ class Config:
self.recentList.insert(0,recentPath)
return
def setConfPath(self, newPath):
if newPath is None: return
if not path.isfile(newPath):
@@ -161,4 +166,8 @@ class Config:
self.confChanged = True
return
def setTreeColWidths(self, colWidths):
self.treeColWidth = colWidths
return
# End Class Config
+61 -11
View File
@@ -15,28 +15,78 @@ import nw
from os import path
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QTreeView
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QTreeWidgetItemIterator, QAbstractItemView
logger = logging.getLogger(__name__)
class GuiDocTree(QTreeView):
class GuiDocTree(QTreeWidget):
def __init__(self):
QTreeView.__init__(self)
def __init__(self, theProject):
QTreeWidget.__init__(self)
logger.debug("Initialising DocTree ...")
self.mainConf = nw.CONFIG
self.mainConf = nw.CONFIG
self.debugGUI = self.mainConf.debugGUI
self.theProject = theProject
self.theMap = {}
self.treeModel = QStandardItemModel(0, 3, self)
self.treeModel.setHeaderData(0, Qt.Horizontal, "Name")
self.treeModel.setHeaderData(1, Qt.Horizontal, "Words")
self.treeModel.setHeaderData(2, Qt.Horizontal, "Status")
self.setColumnCount(4)
self.setHeaderLabels(["Name","","","Handle"])
if not self.debugGUI:
self.hideColumn(3)
self.setModel(self.treeModel)
# Allow Move by Drag & Drop
self.setDragEnabled(True)
self.setDragDropMode(QAbstractItemView.InternalMove)
for colN in range(len(self.mainConf.treeColWidth)):
self.setColumnWidth(colN,self.mainConf.treeColWidth[colN])
logger.debug("DocTree initialisation complete")
return
def saveTreeOrder(self):
theList = []
for i in range(self.topLevelItemCount()):
theList = self._scanChildren(theList, self.topLevelItem(i))
print(theList)
return True
def _scanChildren(self, theList, theItem):
theList.append(theItem.text(3))
for i in range(theItem.childCount()):
self._scanChildren(theList, theItem.child(i))
return theList
def buildTree(self):
for tHandle in self.theProject.projTree:
nwItem = self.theProject.projTree[tHandle]
tName = nwItem.itemName
tStatus = 0
wCount = 0
pHandle = nwItem.parHandle
newItem = QTreeWidgetItem([
tName, str(tStatus), str(wCount), tHandle
])
self.theMap[tHandle] = newItem
if pHandle is None:
self.addTopLevelItem(newItem)
else:
self.theMap[pHandle].addChild(newItem)
return True
def getColumnSizes(self):
retVals = [
self.columnWidth(0),
self.columnWidth(1),
self.columnWidth(2),
]
return retVals
# END Class GuiDocTree
+7 -5
View File
@@ -46,8 +46,8 @@ class GuiMain(QMainWindow):
self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.docEditor)
self.treeBox = QVBoxLayout()
self.treeView = GuiDocTree()
self.treeBox = QVBoxLayout()
self.treeView = GuiDocTree(self.theProject)
self.treeBox.addWidget(self.treeView)
self.treePane.setLayout(self.treeBox)
@@ -58,8 +58,7 @@ class GuiMain(QMainWindow):
self.setCentralWidget(self.splitMain)
self._buildMenu()
# self.docTabs.createTab()
self.treeView.buildTree()
self.show()
@@ -76,7 +75,8 @@ class GuiMain(QMainWindow):
def newProject(self):
logger.info("Creating new project")
self.docTabs.createTab(tabType=nw.DOCTYPE_PROJECT)
self.theProject.newProject()
self.treeView.buildTree()
return
def openProject(self):
@@ -101,6 +101,7 @@ class GuiMain(QMainWindow):
self.theProject.setProjectPath(projPath)
else:
return False
self.treeView.saveTreeOrder()
self.theProject.saveProject()
return True
@@ -130,6 +131,7 @@ class GuiMain(QMainWindow):
def _closeMain(self):
logger.info("Exiting %s" % nw.__package__)
self.mainConf.setWinSize(self.width(), self.height())
self.mainConf.setTreeColWidths(self.treeView.getColumnSizes())
self.mainConf.saveConfig()
return
+103
View File
@@ -0,0 +1,103 @@
# -*- coding: utf-8 -*
"""novelWriter Project Item
novelWriter Project Item
============================
Class holding a project item
File History:
Created: 2018-10-27 [0.1.0]
"""
import logging
import nw
from os import path, mkdir
from lxml import etree
from datetime import datetime
logger = logging.getLogger(__name__)
class NWItem():
TYPE_ROOT = 0
TYPE_FOLDER = 1
TYPE_FILE = 2
CLASS_NONE = 0
CLASS_NOVEL = 1
CLASS_CHARACTER = 2
CLASS_WORLD = 3
def __init__(self):
self.itemName = ""
self.itemHandle = None
self.parHandle = None
self.itemOrder = None
self.itemType = None
self.itemClass = None
return
def setName(self, theName):
self.itemName = theName.strip()
return
def setHandle(self, theHandle):
self.itemHandle = theHandle
return
def setParent(self, theParent):
self.parHandle = theParent
return
def setOrder(self, theOrder):
self.itemOrder = theOrder
return
def setType(self, theType):
if isinstance(theType, int):
self.itemType = theType
elif theType == "ROOT":
self.itemType = self.TYPE_ROOT
elif theType == "FOLDER":
self.itemType = self.TYPE_FOLDER
elif theType == "FILE":
self.itemType = self.TYPE_FILE
else:
logger.error("Unrecognised item type '%s'" % theType)
self.itemType = None
return
def setClass(self, theClass):
if isinstance(theClass, int):
self.itemClass = theClass
elif theClass == "NONE":
self.itemClass = self.CLASS_NONE
elif theClass == "NOVEL":
self.itemClass = self.CLASS_NOVEL
elif theClass == "CHARACTER":
self.itemClass = self.CLASS_CHARACTER
elif theClass == "WORLD":
self.itemClass = self.CLASS_WORLD
else:
logger.error("Unrecognised root item '%s'" % theClass)
self.itemClass = None
return
def getType(self):
if self.itemType == self.TYPE_ROOT: return "ROOT"
if self.itemType == self.TYPE_FOLDER: return "FOLDER"
if self.itemType == self.TYPE_FILE: return "FILE"
return "NONE"
def getClass(self):
if self.itemClass == self.CLASS_NONE: return "NONE"
if self.itemClass == self.CLASS_NOVEL: return "NOVEL"
if self.itemClass == self.CLASS_CHARACTER: return "CHARACTER"
if self.itemClass == self.CLASS_WORLD: return "WORLD"
return "NONE"
# END Class NWItem
+106 -10
View File
@@ -13,9 +13,12 @@
import logging
import nw
from os import path, mkdir
from lxml import etree
from datetime import datetime
from os import path, mkdir
from lxml import etree
from hashlib import sha256
from datetime import datetime, time
from nw.project.item import NWItem
logger = logging.getLogger(__name__)
@@ -23,10 +26,13 @@ class NWProject():
def __init__(self):
self.mainConf = nw.CONFIG
self.projTree = []
# Internal
self.mainConf = nw.CONFIG
self.seedCount = 0
# Project Settings
self.projTree = {}
self.treeOrder = []
self.projPath = None
self.projFile = "nwProject.nwx"
self.projName = ""
@@ -36,9 +42,47 @@ class NWProject():
return
def buildProjectTree(self):
return True
def newRoot(self, rootName, rootType):
newItem = NWItem()
newItem.setName(rootName)
newItem.setType(NWItem.TYPE_ROOT)
newItem.setClass(rootType)
self._appendItem(None,None,newItem)
return newItem.itemHandle
def newFolder(self, folderName, pHandle):
newItem = NWItem()
newItem.setName(folderName)
newItem.setType(NWItem.TYPE_FOLDER)
newItem.setClass(NWItem.CLASS_NONE)
self._appendItem(None,pHandle,newItem)
return newItem.itemHandle
def newFile(self, fileName, pHandle):
newItem = NWItem()
newItem.setName(fileName)
newItem.setType(NWItem.TYPE_FILE)
newItem.setClass(NWItem.CLASS_NONE)
self._appendItem(None,pHandle,newItem)
return newItem.itemHandle
def newProject(self):
self.projTree = {}
self.treeOrder - []
self.projPath = None
self.projFile = "nwProject.nwx"
self.projName = ""
self.bookTitle = ""
self.bookAuthors = []
hNovel = self.newRoot("Novel", NWItem.CLASS_NOVEL)
hChars = self.newRoot("Characters",NWItem.CLASS_CHARACTER)
hWorld = self.newRoot("World", NWItem.CLASS_WORLD)
hChapt = self.newFolder("New Chapter", hNovel)
hScene = self.newFile("New Scene", hChapt)
return
def openProject(self, fileName):
if not path.isfile(fileName):
@@ -108,6 +152,24 @@ class NWProject():
xBookAuthor = etree.SubElement(xProject,"author")
xBookAuthor.text = bookAuthor
# Save Tree Content
xContent = etree.SubElement(nwXML,"content",attrib={"count":str(len(self.projTree))})
itemIdx = 0
for tHandle in self.projTree.keys():
nwItem = self.projTree[tHandle]
xItem = etree.SubElement(xContent,"item",attrib={
"handle" : str(tHandle),
"parent" : str(nwItem.parHandle),
"order" : str(nwItem.itemOrder),
})
xItemName = etree.SubElement(xItem,"name")
xItemName.text = str(nwItem.itemName)
xItemType = etree.SubElement(xItem,"type")
xItemType.text = str(nwItem.getType())
if nwItem.getClass() is not "NONE":
xItemClass = etree.SubElement(xItem,"class")
xItemClass.text = str(nwItem.getClass())
# Write the xml tree to file
with open(path.join(self.projPath,self.projFile),"wb") as outFile:
outFile.write(etree.tostring(
@@ -146,15 +208,49 @@ class NWProject():
self.bookAuthors.append(bookAuthor)
return True
def setTreeOrder(self, newOrder):
if len(self.treeOrder) != len(newOrder):
logger.warning("Size of new and old tree order does not match")
self.treeOrder - newOrder
return True
#
# Internal Functions
#
def _makeHandle(self,seed=""):
def _appendItem(self, tHandle, pHandle, nwItem):
tHandle = self._checkString(tHandle,self._makeHandle(),False)
pHandle = self._checkString(pHandle,None,True)
logger.verbose("Adding entry %s with parent %s" % (str(tHandle),str(pHandle)))
nwItem.setHandle(tHandle)
nwItem.setParent(pHandle)
self.projTree[tHandle] = nwItem
self.treeOrder.append(tHandle)
return
def _makeHandle(self, seed=""):
seed += str(self.seedCount)
self.seedCount += 1
itemHandle = sha256((str(time())+seed).encode()).hexdigest()[0:13]
# if itemHandle in self.treeLookup.keys():
# logger.warning("BookTree: Duplicate handle encountered! Retrying ...")
# itemHandle = self.makeHandle(seed+"!")
if itemHandle in self.projTree.keys():
logger.warning("Duplicate handle encountered! Retrying ...")
itemHandle = self._makeHandle(seed+"!")
return itemHandle
def _checkString(self,checkValue,defaultValue,allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
if isinstance(checkValue,str): return str(checkValue)
return defaultValue
def _checkInt(self,checkValue,defaultValue,allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
try:
return int(checkValue)
except:
return defaultValue
# END Class NWProject
+26 -1
View File
@@ -1,9 +1,34 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.0" fileVersion="1.0" timeStamp="2018-10-25 22:17:01">
<novelWriterXML appVersion="0.1.0" fileVersion="1.0" timeStamp="2018-10-27 23:46:46">
<project>
<name>Sample Project</name>
<title>Sample Project</title>
<author>Jane Smith</author>
<author>Jay Doh</author>
</project>
<content count="5">
<item handle="7031beac91f75" order="None" parent="None">
<name>Novel</name>
<type>ROOT</type>
<class>NOVEL</class>
</item>
<item handle="f6622b4617424" order="None" parent="None">
<name>Characters</name>
<type>ROOT</type>
<class>CHARACTER</class>
</item>
<item handle="73eee34351f85" order="None" parent="None">
<name>World</name>
<type>ROOT</type>
<class>WORLD</class>
</item>
<item handle="e7ded148d6e4a" order="None" parent="7031beac91f75">
<name>New Chapter</name>
<type>FOLDER</type>
</item>
<item handle="96b68994dfa3d" order="None" parent="e7ded148d6e4a">
<name>New Scene</name>
<type>FILE</type>
</item>
</content>
</novelWriterXML>