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
+10 -1
View File
@@ -53,6 +53,7 @@ class Config:
## General
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
+60 -10
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.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
+6 -4
View File
@@ -47,7 +47,7 @@ class GuiMain(QMainWindow):
self.splitMain.addWidget(self.docEditor)
self.treeBox = QVBoxLayout()
self.treeView = GuiDocTree()
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
+103 -7
View File
@@ -15,7 +15,10 @@ import nw
from os import path, mkdir
from lxml import etree
from datetime import datetime
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):
# Internal
self.mainConf = nw.CONFIG
self.projTree = []
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>