Merge branch 'feature/PlotViewer' into develop

This commit is contained in:
Olivier Keshavjee 2016-02-28 13:55:45 +01:00
commit 1f5445b20d
10 changed files with 708 additions and 127 deletions

View file

@ -322,6 +322,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.mainEditor.setFolderView(settings.folderView)
self.mainEditor.updateFolderViewButtons(settings.folderView)
self.tabMain.setCurrentIndex(settings.lastTab)
# We force to emit even if it opens on the current tab
self.tabMain.currentChanged.emit(settings.lastTab)
self.mainEditor.updateCorkBackground()
# Set autosave
@ -406,6 +408,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if sttgns.contains("revisionsState"):
state = [False if v == "false" else True for v in sttgns.value("revisionsState")]
self.redacMetadata.revisions.restoreState(state)
if sttgns.contains("splitterRedacH"):
self.splitterRedacH.restoreState(sttgns.value("splitterRedacH"))
if sttgns.contains("splitterRedacV"):
self.splitterRedacV.restoreState(sttgns.value("splitterRedacV"))
if sttgns.contains("toolbar"):
# self.toolbar is not initialized yet, so we just store balue
self._toolbarState = sttgns.value("toolbar")
else:
self._toolbarState = ""
def closeEvent(self, event):
# Save State and geometry and other things
@ -413,8 +425,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
sttgns.setValue("geometry", self.saveGeometry())
sttgns.setValue("windowState", self.saveState())
sttgns.setValue("metadataState", self.redacMetadata.saveState())
sttgns.setValue("metadataState", self.redacMetadata.saveState())
sttgns.setValue("revisionsState", self.redacMetadata.revisions.saveState())
sttgns.setValue("splitterRedacH", self.splitterRedacH.saveState())
sttgns.setValue("splitterRedacV", self.splitterRedacV.saveState())
sttgns.setValue("toolbar", self.toolbar.saveState())
# Specific settings to save before quitting
settings.lastTab = self.tabMain.currentIndex()
@ -699,6 +713,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.treeOutlineOutline.setModel(self.mdlOutline)
# self.redacEditor.setModel(self.mdlOutline)
self.storylineView.setModels(self.mdlOutline, self.mdlPersos, self.mdlPlots)
self.treeOutlineOutline.selectionModel().selectionChanged.connect(lambda:
self.outlineItemEditor.selectionChanged(
@ -799,6 +814,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.toolbar.addCustomWidget(self.tr("Book summary"), self.grpPlotSummary, self.TabPlots)
self.toolbar.addCustomWidget(self.tr("Project tree"), self.treeRedacWidget, self.TabRedac)
self.toolbar.addCustomWidget(self.tr("Metadata"), self.redacMetadata, self.TabRedac)
self.toolbar.addCustomWidget(self.tr("Story line"), self.storylineView, self.TabRedac)
if self._toolbarState:
self.toolbar.restoreState(self._toolbarState)
# Custom "tab" bar on the left
self.lstTabs.setIconSize(QSize(48, 48))
@ -838,9 +856,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.splitterOutlineV.setStretchFactor(0, 75)
self.splitterOutlineV.setStretchFactor(1, 25)
self.splitterRedac.setStretchFactor(0, 30)
self.splitterRedac.setStretchFactor(1, 40)
self.splitterRedac.setStretchFactor(2, 30)
self.splitterRedacV.setStretchFactor(0, 75)
self.splitterRedacV.setStretchFactor(1, 25)
self.splitterRedacH.setStretchFactor(0, 30)
self.splitterRedacH.setStretchFactor(1, 40)
self.splitterRedacH.setStretchFactor(2, 30)
# QFormLayout stretch
for w in [self.txtWorldDescription, self.txtWorldPassion, self.txtWorldConflict]:

View file

@ -836,11 +836,20 @@ class outlineItem():
return lst
def findItemsContaining(self, text, columns, mainWindow, caseSensitive=False):
def findItemsContaining(self, text, columns, mainWindow=mainWindow(), caseSensitive=False, recursive=True):
"""Returns a list if IDs of all subitems
containing ``text`` in columns ``columns``
(being a list of int).
"""
lst = self.itemContains(text, columns, mainWindow, caseSensitive)
if recursive:
for c in self.children():
lst.extend(c.findItemsContaining(text, columns, mainWindow, caseSensitive))
return lst
def itemContains(self, text, columns, mainWindow=mainWindow(), caseSensitive=False):
lst = []
text = text.lower() if not caseSensitive else text
for c in columns:
@ -863,9 +872,6 @@ class outlineItem():
if not self.ID() in lst:
lst.append(self.ID())
for c in self.children():
lst.extend(c.findItemsContaining(text, columns, mainWindow, caseSensitive))
return lst
###############################################################################

View file

@ -21,30 +21,47 @@ RegEx = r"{(\w):(\d+):?.*?}"
RegExNonCapturing = r"{\w:\d+:?.*?}"
# The basic format of the references
EmptyRef = "{{{}:{}:{}}}"
EmptyRefSearchable = "{{{}:{}:"
PersoLetter = "C"
TextLetter = "T"
PlotLetter = "P"
WorldLetter = "W"
def plotReference(ID):
"""Takes the ID of a plot and returns a reference for that plot."""
return EmptyRef.format(PlotLetter, ID, "")
def plotReference(ID, searchable=False):
"""Takes the ID of a plot and returns a reference for that plot.
@searchable: returns a stripped version that allows simple text search."""
if not searchable:
return EmptyRef.format(PlotLetter, ID, "")
else:
return EmptyRefSearchable.format(PlotLetter, ID, "")
def persoReference(ID):
"""Takes the ID of a character and returns a reference for that character."""
return EmptyRef.format(PersoLetter, ID, "")
def persoReference(ID, searchable=False):
"""Takes the ID of a character and returns a reference for that character.
@searchable: returns a stripped version that allows simple text search."""
if not searchable:
return EmptyRef.format(PersoLetter, ID, "")
else:
return EmptyRefSearchable.format(PersoLetter, ID, "")
def textReference(ID):
"""Takes the ID of an outline item and returns a reference for that item."""
return EmptyRef.format(TextLetter, ID, "")
def textReference(ID, searchable=False):
"""Takes the ID of an outline item and returns a reference for that item.
@searchable: returns a stripped version that allows simple text search."""
if not searchable:
return EmptyRef.format(TextLetter, ID, "")
else:
return EmptyRefSearchable.format(TextLetter, ID, "")
def worldReference(ID):
"""Takes the ID of a world item and returns a reference for that item."""
return EmptyRef.format(WorldLetter, ID, "")
def worldReference(ID, searchable=False):
"""Takes the ID of a world item and returns a reference for that item.
@searchable: returns a stripped version that allows simple text search."""
if not searchable:
return EmptyRef.format(WorldLetter, ID, "")
else:
return EmptyRefSearchable.format(WorldLetter, ID, "")
###############################################################################
@ -375,7 +392,10 @@ def tooltip(ref):
item = idx.internalPointer()
tt = qApp.translate("references", "Text: <b>{}</b>").format(item.title())
if item.isFolder():
tt = qApp.translate("references", "Folder: <b>{}</b>").format(item.title())
else:
tt = qApp.translate("references", "Text: <b>{}</b>").format(item.title())
tt += "<br><i>{}</i>".format(item.path())
return tt
@ -451,11 +471,32 @@ def linkifyAllRefs(text):
return re.sub(RegEx, lambda m: refToLink(m.group(0)), text)
def findReferencesTo(ref, parent=None, recursive=True):
"""List of text items containing references ref, and returns IDs.
Starts from item parent. If None, starts from root."""
oM = mainWindow().mdlOutline
if parent == None:
parent = oM.rootItem
# Removes everything after the second ':': '{L:ID:random text}' → '{L:ID:'
ref = ref[:ref.index(":", ref.index(":") + 1)+1]
# Bare form '{L:ID}'
ref2 = ref[:-1] + "}"
# Since it's a simple search (no regex), we search for both.
lst = parent.findItemsContaining(ref, [Outline.notes.value], recursive=recursive)
lst += parent.findItemsContaining(ref2, [Outline.notes.value], recursive=recursive)
return lst
def listReferences(ref, title=qApp.translate("references", "Referenced in:")):
oM = mainWindow().mdlOutline
listRefs = ""
ref = ref[:ref.index(":", ref.index(":") + 1)]
lst = oM.findItemsContaining(ref, [Outline.notes.value])
lst = findReferencesTo(ref)
for t in lst:
idx = oM.getIndexByID(t)
listRefs += "<li><a href='{link}'>{text}</a></li>".format(

View file

@ -69,6 +69,7 @@ class collapsibleDockWidgets(QToolBar):
# widget.installEventFilter(self)
b = verticalButton(self)
b.setDefaultAction(a)
#b.setChecked(widget.isVisible())
a2 = self.addWidget(b)
self.otherWidgets.append((b, a2, widget, group))
@ -87,6 +88,22 @@ class collapsibleDockWidgets(QToolBar):
else:
action.setVisible(True)
def saveState(self):
# We just need to save states of the custom widgets.
state = []
for btn, act, w, grp in self.otherWidgets:
state.append(
(grp, btn.text(), btn.isChecked())
)
return state
def restoreState(self, state):
for group, title, status in state:
for btn, act, widget, grp in self.otherWidgets:
if group == grp and title == btn.text():
btn.setChecked(status)
widget.setVisible(status)
class verticalButton(QToolButton):
def __init__(self, parent):

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/mainWindow.ui'
#
# Created: Mon Feb 8 11:20:10 2016
# Created: Sun Feb 28 13:22:17 2016
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
@ -869,10 +869,15 @@ class Ui_MainWindow(object):
self.verticalLayout_15 = QtWidgets.QVBoxLayout(self.lytTabRedac)
self.verticalLayout_15.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_15.setObjectName("verticalLayout_15")
self.splitterRedac = QtWidgets.QSplitter(self.lytTabRedac)
self.splitterRedac.setOrientation(QtCore.Qt.Horizontal)
self.splitterRedac.setObjectName("splitterRedac")
self.treeRedacWidget = QtWidgets.QWidget(self.splitterRedac)
self.splitterRedacV = QtWidgets.QSplitter(self.lytTabRedac)
self.splitterRedacV.setOrientation(QtCore.Qt.Vertical)
self.splitterRedacV.setChildrenCollapsible(False)
self.splitterRedacV.setObjectName("splitterRedacV")
self.splitterRedacH = QtWidgets.QSplitter(self.splitterRedacV)
self.splitterRedacH.setOrientation(QtCore.Qt.Horizontal)
self.splitterRedacH.setChildrenCollapsible(False)
self.splitterRedacH.setObjectName("splitterRedacH")
self.treeRedacWidget = QtWidgets.QWidget(self.splitterRedacH)
self.treeRedacWidget.setObjectName("treeRedacWidget")
self.verticalLayout_30 = QtWidgets.QVBoxLayout(self.treeRedacWidget)
self.verticalLayout_30.setContentsMargins(0, 0, 0, 0)
@ -905,11 +910,13 @@ class Ui_MainWindow(object):
spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_31.addItem(spacerItem16)
self.verticalLayout_30.addLayout(self.horizontalLayout_31)
self.mainEditor = mainEditor(self.splitterRedac)
self.mainEditor = mainEditor(self.splitterRedacH)
self.mainEditor.setObjectName("mainEditor")
self.redacMetadata = metadataView(self.splitterRedac)
self.redacMetadata = metadataView(self.splitterRedacH)
self.redacMetadata.setObjectName("redacMetadata")
self.verticalLayout_15.addWidget(self.splitterRedac)
self.storylineView = storylineView(self.splitterRedacV)
self.storylineView.setObjectName("storylineView")
self.verticalLayout_15.addWidget(self.splitterRedacV)
self.tabMain.addTab(self.lytTabRedac, "")
self.lytTabDebug = QtWidgets.QWidget()
self.lytTabDebug.setObjectName("lytTabDebug")
@ -1159,7 +1166,7 @@ class Ui_MainWindow(object):
self.retranslateUi(MainWindow)
self.stack.setCurrentIndex(1)
self.tabMain.setCurrentIndex(4)
self.tabMain.setCurrentIndex(6)
self.tabSummary.setCurrentIndex(0)
self.tabPersos.setCurrentIndex(0)
self.tabPlot.setCurrentIndex(0)
@ -1294,19 +1301,20 @@ class Ui_MainWindow(object):
self.actCloseProject.setText(_translate("MainWindow", "&Close project"))
self.actCompile.setText(_translate("MainWindow", "Co&mpile"))
self.actCompile.setShortcut(_translate("MainWindow", "F6"))
self.actToolFrequency.setText(_translate("MainWindow", "Frequency Analyzer"))
self.actToolFrequency.setText(_translate("MainWindow", "&Frequency Analyzer"))
from manuskript.ui.welcome import welcome
from manuskript.ui.views.metadataView import metadataView
from manuskript.ui.views.basicItemView import basicItemView
from manuskript.ui.editors.mainEditor import mainEditor
from manuskript.ui.views.plotTreeView import plotTreeView
from manuskript.ui.sldImportance import sldImportance
from manuskript.ui.views.textEditCompleter import textEditCompleter
from manuskript.ui.views.treeView import treeView
from manuskript.ui.views.persoTreeView import persoTreeView
from manuskript.ui.search import search
from manuskript.ui.cheatSheet import cheatSheet
from manuskript.ui.views.outlineView import outlineView
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.cheatSheet import cheatSheet
from manuskript.ui.editors.mainEditor import mainEditor
from manuskript.ui.views.outlineView import outlineView
from manuskript.ui.views.treeView import treeView
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.storylineView import storylineView
from manuskript.ui.views.persoTreeView import persoTreeView
from manuskript.ui.views.plotTreeView import plotTreeView
from manuskript.ui.search import search
from manuskript.ui.views.basicItemView import basicItemView
from manuskript.ui.welcome import welcome
from manuskript.ui.views.textEditCompleter import textEditCompleter
from manuskript.ui.sldImportance import sldImportance
from manuskript.ui.views.metadataView import metadataView

View file

@ -124,7 +124,7 @@
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>4</number>
<number>6</number>
</property>
<property name="documentMode">
<bool>true</bool>
@ -1770,88 +1770,100 @@
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitterRedac">
<widget class="QSplitter" name="splitterRedacV">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="treeRedacWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_30">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="treeView" name="treeRedacOutline">
<property name="editTriggers">
<set>QAbstractItemView::EditKeyPressed</set>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_31">
<item>
<widget class="QPushButton" name="btnRedacAddFolder">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="folder-new">
<normaloff>../../../../../../../.designer/backup</normaloff>../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRedacAddText">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="document-new">
<normaloff>../../../../../../../.designer/backup</normaloff>../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRedacRemoveItem">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="list-remove">
<normaloff>../../../../../../../.designer/backup</normaloff>../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QSplitter" name="splitterRedacH">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QWidget" name="treeRedacWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_30">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="treeView" name="treeRedacOutline">
<property name="editTriggers">
<set>QAbstractItemView::EditKeyPressed</set>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_31">
<item>
<widget class="QPushButton" name="btnRedacAddFolder">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="folder-new">
<normaloff>../../../../../../../.designer/backup</normaloff>../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRedacAddText">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="document-new">
<normaloff>../../../../../../../.designer/backup</normaloff>../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRedacRemoveItem">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="list-remove">
<normaloff>../../../../../../../.designer/backup</normaloff>../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="mainEditor" name="mainEditor" native="true"/>
<widget class="metadataView" name="redacMetadata" native="true"/>
</widget>
<widget class="mainEditor" name="mainEditor" native="true"/>
<widget class="metadataView" name="redacMetadata" native="true"/>
<widget class="storylineView" name="storylineView" native="true"/>
</widget>
</item>
</layout>
@ -2323,7 +2335,7 @@ QListView::item:hover {
</action>
<action name="actToolFrequency">
<property name="text">
<string>Frequency Analyzer</string>
<string>&amp;Frequency Analyzer</string>
</property>
</action>
</widget>
@ -2405,6 +2417,12 @@ QListView::item:hover {
<extends>QTextEdit</extends>
<header>manuskript.ui.views.textEditCompleter.h</header>
</customwidget>
<customwidget>
<class>storylineView</class>
<extends>QWidget</extends>
<header>manuskript.ui.views.storylineView.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>

View file

@ -0,0 +1,265 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
from PyQt5.QtCore import Qt, QTimer, QRectF
from PyQt5.QtGui import QBrush, QPen, QFontMetrics, QFontMetricsF
from PyQt5.QtWidgets import QWidget, QGraphicsScene, QGraphicsSimpleTextItem, QMenu, QAction, QGraphicsRectItem, \
QGraphicsLineItem, QGraphicsEllipseItem
from manuskript.enums import Outline
from manuskript.functions import randomColor
from manuskript.models import references
from manuskript.ui.views.storylineView_ui import Ui_storylineView
class storylineView(QWidget, Ui_storylineView):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self._mdlPlots = None
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
self.reloadTimer = QTimer()
self.reloadTimer.timeout.connect(self.refresh)
self.reloadTimer.setSingleShot(True)
self.reloadTimer.setInterval(500)
self.btnRefresh.clicked.connect(self.refresh)
self.sldTxtSize.sliderMoved.connect(self.reloadTimer.start)
self.generateMenu()
def generateMenu(self):
m = QMenu()
for i in [
self.tr("Show Plots"),
self.tr("Show Characters"),
self.tr("Show Objects"),
]:
a = QAction(i, m)
a.setCheckable(True)
a.setEnabled(False)
m.addAction(a)
self.btnSettings.setMenu(m)
def setModels(self, mdlOutline, mdlPersos, mdlPlots):
self._mdlPlots = mdlPlots
# self._mdlPlots.dataChanged.connect(self.refresh)
# self._mdlPlots.rowsInserted.connect(self.refresh)
self._mdlOutline = mdlOutline
self._mdlOutline.dataChanged.connect(self.reloadTimer.start)
self._mdlPersos = mdlPersos
self._mdlPersos.dataChanged.connect(self.reloadTimer.start)
def refresh(self):
if not self._mdlPlots or not self._mdlOutline or not self._mdlPersos:
pass
LINE_HEIGHT = 18
SPACING = 3
TEXT_WIDTH = self.sldTxtSize.value()
CIRCLE_WIDTH = 10
LEVEL_HEIGHT = 12
s = self.scene
s.clear()
# Get Max Level (max depth)
root = self._mdlOutline.rootItem
def maxLevel(item, level=0, max=0):
if level > max:
max = level
for c in item.children():
m = maxLevel(c, level + 1)
if m > max:
max = m
return max
MAX_LEVEL = maxLevel(root)
# Generate left entries
# (As of now, plot only)
plotsID = self._mdlPlots.getPlotsByImportance()
trackedItems = []
fm = QFontMetrics(s.font())
max_name = 0
for importance in plotsID:
for ID in importance:
name = self._mdlPlots.getPlotNameByID(ID)
ref = references.plotReference(ID, searchable=True)
trackedItems.append((ID, ref, name))
max_name = max(fm.width(name), max_name)
ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING )
TITLE_WIDTH = max_name + 2 * SPACING
# Add Folders and Texts
outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT)
s.addItem(outline)
outline.setPos(TITLE_WIDTH + SPACING, 0)
refCircles = [] # a list of all references, to be added later on the lines
# A Function to add a rect with centered elided text
def addRectText(x, w, parent, text="", level=0, tooltip=""):
deltaH = LEVEL_HEIGHT if level else 0
r = OutlineRect(0, 0, w, parent.rect().height()-deltaH, parent, title=text)
r.setPos(x, deltaH)
txt = QGraphicsSimpleTextItem(text, r)
f = txt.font()
f.setPointSize(8)
fm = QFontMetricsF(f)
elidedText = fm.elidedText(text, Qt.ElideMiddle, w)
txt.setFont(f)
txt.setText(elidedText)
txt.setPos(r.boundingRect().center() - txt.boundingRect().center())
txt.setY(0)
return r
# A function to returns an item's width, by counting its children
def itemWidth(item):
if item.isFolder():
r = 0
for c in item.children():
r += itemWidth(c)
return r or TEXT_WIDTH
else:
return TEXT_WIDTH
def listItems(item, rect, level=0):
delta = 0
for child in item.children():
w = itemWidth(child)
if child.isFolder():
parent = addRectText(delta, w, rect, child.title(), level, tooltip=child.title())
parent.setToolTip(references.tooltip(references.textReference(child.ID())))
listItems(child, parent, level + 1)
else:
rectChild = addRectText(delta, TEXT_WIDTH, rect, "", level, tooltip=child.title())
rectChild.setToolTip(references.tooltip(references.textReference(child.ID())))
# Find tracked references in that scene (or parent folders)
for ID, ref, name in trackedItems:
result = []
c = child
while c:
result += references.findReferencesTo(ref, c, recursive=False)
c = c.parent()
if result:
ref2 = result[0]
# Create a RefCircle with the reference
c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2)
# Store it, with the position of that item, to display it on the line later on
refCircles.append((ref, c, rect.mapToItem(outline, rectChild.pos())))
delta += w
listItems(root, outline)
OUTLINE_WIDTH = itemWidth(root)
# Add Plots
i = 0
itemsRect = s.addRect(0, 0, 0, 0)
itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING)
for ID, ref, name in trackedItems:
color = randomColor()
# Rect
r = QGraphicsRectItem(0, 0, TITLE_WIDTH, LINE_HEIGHT, itemsRect)
r.setPen(QPen(Qt.NoPen))
r.setBrush(QBrush(color))
r.setPos(0, i * LINE_HEIGHT + i * SPACING)
i += 1
# Text
txt = QGraphicsSimpleTextItem(name, r)
txt.setPos(r.boundingRect().center() - txt.boundingRect().center())
# Line
line = PlotLine(0, 0,
OUTLINE_WIDTH + SPACING, 0)
line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y())
s.addItem(line)
line.setPen(QPen(color, 5))
line.setToolTip(self.tr("Plot: ") + name)
# We add the circles / references to text, on the line
for ref2, circle, pos in refCircles:
if ref2 == ref:
circle.setParentItem(line)
circle.setPos(pos.x(), 0)
# self.view.fitInView(0, 0, TOTAL_WIDTH, i * LINE_HEIGHT, Qt.KeepAspectRatioByExpanding) # KeepAspectRatio
self.view.setSceneRect(0, 0, 0, 0)
class OutlineRect(QGraphicsRectItem):
def __init__(self, x, y, w, h, parent=None, title=None):
QGraphicsRectItem.__init__(self, x, y, w, h, parent)
self.setBrush(Qt.white)
self.setAcceptHoverEvents(True)
self._title = title
def hoverEnterEvent(self, event):
self.setBrush(Qt.lightGray)
def hoverLeaveEvent(self, event):
self.setBrush(Qt.white)
class RefCircle(QGraphicsEllipseItem):
def __init__(self, x, y, diameter, parent=None, ID=None):
QGraphicsEllipseItem.__init__(self, x, y, diameter, diameter, parent)
self.setBrush(Qt.white)
self._ref = references.textReference(ID)
self.setToolTip(references.tooltip(self._ref))
self.setPen(QPen(Qt.black, 2))
self.setAcceptHoverEvents(True)
def multiplyDiameter(self, factor):
r1 = self.rect()
r2 = QRectF(0, 0, r1.width() * factor, r1.height() * factor)
self.setRect(r2)
self.setPos(self.pos() + r1.center() - r2.center())
def mouseDoubleClickEvent(self, event):
references.open(self._ref)
def hoverEnterEvent(self, event):
self.multiplyDiameter(2)
def hoverLeaveEvent(self, event):
self.multiplyDiameter(.5)
class PlotLine(QGraphicsLineItem):
def __init__(self, x1, y1, x2, y2, parent=None):
QGraphicsLineItem.__init__(self, x1, y1, x2, y2, parent)
self.setAcceptHoverEvents(True)
def hoverEnterEvent(self, QGraphicsSceneHoverEvent):
p = self.pen()
p.setWidth(10)
self.setPen(p)
def hoverLeaveEvent(self, QGraphicsSceneHoverEvent):
p = self.pen()
p.setWidth(5)
self.setPen(p)

View file

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'manuskript/ui/views/storylineView_ui.ui'
#
# Created: Sun Feb 28 09:13:29 2016
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_storylineView(object):
def setupUi(self, storylineView):
storylineView.setObjectName("storylineView")
storylineView.resize(1040, 130)
self.horizontalLayout = QtWidgets.QHBoxLayout(storylineView)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout")
self.btnZoomIn = QtWidgets.QPushButton(storylineView)
self.btnZoomIn.setMaximumSize(QtCore.QSize(32, 32))
self.btnZoomIn.setFlat(True)
self.btnZoomIn.setObjectName("btnZoomIn")
self.verticalLayout.addWidget(self.btnZoomIn)
self.btnZoomOut = QtWidgets.QPushButton(storylineView)
self.btnZoomOut.setMaximumSize(QtCore.QSize(32, 32))
self.btnZoomOut.setFlat(True)
self.btnZoomOut.setObjectName("btnZoomOut")
self.verticalLayout.addWidget(self.btnZoomOut)
self.btnRefresh = QtWidgets.QPushButton(storylineView)
self.btnRefresh.setMaximumSize(QtCore.QSize(32, 32))
self.btnRefresh.setText("")
icon = QtGui.QIcon.fromTheme("view-refresh")
self.btnRefresh.setIcon(icon)
self.btnRefresh.setFlat(True)
self.btnRefresh.setObjectName("btnRefresh")
self.verticalLayout.addWidget(self.btnRefresh)
self.sldTxtSize = QtWidgets.QSlider(storylineView)
self.sldTxtSize.setMinimum(1)
self.sldTxtSize.setMaximum(100)
self.sldTxtSize.setProperty("value", 20)
self.sldTxtSize.setOrientation(QtCore.Qt.Vertical)
self.sldTxtSize.setObjectName("sldTxtSize")
self.verticalLayout.addWidget(self.sldTxtSize)
self.btnSettings = QtWidgets.QPushButton(storylineView)
self.btnSettings.setMaximumSize(QtCore.QSize(32, 32))
self.btnSettings.setText("")
icon = QtGui.QIcon.fromTheme("preferences-system")
self.btnSettings.setIcon(icon)
self.btnSettings.setFlat(True)
self.btnSettings.setObjectName("btnSettings")
self.verticalLayout.addWidget(self.btnSettings)
self.horizontalLayout.addLayout(self.verticalLayout)
self.view = QtWidgets.QGraphicsView(storylineView)
self.view.setObjectName("view")
self.horizontalLayout.addWidget(self.view)
self.retranslateUi(storylineView)
QtCore.QMetaObject.connectSlotsByName(storylineView)
def retranslateUi(self, storylineView):
_translate = QtCore.QCoreApplication.translate
storylineView.setWindowTitle(_translate("storylineView", "Form"))
self.btnZoomIn.setText(_translate("storylineView", "+"))
self.btnZoomOut.setText(_translate("storylineView", "-"))

View file

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>storylineView</class>
<widget class="QWidget" name="storylineView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1040</width>
<height>130</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="btnZoomIn">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string>+</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnZoomOut">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string>-</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRefresh">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="view-refresh">
<normaloff/>
</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="sldTxtSize">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSettings">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="preferences-system">
<normaloff/>
</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGraphicsView" name="view"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

Binary file not shown.