Added filters to timeline view GUI

This commit is contained in:
Veronica K. B. Olsen
2019-10-21 20:57:46 +02:00
parent 3aa07e9b33
commit 1434c2bdf3
5 changed files with 119 additions and 21 deletions
+100 -15
View File
@@ -17,12 +17,13 @@ from os import path
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon, QColor, QPixmap from PyQt5.QtGui import QIcon, QColor, QPixmap
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QDialogButtonBox, QLabel,
QDialogButtonBox, QLabel, QPushButton, QHeaderView QPushButton, QHeaderView, QGridLayout, QGroupBox, QCheckBox
) )
from nw.tools.optlaststate import OptLastState from nw.tools.optlaststate import OptLastState
from nw.constants import nwFiles from nw.constants import nwFiles
from nw.enum import nwItemClass
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -45,6 +46,8 @@ class GuiTimeLineView(QDialog):
self.numCols = 0 self.numCols = 0
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.filterBox = QVBoxLayout()
self.centreBox = QHBoxLayout()
self.bottomBox = QHBoxLayout() self.bottomBox = QHBoxLayout()
self.setWindowTitle("Timeline View") self.setWindowTitle("Timeline View")
@@ -55,6 +58,7 @@ class GuiTimeLineView(QDialog):
self.optState.getSetting("winHeight") self.optState.getSetting("winHeight")
) )
# TimeLine Table
self.mainTable = QTableWidget() self.mainTable = QTableWidget()
self.mainTable.setGridStyle(Qt.NoPen) self.mainTable.setGridStyle(Qt.NoPen)
@@ -66,6 +70,41 @@ class GuiTimeLineView(QDialog):
self.vHeader.setSectionResizeMode(QHeaderView.ResizeToContents) self.vHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
self.mainTable.setVerticalHeader(self.vHeader) self.mainTable.setVerticalHeader(self.vHeader)
# Option Box
self.optFilter = QGroupBox("Include Tags", self)
self.optFilterGrid = QGridLayout(self)
self.optFilter.setLayout(self.optFilterGrid)
self.filterPlot = QCheckBox("Plot tags", self)
self.filterPlot.setChecked(self.optState.getSetting("fPlot"))
self.filterChar = QCheckBox("Character tags", self)
self.filterChar.setChecked(self.optState.getSetting("fChar"))
self.filterWorld = QCheckBox("Location tags", self)
self.filterWorld.setChecked(self.optState.getSetting("fWorld"))
self.filterTime = QCheckBox("Timeline tags", self)
self.filterTime.setChecked(self.optState.getSetting("fTime"))
self.filterObject = QCheckBox("Object tags", self)
self.filterObject.setChecked(self.optState.getSetting("fObject"))
self.filterCustom = QCheckBox("Custom tags", self)
self.filterCustom.setChecked(self.optState.getSetting("fCustom"))
self.optFilterGrid.addWidget(self.filterPlot, 0, 1)
self.optFilterGrid.addWidget(self.filterChar, 1, 1)
self.optFilterGrid.addWidget(self.filterWorld, 2, 1)
self.optFilterGrid.addWidget(self.filterTime, 3, 1)
self.optFilterGrid.addWidget(self.filterObject, 4, 1)
self.optFilterGrid.addWidget(self.filterCustom, 5, 1)
self.optHide = QGroupBox("Filters", self)
self.optHideGrid = QGridLayout(self)
self.optHide.setLayout(self.optHideGrid)
self.hideUnused = QCheckBox("Hide unused", self)
self.hideUnused.setChecked(self.optState.getSetting("hUnused"))
self.optHideGrid.addWidget(self.hideUnused, 0, 1)
# Button Box
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
self.buttonBox.rejected.connect(self._doClose) self.buttonBox.rejected.connect(self._doClose)
@@ -75,14 +114,21 @@ class GuiTimeLineView(QDialog):
self.btnRefresh = QPushButton("Refresh Table") self.btnRefresh = QPushButton("Refresh Table")
self.btnRefresh.clicked.connect(self._buildNovelList) self.btnRefresh.clicked.connect(self._buildNovelList)
self.setLayout(self.outerBox)
self.outerBox.addWidget(self.mainTable)
self.outerBox.addLayout(self.bottomBox)
self.bottomBox.addWidget(self.btnRebuild) self.bottomBox.addWidget(self.btnRebuild)
self.bottomBox.addWidget(self.btnRefresh) self.bottomBox.addWidget(self.btnRefresh)
self.bottomBox.addStretch() self.bottomBox.addStretch()
self.bottomBox.addWidget(self.buttonBox) self.bottomBox.addWidget(self.buttonBox)
# Assemble
self.filterBox.addWidget(self.optFilter)
self.filterBox.addWidget(self.optHide)
self.filterBox.addStretch()
self.centreBox.addWidget(self.mainTable)
self.centreBox.addLayout(self.filterBox)
self.outerBox.addLayout(self.centreBox)
self.outerBox.addLayout(self.bottomBox)
self.setLayout(self.outerBox)
self._buildNovelList() self._buildNovelList()
self.buttonBox.setFocus() self.buttonBox.setFocus()
@@ -94,13 +140,28 @@ class GuiTimeLineView(QDialog):
def _buildNovelList(self): def _buildNovelList(self):
self.theIndex.buildNovelList()
self.numRows = len(self.theIndex.novelList)
self.numCols = len(self.theIndex.tagIndex.keys())
self.mainTable.clear() self.mainTable.clear()
self.theIndex.buildNovelList()
self.numRows = len(self.theIndex.novelList)
self.mainTable.setRowCount(self.numRows) self.mainTable.setRowCount(self.numRows)
self.mainTable.setColumnCount(self.numCols)
theFilters = {}
theFilters["exClass"] = []
theFilters["hUnused"] = self.hideUnused.isChecked()
if not self.filterPlot.isChecked():
theFilters["exClass"].append(nwItemClass.PLOT)
if not self.filterChar.isChecked():
theFilters["exClass"].append(nwItemClass.CHARACTER)
if not self.filterWorld.isChecked():
theFilters["exClass"].append(nwItemClass.WORLD)
if not self.filterTime.isChecked():
theFilters["exClass"].append(nwItemClass.TIMELINE)
if not self.filterObject.isChecked():
theFilters["exClass"].append(nwItemClass.OBJECT)
if not self.filterCustom.isChecked():
theFilters["exClass"].append(nwItemClass.CUSTOM)
for n in range(len(self.theIndex.novelList)): for n in range(len(self.theIndex.novelList)):
iDepth = self.theIndex.novelList[n][1] iDepth = self.theIndex.novelList[n][1]
@@ -108,14 +169,17 @@ class GuiTimeLineView(QDialog):
newItem = QTableWidgetItem("%s%s " % (" "*iDepth,iTitle)) newItem = QTableWidgetItem("%s%s " % (" "*iDepth,iTitle))
self.mainTable.setVerticalHeaderItem(n, newItem) self.mainTable.setVerticalHeaderItem(n, newItem)
theMap = self.theIndex.buildTagNovelMap(self.theIndex.tagIndex.keys()) theMap = self.theIndex.buildTagNovelMap(self.theIndex.tagIndex.keys(), theFilters)
nCol = 0 self.numCols = len(theMap.keys())
self.mainTable.setColumnCount(self.numCols)
nCol = 0
for theTag, theCols in theMap.items(): for theTag, theCols in theMap.items():
newItem = QTableWidgetItem(" %s " % theTag) newItem = QTableWidgetItem(" %s " % theTag)
self.mainTable.setHorizontalHeaderItem(nCol, newItem) self.mainTable.setHorizontalHeaderItem(nCol, newItem)
for n in range(len(theCols)): for n in range(len(theCols)):
if theCols[n] == 1: if theCols[n] == 1:
pxNew = QPixmap(10,10) pxNew = QPixmap(10,10)
pxNew.fill(QColor(0,120,0)) pxNew.fill(QColor(0,120,0))
lblNew = QLabel() lblNew = QLabel()
lblNew.setPixmap(pxNew) lblNew.setPixmap(pxNew)
@@ -123,7 +187,7 @@ class GuiTimeLineView(QDialog):
lblNew.setAttribute(Qt.WA_TranslucentBackground) lblNew.setAttribute(Qt.WA_TranslucentBackground)
self.mainTable.setCellWidget(n, nCol, lblNew) self.mainTable.setCellWidget(n, nCol, lblNew)
elif theCols[n] == 2: elif theCols[n] == 2:
pxNew = QPixmap(10,10) pxNew = QPixmap(10,10)
pxNew.fill(QColor(0,0,120)) pxNew.fill(QColor(0,0,120))
lblNew = QLabel() lblNew = QLabel()
lblNew.setPixmap(pxNew) lblNew.setPixmap(pxNew)
@@ -140,9 +204,23 @@ class GuiTimeLineView(QDialog):
winWidth = self.width() winWidth = self.width()
winHeight = self.height() winHeight = self.height()
fPlot = self.filterPlot.isChecked()
fChar = self.filterChar.isChecked()
fWorld = self.filterWorld.isChecked()
fTime = self.filterTime.isChecked()
fObject = self.filterObject.isChecked()
fCustom = self.filterCustom.isChecked()
hUnused = self.hideUnused.isChecked()
self.optState.setSetting("winWidth", winWidth) self.optState.setSetting("winWidth", winWidth)
self.optState.setSetting("winHeight",winHeight) self.optState.setSetting("winHeight",winHeight)
self.optState.setSetting("fPlot", fPlot)
self.optState.setSetting("fChar", fChar)
self.optState.setSetting("fWorld", fWorld)
self.optState.setSetting("fTime", fTime)
self.optState.setSetting("fObject", fObject)
self.optState.setSetting("fCustom", fCustom)
self.optState.setSetting("hUnused", hUnused)
self.optState.saveSettings() self.optState.saveSettings()
self.close() self.close()
@@ -158,9 +236,16 @@ class TimeLineLastState(OptLastState):
self.theState = { self.theState = {
"winWidth" : 700, "winWidth" : 700,
"winHeight" : 400, "winHeight" : 400,
"fPlot" : True,
"fChar" : True,
"fWorld" : True,
"fTime" : True,
"fObject" : True,
"fCustom" : True,
"hUnused" : True,
} }
self.stringOpt = () self.stringOpt = ()
self.boolOpt = () self.boolOpt = ("fPlot","fChar","fWorld","fTime","fObject","fCustom","hUnused")
self.intOpt = ("winWidth","winHeight") self.intOpt = ("winWidth","winHeight")
return return
+15 -2
View File
@@ -319,18 +319,24 @@ class NWIndex():
return True return True
def buildTagNovelMap(self, theTags): def buildTagNovelMap(self, theTags, theFilters=None):
tagMap = {} tagMap = {}
tagClass = {} tagClass = {}
exClass = []
if theFilters is not None:
if "exClass" in theFilters.keys():
exClass = theFilters["exClass"]
for theTag in theTags: for theTag in theTags:
tagMap[theTag] = [0]*len(self.novelOrder)
try: try:
tagClass[theTag] = nwItemClass[self.tagIndex[theTag][2]] tagClass[theTag] = nwItemClass[self.tagIndex[theTag][2]]
except: except:
logger.error("Could not map '%s' to nwItemClass" % self.tagIndex[theTag][2]) logger.error("Could not map '%s' to nwItemClass" % self.tagIndex[theTag][2])
tagClass[theTag] = None tagClass[theTag] = None
if tagClass[theTag] not in exClass:
tagMap[theTag] = [0]*len(self.novelOrder)
for tHandle in self.refIndex: for tHandle in self.refIndex:
for nLine, tKey, tTag, nTitle in self.refIndex[tHandle]: for nLine, tKey, tTag, nTitle in self.refIndex[tHandle]:
@@ -342,6 +348,13 @@ class NWIndex():
except: except:
logger.error("Could not find '%s:%d' in novelOrder" % (tHandle, nTitle)) logger.error("Could not find '%s:%d' in novelOrder" % (tHandle, nTitle))
if theFilters["hUnused"]:
tagMapFiltered = {}
for theTag in tagMap.keys():
if sum(tagMap[theTag]) > 0:
tagMapFiltered[theTag] = tagMap[theTag]
return tagMapFiltered
return tagMap return tagMap
# END Class NWIndex # END Class NWIndex
@@ -3,7 +3,7 @@
% Begin Meta % Begin Meta
@pov: Jane @pov: Jane
@char: John @char: John
@location: Earth @location: Space
% End Meta % End Meta
Some text here would look good as well, and maybe some "dialogue"? Some text here would look good as well, and maybe some "dialogue"?
@@ -1,7 +1,7 @@
### Another Scene ### Another Scene
@pov: John @pov: John
@location: Space @location: Earth
This is the second scene in out story. We have no idea whats going on, so were just going to ramble on until we have a few lines of text so that the editor has something to work with. This is the second scene in out story. We have no idea whats going on, so were just going to ramble on until we have a few lines of text so that the editor has something to work with.
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.2.3" fileVersion="1.0" timeStamp="2019-10-19 13:37:25"> <novelWriterXML appVersion="0.3.1" fileVersion="1.0" timeStamp="2019-10-21 20:54:53">
<project> <project>
<name>Sample Project</name> <name>Sample Project</name>
<title>Sample Project</title> <title>Sample Project</title>
@@ -82,7 +82,7 @@
<charCount>713</charCount> <charCount>713</charCount>
<wordCount>132</wordCount> <wordCount>132</wordCount>
<paraCount>6</paraCount> <paraCount>6</paraCount>
<cursorPos>85</cursorPos> <cursorPos>72</cursorPos>
</item> </item>
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a"> <item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
<name>Another Scene</name> <name>Another Scene</name>