diff --git a/manuskript/models/references.py b/manuskript/models/references.py index ac29a06c..d8f87e7a 100644 --- a/manuskript/models/references.py +++ b/manuskript/models/references.py @@ -373,56 +373,125 @@ def infos(ref): return qApp.translate("references", "Unknown reference: {}.").format(ref) -def tooltip(ref): - """Returns a tooltip in HTML for the reference ``ref``.""" +def shortInfos(ref): + """Returns infos about reference ``ref``. + Returns -1 if ``ref`` is not a valid reference, and None if it is valid but unknown.""" match = re.fullmatch(RegEx, ref) if not match: - return qApp.translate("references", "Not a reference: {}.").format(ref) + return -1 _type = match.group(1) _ref = match.group(2) + infos = {} + infos["ID"] = _ref + if _type == TextLetter: + + infos["type"] = TextLetter + m = mainWindow().mdlOutline idx = m.getIndexByID(_ref) if not idx.isValid(): - return qApp.translate("references", "Unknown reference: {}.").format(ref) + return None item = idx.internalPointer() if item.isFolder(): - tt = qApp.translate("references", "Folder: {}").format(item.title()) + infos["text_type"] = "folder" else: - tt = qApp.translate("references", "Text: {}").format(item.title()) - tt += "
{}".format(item.path()) + infos["text_type"] = "text" - return tt + infos["title"] = item.title() + infos["path"] = item.path() + return infos elif _type == PersoLetter: + + infos["type"] = PersoLetter + m = mainWindow().mdlPersos item = m.item(int(_ref), Perso.name.value) if item: - return qApp.translate("references", "Character: {}").format(item.text()) + infos["title"] = item.text() + infos["name"] = item.text() + return infos elif _type == PlotLetter: + + infos["type"] = PlotLetter + m = mainWindow().mdlPlots name = m.getPlotNameByID(_ref) if name: - return qApp.translate("references", "Plot: {}").format(name) + infos["title"] = name + return infos elif _type == WorldLetter: + + infos["type"] = WorldLetter + m = mainWindow().mdlWorld item = m.itemByID(_ref) if item: name = item.text() path = m.path(item) - return qApp.translate("references", "World: {name}{path}").format( - name=name, - path=" ({})".format(path) if path else "") + infos["title"] = name + infos["path"] = path + return infos - return qApp.translate("references", "Unknown reference: {}.").format(ref) + return None + + +def title(ref): + """Returns a the title (or name) for the reference ``ref``.""" + infos = shortInfos(ref) + if infos and infos != -1 and "title" in infos: + return infos["title"] + else: + return None + +def type(ref): + infos = shortInfos(ref) + if infos and infos != -1: + return infos["type"] + +def ID(ref): + infos = shortInfos(ref) + if infos and infos != -1: + return infos["ID"] + +def tooltip(ref): + """Returns a tooltip in HTML for the reference ``ref``.""" + infos = shortInfos(ref) + + if not infos: + return qApp.translate("references", "Unknown reference: {}.").format(ref) + + if infos == -1: + return qApp.translate("references", "Not a reference: {}.").format(ref) + + + if infos["type"] == TextLetter: + if infos["text_type"] == "folder": + tt = qApp.translate("references", "Folder: {}").format(infos["title"]) + else: + tt = qApp.translate("references", "Text: {}").format(infos["title"]) + tt += "
{}".format(infos["path"]) + return tt + + elif infos["type"] == PersoLetter: + return qApp.translate("references", "Character: {}").format(infos["title"]) + + elif infos["type"] == PlotLetter: + return qApp.translate("references", "Plot: {}").format(infos["title"]) + + elif infos["type"] == WorldLetter: + return qApp.translate("references", "World: {name}{path}").format( + name=infos["title"], + path=" ({})".format(infos["path"]) if infos["path"] else "") ############################################################################### diff --git a/manuskript/ui/views/storylineView.py b/manuskript/ui/views/storylineView.py index ac149f70..a5f81362 100644 --- a/manuskript/ui/views/storylineView.py +++ b/manuskript/ui/views/storylineView.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # --!-- coding: utf8 --!-- from PyQt5.QtCore import Qt, QTimer, QRectF -from PyQt5.QtGui import QBrush, QPen, QFontMetrics, QFontMetricsF +from PyQt5.QtGui import QBrush, QPen, QFontMetrics, QFontMetricsF, QColor from PyQt5.QtWidgets import QWidget, QGraphicsScene, QGraphicsSimpleTextItem, QMenu, QAction, QGraphicsRectItem, \ QGraphicsLineItem, QGraphicsEllipseItem @@ -32,15 +32,17 @@ class storylineView(QWidget, Ui_storylineView): 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.actPlots = QAction(self.tr("Show Plots"), m) + self.actPlots.setCheckable(True) + self.actPlots.setChecked(True) + self.actPlots.toggled.connect(self.reloadTimer.start) + m.addAction(self.actPlots) + + self.actCharacters = QAction(self.tr("Show Characters"), m) + self.actCharacters.setCheckable(True) + self.actCharacters.setChecked(False) + self.actCharacters.toggled.connect(self.reloadTimer.start) + m.addAction(self.actCharacters) self.btnSettings.setMenu(m) @@ -55,6 +57,33 @@ class storylineView(QWidget, Ui_storylineView): self._mdlPersos = mdlPersos self._mdlPersos.dataChanged.connect(self.reloadTimer.start) + def plotReferences(self): + "Returns a list of plot references" + if not self._mdlPlots: + pass + + plotsID = self._mdlPlots.getPlotsByImportance() + r = [] + for importance in plotsID: + for ID in importance: + ref = references.plotReference(ID) + r.append(ref) + + return r + + def persosReferences(self): + "Returns a list of character references" + if not self._mdlPersos: + pass + + IDs = self._mdlPersos.getPersosByImportance() + r = [] + for importance in IDs: + for ID in importance: + ref = references.persoReference(ID) + r.append(ref) + + return r def refresh(self): if not self._mdlPlots or not self._mdlOutline or not self._mdlPersos: @@ -82,24 +111,24 @@ class storylineView(QWidget, Ui_storylineView): MAX_LEVEL = maxLevel(root) - # Generate left entries - # (As of now, plot only) - plotsID = self._mdlPlots.getPlotsByImportance() + # Get the list of tracked items (array of references) 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) + if self.actPlots.isChecked(): + trackedItems += self.plotReferences() - trackedItems.append((ID, ref, name)) - max_name = max(fm.width(name), max_name) + if self.actCharacters.isChecked(): + trackedItems += self.persosReferences() ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING ) - TITLE_WIDTH = max_name + 2 * SPACING + fm = QFontMetrics(s.font()) + max_name = 0 + for ref in trackedItems: + name = references.title(ref) + max_name = max(fm.width(name), max_name) + + TITLE_WIDTH = max_name + 2 * SPACING # Add Folders and Texts outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT) @@ -150,9 +179,22 @@ class storylineView(QWidget, Ui_storylineView): rectChild.setToolTip(references.tooltip(references.textReference(child.ID()))) # Find tracked references in that scene (or parent folders) - for ID, ref, name in trackedItems: + for ref in trackedItems: result = [] + + # Tests if POV + scenePOV = False # Will hold true of character is POV of the current text, not containing folder + if references.type(ref) == references.PersoLetter: + ID = references.ID(ref) + c = child + while c: + if c.POV() == ID: + result.append(c.ID()) + if c == child: scenePOV = True + c = c.parent() + + # Search in notes/references c = child while c: result += references.findReferencesTo(ref, c, recursive=False) @@ -162,7 +204,7 @@ class storylineView(QWidget, Ui_storylineView): ref2 = result[0] # Create a RefCircle with the reference - c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2) + c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2, important=scenePOV) # 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()))) @@ -173,22 +215,27 @@ class storylineView(QWidget, Ui_storylineView): OUTLINE_WIDTH = itemWidth(root) - # Add Plots + # Add Tracked items 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() + for ref in trackedItems: + if references.type(ref) == references.PersoLetter: + color = QColor(self._mdlPersos.getPersoColorByID(references.ID(ref))) + else: + 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) + r.setToolTip(references.tooltip(ref)) i += 1 # Text + name = references.title(ref) txt = QGraphicsSimpleTextItem(name, r) txt.setPos(r.boundingRect().center() - txt.boundingRect().center()) @@ -198,7 +245,7 @@ class storylineView(QWidget, Ui_storylineView): line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y()) s.addItem(line) line.setPen(QPen(color, 5)) - line.setToolTip(self.tr("Plot: ") + name) + line.setToolTip(references.tooltip(ref)) # We add the circles / references to text, on the line for ref2, circle, pos in refCircles: @@ -225,13 +272,15 @@ class OutlineRect(QGraphicsRectItem): class RefCircle(QGraphicsEllipseItem): - def __init__(self, x, y, diameter, parent=None, ID=None): + def __init__(self, x, y, diameter, parent=None, ID=None, important=False): 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) + if important: + self.setBrush(Qt.black) def multiplyDiameter(self, factor): r1 = self.rect()