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.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
@@ -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 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.
|
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'?>
|
<?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>
|
||||||
|
|||||||
Reference in New Issue
Block a user