Added filters to timeline view GUI
This commit is contained in:
+100
-15
@@ -17,12 +17,13 @@ from os import path
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QIcon, QColor, QPixmap
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem,
|
||||
QDialogButtonBox, QLabel, QPushButton, QHeaderView
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QDialogButtonBox, QLabel,
|
||||
QPushButton, QHeaderView, QGridLayout, QGroupBox, QCheckBox
|
||||
)
|
||||
|
||||
from nw.tools.optlaststate import OptLastState
|
||||
from nw.constants import nwFiles
|
||||
from nw.enum import nwItemClass
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -45,6 +46,8 @@ class GuiTimeLineView(QDialog):
|
||||
self.numCols = 0
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.filterBox = QVBoxLayout()
|
||||
self.centreBox = QHBoxLayout()
|
||||
self.bottomBox = QHBoxLayout()
|
||||
|
||||
self.setWindowTitle("Timeline View")
|
||||
@@ -55,6 +58,7 @@ class GuiTimeLineView(QDialog):
|
||||
self.optState.getSetting("winHeight")
|
||||
)
|
||||
|
||||
# TimeLine Table
|
||||
self.mainTable = QTableWidget()
|
||||
self.mainTable.setGridStyle(Qt.NoPen)
|
||||
|
||||
@@ -66,6 +70,41 @@ class GuiTimeLineView(QDialog):
|
||||
self.vHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
|
||||
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.rejected.connect(self._doClose)
|
||||
|
||||
@@ -75,14 +114,21 @@ class GuiTimeLineView(QDialog):
|
||||
self.btnRefresh = QPushButton("Refresh Table")
|
||||
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.btnRefresh)
|
||||
self.bottomBox.addStretch()
|
||||
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.buttonBox.setFocus()
|
||||
|
||||
@@ -94,13 +140,28 @@ class GuiTimeLineView(QDialog):
|
||||
|
||||
def _buildNovelList(self):
|
||||
|
||||
self.theIndex.buildNovelList()
|
||||
self.numRows = len(self.theIndex.novelList)
|
||||
self.numCols = len(self.theIndex.tagIndex.keys())
|
||||
|
||||
self.mainTable.clear()
|
||||
self.theIndex.buildNovelList()
|
||||
|
||||
self.numRows = len(self.theIndex.novelList)
|
||||
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)):
|
||||
iDepth = self.theIndex.novelList[n][1]
|
||||
@@ -108,14 +169,17 @@ class GuiTimeLineView(QDialog):
|
||||
newItem = QTableWidgetItem("%s%s " % (" "*iDepth,iTitle))
|
||||
self.mainTable.setVerticalHeaderItem(n, newItem)
|
||||
|
||||
theMap = self.theIndex.buildTagNovelMap(self.theIndex.tagIndex.keys())
|
||||
nCol = 0
|
||||
theMap = self.theIndex.buildTagNovelMap(self.theIndex.tagIndex.keys(), theFilters)
|
||||
self.numCols = len(theMap.keys())
|
||||
self.mainTable.setColumnCount(self.numCols)
|
||||
|
||||
nCol = 0
|
||||
for theTag, theCols in theMap.items():
|
||||
newItem = QTableWidgetItem(" %s " % theTag)
|
||||
self.mainTable.setHorizontalHeaderItem(nCol, newItem)
|
||||
for n in range(len(theCols)):
|
||||
if theCols[n] == 1:
|
||||
pxNew = QPixmap(10,10)
|
||||
pxNew = QPixmap(10,10)
|
||||
pxNew.fill(QColor(0,120,0))
|
||||
lblNew = QLabel()
|
||||
lblNew.setPixmap(pxNew)
|
||||
@@ -123,7 +187,7 @@ class GuiTimeLineView(QDialog):
|
||||
lblNew.setAttribute(Qt.WA_TranslucentBackground)
|
||||
self.mainTable.setCellWidget(n, nCol, lblNew)
|
||||
elif theCols[n] == 2:
|
||||
pxNew = QPixmap(10,10)
|
||||
pxNew = QPixmap(10,10)
|
||||
pxNew.fill(QColor(0,0,120))
|
||||
lblNew = QLabel()
|
||||
lblNew.setPixmap(pxNew)
|
||||
@@ -140,9 +204,23 @@ class GuiTimeLineView(QDialog):
|
||||
|
||||
winWidth = self.width()
|
||||
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("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.close()
|
||||
@@ -158,9 +236,16 @@ class TimeLineLastState(OptLastState):
|
||||
self.theState = {
|
||||
"winWidth" : 700,
|
||||
"winHeight" : 400,
|
||||
"fPlot" : True,
|
||||
"fChar" : True,
|
||||
"fWorld" : True,
|
||||
"fTime" : True,
|
||||
"fObject" : True,
|
||||
"fCustom" : True,
|
||||
"hUnused" : True,
|
||||
}
|
||||
self.stringOpt = ()
|
||||
self.boolOpt = ()
|
||||
self.boolOpt = ("fPlot","fChar","fWorld","fTime","fObject","fCustom","hUnused")
|
||||
self.intOpt = ("winWidth","winHeight")
|
||||
return
|
||||
|
||||
|
||||
+15
-2
@@ -319,18 +319,24 @@ class NWIndex():
|
||||
|
||||
return True
|
||||
|
||||
def buildTagNovelMap(self, theTags):
|
||||
def buildTagNovelMap(self, theTags, theFilters=None):
|
||||
|
||||
tagMap = {}
|
||||
tagClass = {}
|
||||
exClass = []
|
||||
|
||||
if theFilters is not None:
|
||||
if "exClass" in theFilters.keys():
|
||||
exClass = theFilters["exClass"]
|
||||
|
||||
for theTag in theTags:
|
||||
tagMap[theTag] = [0]*len(self.novelOrder)
|
||||
try:
|
||||
tagClass[theTag] = nwItemClass[self.tagIndex[theTag][2]]
|
||||
except:
|
||||
logger.error("Could not map '%s' to nwItemClass" % self.tagIndex[theTag][2])
|
||||
tagClass[theTag] = None
|
||||
if tagClass[theTag] not in exClass:
|
||||
tagMap[theTag] = [0]*len(self.novelOrder)
|
||||
|
||||
for tHandle in self.refIndex:
|
||||
for nLine, tKey, tTag, nTitle in self.refIndex[tHandle]:
|
||||
@@ -342,6 +348,13 @@ class NWIndex():
|
||||
except:
|
||||
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
|
||||
|
||||
# END Class NWIndex
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
% Begin Meta
|
||||
@pov: Jane
|
||||
@char: John
|
||||
@location: Earth
|
||||
@location: Space
|
||||
% End Meta
|
||||
|
||||
Some text here would look good as well, and maybe some "dialogue"?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
### Another Scene
|
||||
|
||||
@pov: John
|
||||
@location: Space
|
||||
@location: Earth
|
||||
|
||||
This is the second scene in out story. We have no idea what’s going on, so we’re just going to ramble on until we have a few lines of text so that the editor has something to work with.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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>
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
@@ -82,7 +82,7 @@
|
||||
<charCount>713</charCount>
|
||||
<wordCount>132</wordCount>
|
||||
<paraCount>6</paraCount>
|
||||
<cursorPos>85</cursorPos>
|
||||
<cursorPos>72</cursorPos>
|
||||
</item>
|
||||
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
|
||||
<name>Another Scene</name>
|
||||
|
||||
Reference in New Issue
Block a user