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
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 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 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.CharacterLetter: 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) 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, 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()))) delta += w
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 mouseMoveEvent(self, event): textEditView.mouseMoveEvent(self, event) onRef = [r for r in self.refRects if r.contains(event.pos())] if not onRef: qApp.restoreOverrideCursor() QToolTip.hideText() return cursor = self.cursorForPosition(event.pos()) ref = self.refUnderCursor(cursor) if ref: if not qApp.overrideCursor(): qApp.setOverrideCursor(Qt.PointingHandCursor) QToolTip.showText(self.mapToGlobal(event.pos()), Ref.tooltip(ref))
def mouseMoveEvent(self, event): MDEditView.mouseMoveEvent(self, event) onRef = [r for r in self.refRects if r.contains(event.pos())] if not onRef: qApp.restoreOverrideCursor() QToolTip.hideText() return cursor = self.cursorForPosition(event.pos()) ref = self.refUnderCursor(cursor) if ref: if not qApp.overrideCursor(): qApp.setOverrideCursor(Qt.PointingHandCursor) QToolTip.showText(self.mapToGlobal(event.pos()), Ref.tooltip(ref))
def mouseMoveEvent(self, event): """ When mouse moves, we show tooltip when appropriate. """ self.beginTooltipMoveEvent() MDEditView.mouseMoveEvent(self, event) self.endTooltipMoveEvent() onRef = [r for r in self.refRects if r.contains(event.pos())] if not onRef: qApp.restoreOverrideCursor() self.hideTooltip() return cursor = self.cursorForPosition(event.pos()) ref = self.refUnderCursor(cursor) if ref: if not qApp.overrideCursor(): qApp.setOverrideCursor(Qt.PointingHandCursor) self.showTooltip(self.mapToGlobal(event.pos()), Ref.tooltip(ref))
def linkHovered(self, link): if link: QToolTip.showText(QCursor.pos(), Ref.tooltip(link))
def test_references(MWSampleProject): """ Tests references using sample project. """ from manuskript.models import references as Ref MW = MWSampleProject # References ref1 = Ref.plotReference("42", searchable=True) ref2 = Ref.plotReference("42") assert ref1 in ref2 ref1 = Ref.characterReference("42", searchable=True) ref2 = Ref.characterReference("42") assert ref1 in ref2 ref1 = Ref.textReference("42", searchable=True) ref2 = Ref.textReference("42") assert ref1 in ref2 ref1 = Ref.worldReference("42", searchable=True) ref2 = Ref.worldReference("42") assert ref1 in ref2 # Plots mdlPlots = MW.mdlPlots plotsImp = mdlPlots.getPlotsByImportance() plots = [] [plots.extend(i) for i in plotsImp] assert len(plots) == 3 plotID = plots[0] assert "\n" in Ref.infos(Ref.plotReference(plotID)) assert "Not a ref" in Ref.infos("<invalid>") assert "Unknown" in Ref.infos(Ref.plotReference("999")) assert Ref.shortInfos(Ref.plotReference(plotID)) is not None assert Ref.shortInfos(Ref.plotReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 # Character mdlChar = MW.mdlCharacter IDs = [mdlChar.ID(r) for r in range(mdlChar.rowCount())] assert len(IDs) == 6 # Peter, Paul, Philip, Stephen, Barnabas, Herod charID = IDs[0] assert "\n" in Ref.infos(Ref.characterReference(charID)) assert "Unknown" in Ref.infos(Ref.characterReference("999")) assert Ref.shortInfos(Ref.characterReference(charID)) is not None assert Ref.shortInfos(Ref.characterReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 # Texts mdlOutline = MW.mdlOutline assert mdlOutline.rowCount() == 3 # Jerusalem, Samaria, Extremities root = mdlOutline.rootItem textID = root.child(0).ID() assert "\n" in Ref.infos(Ref.textReference(textID)) assert "Unknown" in Ref.infos(Ref.textReference("999")) assert Ref.shortInfos(Ref.textReference(textID)) is not None assert Ref.shortInfos(Ref.textReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 # World mdlWorld = MW.mdlWorld assert mdlWorld.rowCount() == 3 # Places, Culture, Travel worldID = mdlWorld.itemID(mdlWorld.item(2).child(1)) assert "\n" in Ref.infos(Ref.worldReference(worldID)) assert "Unknown" in Ref.infos(Ref.worldReference("999")) assert Ref.shortInfos(Ref.worldReference(worldID)) is not None assert Ref.shortInfos(Ref.worldReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 refs = [ Ref.plotReference(plotID), Ref.characterReference(charID), Ref.textReference(textID), Ref.worldReference(worldID), ] # Titles for ref in refs: assert Ref.title(ref) is not None assert Ref.title("<invalid>") is None assert Ref.title(Ref.plotReference("999")) is None # Other stuff assert Ref.type(Ref.plotReference(plotID)) == Ref.PlotLetter assert Ref.ID(Ref.textReference(textID)) == textID assert "Unknown" in Ref.tooltip(Ref.worldReference("999")) assert "Not a ref" in Ref.tooltip("<invalid>") for ref in refs: assert Ref.tooltip(ref) is not None # Links assert Ref.refToLink("<invalid>") is None assert Ref.refToLink(Ref.plotReference("999")) == Ref.plotReference("999") assert Ref.refToLink( Ref.characterReference("999")) == Ref.characterReference("999") assert Ref.refToLink(Ref.textReference("999")) == Ref.textReference("999") assert Ref.refToLink( Ref.worldReference("999")) == Ref.worldReference("999") for ref in refs: assert "<a href" in Ref.refToLink(ref) # Open assert Ref.open("<invalid>") is None assert Ref.open(Ref.plotReference("999")) == False assert Ref.open(Ref.characterReference("999")) == False assert Ref.open(Ref.textReference("999")) == False assert Ref.open(Ref.worldReference("999")) == False for ref in refs: assert Ref.open(ref) == True assert Ref.open(Ref.EmptyRef.format("Z", 14, "")) == False
def refresh(self): if not self._mdlPlots or not self._mdlOutline or not self._mdlCharacter: return if not self.isVisible(): return 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) # Get the list of tracked items (array of references) trackedItems = [] if self.actPlots.isChecked(): trackedItems += self.plotReferences() if self.actCharacters.isChecked(): trackedItems += self.charactersReferences() ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + 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) 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 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.CharacterLetter: 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) 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, 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()))) delta += w listItems(root, outline) OUTLINE_WIDTH = itemWidth(root) # Add Tracked items i = 0 itemsRect = s.addRect(0, 0, 0, 0) itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING) # Set of colors for plots (as long as they don't have their own colors) colors = [ "#D97777", "#AE5F8C", "#D9A377", "#FFC2C2", "#FFDEC2", "#D2A0BC", "#7B0F0F", "#7B400F", "#620C3D", "#AA3939", "#AA6C39", "#882D61", "#4C0000", "#4C2200", "#3D0022", ] for ref in trackedItems: if references.type(ref) == references.CharacterLetter: color = self._mdlCharacter.getCharacterByID( references.ID(ref)).color() else: color = QColor(colors[i % len(colors)]) # 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()) # 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(references.tooltip(ref)) # 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)
def refresh(self): if not self._mdlPlots or not self._mdlOutline or not self._mdlCharacter: return if not self.isVisible(): return 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) # Get the list of tracked items (array of references) trackedItems = [] if self.actPlots.isChecked(): trackedItems += self.plotReferences() if self.actCharacters.isChecked(): trackedItems += self.charactersReferences() ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + 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) 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 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.CharacterLetter: 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) 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, 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()))) delta += w listItems(root, outline) OUTLINE_WIDTH = itemWidth(root) # Add Tracked items i = 0 itemsRect = s.addRect(0, 0, 0, 0) itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING) # Set of colors for plots (as long as they don't have their own colors) colors = [ "#D97777", "#AE5F8C", "#D9A377", "#FFC2C2", "#FFDEC2", "#D2A0BC", "#7B0F0F", "#7B400F", "#620C3D", "#AA3939", "#AA6C39", "#882D61", "#4C0000", "#4C2200", "#3D0022", ] for ref in trackedItems: if references.type(ref) == references.CharacterLetter: color = self._mdlCharacter.getCharacterByID(references.ID(ref)).color() else: color = QColor(colors[i % len(colors)]) # 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()) # 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(references.tooltip(ref)) # 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)
def test_references(MWSampleProject): """ Tests references using sample project. """ from manuskript.models import references as Ref MW = MWSampleProject # References ref1 = Ref.plotReference("42", searchable=True) ref2 = Ref.plotReference("42") assert ref1 in ref2 ref1 = Ref.characterReference("42", searchable=True) ref2 = Ref.characterReference("42") assert ref1 in ref2 ref1 = Ref.textReference("42", searchable=True) ref2 = Ref.textReference("42") assert ref1 in ref2 ref1 = Ref.worldReference("42", searchable=True) ref2 = Ref.worldReference("42") assert ref1 in ref2 # Plots mdlPlots = MW.mdlPlots plotsImp = mdlPlots.getPlotsByImportance() plots = [] [plots.extend(i) for i in plotsImp] assert len(plots) == 3 plotID = plots[0] assert "\n" in Ref.infos(Ref.plotReference(plotID)) assert "Not a ref" in Ref.infos("<invalid>") assert "Unknown" in Ref.infos(Ref.plotReference("999")) assert Ref.shortInfos(Ref.plotReference(plotID)) is not None assert Ref.shortInfos(Ref.plotReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 # Character mdlChar = MW.mdlCharacter IDs = [mdlChar.ID(r) for r in range(mdlChar.rowCount())] assert len(IDs) == 6 # Peter, Paul, Philip, Stephen, Barnabas, Herod charID = IDs[0] assert "\n" in Ref.infos(Ref.characterReference(charID)) assert "Unknown" in Ref.infos(Ref.characterReference("999")) assert Ref.shortInfos(Ref.characterReference(charID)) is not None assert Ref.shortInfos(Ref.characterReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 # Texts mdlOutline = MW.mdlOutline assert mdlOutline.rowCount() == 3 # Jerusalem, Samaria, Extremities root = mdlOutline.rootItem textID = root.child(0).ID() assert "\n" in Ref.infos(Ref.textReference(textID)) assert "Unknown" in Ref.infos(Ref.textReference("999")) assert Ref.shortInfos(Ref.textReference(textID)) is not None assert Ref.shortInfos(Ref.textReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 # World mdlWorld = MW.mdlWorld assert mdlWorld.rowCount() == 3 # Places, Culture, Travel worldID = mdlWorld.itemID(mdlWorld.item(2).child(1)) assert "\n" in Ref.infos(Ref.worldReference(worldID)) assert "Unknown" in Ref.infos(Ref.worldReference("999")) assert Ref.shortInfos(Ref.worldReference(worldID)) is not None assert Ref.shortInfos(Ref.worldReference("999")) == None assert Ref.shortInfos("<invalidref>") == -1 refs = [Ref.plotReference(plotID), Ref.characterReference(charID), Ref.textReference(textID), Ref.worldReference(worldID),] # Titles for ref in refs: assert Ref.title(ref) is not None assert Ref.title("<invalid>") is None assert Ref.title(Ref.plotReference("999")) is None # Other stuff assert Ref.type(Ref.plotReference(plotID)) == Ref.PlotLetter assert Ref.ID(Ref.textReference(textID)) == textID assert "Unknown" in Ref.tooltip(Ref.worldReference("999")) assert "Not a ref" in Ref.tooltip("<invalid>") for ref in refs: assert Ref.tooltip(ref) is not None # Links assert Ref.refToLink("<invalid>") is None assert Ref.refToLink(Ref.plotReference("999")) == Ref.plotReference("999") assert Ref.refToLink(Ref.characterReference("999")) == Ref.characterReference("999") assert Ref.refToLink(Ref.textReference("999")) == Ref.textReference("999") assert Ref.refToLink(Ref.worldReference("999")) == Ref.worldReference("999") for ref in refs: assert "<a href" in Ref.refToLink(ref) # Open assert Ref.open("<invalid>") is None assert Ref.open(Ref.plotReference("999")) == False assert Ref.open(Ref.characterReference("999")) == False assert Ref.open(Ref.textReference("999")) == False assert Ref.open(Ref.worldReference("999")) == False for ref in refs: assert Ref.open(ref) == True assert Ref.open(Ref.EmptyRef.format("Z", 14, "")) == False