class EdgeItem(GraphItem): EDGE_PEN_WIDTH = 0.5 def __init__(self, spline, label, label_center, from_node, to_node, parent=None, **kwargs): super(EdgeItem, self).__init__(parent, **kwargs) self._edge_pen_width = kwargs.get('edge_pen_width', self.EDGE_PEN_WIDTH) self.from_node = from_node self.from_node.add_outgoing_edge(self) self.to_node = to_node self.to_node.add_incoming_edge(self) self._brush = QBrush(self._color) self._label_pen = QPen() self._label_pen.setColor(self._color) self._label_pen.setJoinStyle(Qt.RoundJoin) self._label_pen.setWidthF(self._label_pen_width) self._edge_pen = QPen() self._edge_pen.setColor(self._color) self._edge_pen.setWidthF(self._edge_pen_width) self._sibling_edges = set() self._label = None if label is not None: self._label = QGraphicsSimpleTextItem(label) font = self._label.font() font.setPointSize(8) self._label.setFont(font) label_rect = self._label.boundingRect() label_rect.moveCenter(label_center) self._label.setPos(label_rect.x(), label_rect.y()) # spline specification according to http://www.graphviz.org/doc/info/attrs.html#k:splineType coordinates = spline.split(' ') # extract optional end_point end_point = None if coordinates[0].startswith('e,'): parts = coordinates.pop(0)[2:].split(',') end_point = QPointF(float(parts[0]), -float(parts[1])) # extract optional start_point if coordinates[0].startswith('s,'): parts = coordinates.pop(0).split(',') # first point parts = coordinates.pop(0).split(',') point = QPointF(float(parts[0]), -float(parts[1])) path = QPainterPath(point) while len(coordinates) > 2: # extract triple of points for a cubic spline parts = coordinates.pop(0).split(',') point1 = QPointF(float(parts[0]), -float(parts[1])) parts = coordinates.pop(0).split(',') point2 = QPointF(float(parts[0]), -float(parts[1])) parts = coordinates.pop(0).split(',') point3 = QPointF(float(parts[0]), -float(parts[1])) path.cubicTo(point1, point2, point3) self._arrow = None if end_point is not None: # draw arrow self._arrow = QGraphicsPolygonItem() polygon = QPolygonF() polygon.append(point3) offset = QPointF(end_point - point3) corner1 = QPointF(-offset.y(), offset.x()) * 0.35 corner2 = QPointF(offset.y(), -offset.x()) * 0.35 polygon.append(point3 + corner1) polygon.append(end_point) polygon.append(point3 + corner2) self._arrow.setPolygon(polygon) self._path = QGraphicsPathItem() self._path.setPath(path) self.addToGroup(self._path) self._brush.setColor(self._color) self._edge_pen.setColor(self._color) self._label_pen.setColor(self._color) self._path.setPen(self._edge_pen) if self._arrow is not None: self._arrow.setBrush(self._brush) self._arrow.setPen(self._edge_pen) if self._label is not None: self._label.setBrush(self._brush) self._label.setPen(self._label_pen) def add_to_scene(self, scene): scene.addItem(self) if self._label is not None: scene.addItem(self._label) if self._arrow is not None: scene.addItem(self._arrow) def setToolTip(self, tool_tip): super(EdgeItem, self).setToolTip(tool_tip) if self._label is not None: self._label.setToolTip(tool_tip) if self._arrow is not None: self._arrow.setToolTip(tool_tip) def add_sibling_edge(self, edge): self._sibling_edges.add(edge) def set_color(self, color=None): if color is None: color = self._color self._brush.setColor(color) self._edge_pen.setColor(color) self._label_pen.setColor(color) self._path.setPen(self._edge_pen) if self._arrow is not None: self._arrow.setBrush(self._brush) self._arrow.setPen(self._edge_pen) if self._label is not None: self._label.setBrush(self._brush) self._label.setPen(self._label_pen)
class NodeItem(GraphItem): def __init__(self, bounding_box, shape, label, label_pos=None, url=None, parent=None, **kwargs): super(NodeItem, self).__init__(parent, **kwargs) self.url = url self._incoming_edges = set() self._outgoing_edges = set() self._brush = QBrush(self._color) self._label_pen = QPen() self._label_pen.setColor(self._color) self._label_pen.setJoinStyle(Qt.RoundJoin) self._label_pen.setWidthF(self._label_pen_width) if self._pen_width == 0.0: self._graphics_item_pen = QPen(Qt.NoPen) else: self._graphics_item_pen = QPen(self._label_pen) self._graphics_item_pen.setWidthF(self._pen_width) self._graphics_item = ShapeFactory.create(shape, bounding_box) if ShapeFactory.message is not None: print ShapeFactory.message self.addToGroup(self._graphics_item) if not shape == 'point': self._label = QGraphicsSimpleTextItem(label) label_rectangle = self._label.boundingRect() if label_pos is None: label_rectangle.moveCenter(bounding_box.center()) else: label_rectangle.moveCenter(label_pos) self._label.setPos(label_rectangle.x(), label_rectangle.y()) self.addToGroup(self._label) else: self._graphics_item.setBrush(self._color) self._label = None self._brush.setColor(self._color) self._graphics_item_pen.setColor(self._color) self._label_pen.setColor(self._color) self._graphics_item.setPen(self._graphics_item_pen) if self._label is not None: self._label.setBrush(self._brush) self._label.setPen(self._label_pen) def add_incoming_edge(self, edge): self._incoming_edges.add(edge) def add_outgoing_edge(self, edge): self._outgoing_edges.add(edge) def set_color(self, color=None): if color is None: color = self._color self._brush.setColor(color) self._graphics_item_pen.setColor(color) self._label_pen.setColor(color) self._graphics_item.setPen(self._graphics_item_pen) if self._label is not None: self._label.setBrush(self._brush) self._label.setPen(self._label_pen)
class DmgHtmlNodeItem(GraphItem): HIGHLIGHT_LEVEL = 1 HOVERED_COLOR = QColor(250, 0, 0) HIGHLIGHTED_COLOR = QColor(100, 100, 100) HIGHLIGHTED_PEN_WIDTH = 2.0 HIGHLIGHTED_LABEL_PEN_WIDTH = 1.0 def __init__(self, bounding_box, shape, label, label_pos=None, url=None, parent=None, **kwargs): super(DmgHtmlNodeItem, self).__init__(parent, **kwargs) self.url = url self._incoming_edges = set() self._outgoing_edges = set() self._brush = QBrush(self._color) self._label_pen = QPen() self._label_pen.setColor(self._color) self._label_pen.setJoinStyle(Qt.RoundJoin) self._label_pen.setWidthF(self._label_pen_width) self._graphics_item_pen = QPen(self._label_pen) self._graphics_item_pen.setWidthF(self._pen_width) self._label = QGraphicsTextItem() self._label.setHtml(label) label_rectangle = self._label.boundingRect() if label_pos is None: label_rectangle.moveCenter(bounding_box.center()) else: label_rectangle.moveCenter(label_pos) self._label.setPos(label_rectangle.x(), label_rectangle.y()) self.addToGroup(self._label) self._graphics_item = ShapeFactory.create(shape, bounding_box) if ShapeFactory.message is not None: print ShapeFactory.message self.addToGroup(self._graphics_item) self._brush.setColor(self._color) self._graphics_item_pen.setColor(self._color) self._label_pen.setColor(self._color) self._graphics_item.setPen(self._graphics_item_pen) self._highlight_level = kwargs.get('highlight_level', self.HIGHLIGHT_LEVEL) self._hovered_color = kwargs.get('hovered_color', self.HOVERED_COLOR) self._highlighted_color = kwargs.get('highlighted_color', self.HIGHLIGHTED_COLOR) self._highlighted_pen_width = kwargs.get('highlighted_pen_width', self.HIGHLIGHTED_PEN_WIDTH) self._highlighted_label_pen_width = kwargs.get( 'highlighted_label_pen_width', self.HIGHLIGHTED_LABEL_PEN_WIDTH) self.hover_shape = None self.setAcceptHoverEvents(True) def add_incoming_edge(self, edge): self._incoming_edges.add(edge) def add_outgoing_edge(self, edge): self._outgoing_edges.add(edge) def set_color(self, color=None): if color is None: color = self._color self._brush.setColor(color) self._graphics_item_pen.setColor(color) self._label.setDefaultTextColor(color) self._graphics_item.setPen(self._graphics_item_pen) def set_hover_shape(self, shape): self.hover_shape = shape def shape(self): if self.hover_shape is not None: path = QPainterPath() path.addRect(self.hover_shape) return path return super(GraphItem, self).shape() def hoverEnterEvent(self, event): self.set_color(self._highlighted_color) self._highlight_connections() def hoverLeaveEvent(self, event): self.set_color() self._highlight_connections(False) def _highlight_connections(self, highlighted=True): if highlighted: if self._highlight_level > 1: cyclic_edges = self._incoming_edges.intersection( self._outgoing_edges) # incoming edges in blue incoming_nodes = set() for incoming_edge in self._incoming_edges.difference( cyclic_edges): incoming_edge.set_color(self.COLOR_BLUE) if incoming_edge.from_node != self: incoming_nodes.add(incoming_edge.from_node) # outgoing edges in green outgoing_nodes = set() for outgoing_edge in self._outgoing_edges.difference( cyclic_edges): outgoing_edge.set_color(self.COLOR_GREEN) if outgoing_edge.to_node != self: outgoing_nodes.add(outgoing_edge.to_node) # incoming/outgoing edges in teal for edge in cyclic_edges: edge.set_color(self.COLOR_TEAL) if self._highlight_level > 2: cyclic_nodes = incoming_nodes.intersection(outgoing_nodes) # incoming nodes in blue for incoming_node in incoming_nodes.difference( cyclic_nodes): incoming_node.set_color(self.COLOR_BLUE) # outgoing nodes in green for outgoing_node in outgoing_nodes.difference( cyclic_nodes): outgoing_node.set_color(self.COLOR_GREEN) # incoming/outgoing nodes in teal for node in cyclic_nodes: node.set_color(self.COLOR_TEAL) else: if self._highlight_level > 1: for incoming_edge in self._incoming_edges: incoming_edge.set_color() if self.highlight_level > 2 and incoming_edge.from_node != self: incoming_edge.from_node.set_color() for outgoing_edge in self._outgoing_edges: outgoing_edge.set_color() if self.highlight_level > 2 and outgoing_edge.to_node != self: outgoing_edge.to_node.set_color() def highlight(self, highlighted=True): if highlighted: self._graphics_item_pen.setWidthF(self._highlighted_pen_width) else: self._graphics_item_pen.setWidthF(self._pen_width) self._graphics_item.setPen(self._graphics_item_pen)
class DmgHtmlNodeItem(GraphItem): HIGHLIGHT_LEVEL = 1 HOVERED_COLOR = QColor(250, 0, 0) HIGHLIGHTED_COLOR = QColor(100, 100, 100) HIGHLIGHTED_PEN_WIDTH = 2.0 HIGHLIGHTED_LABEL_PEN_WIDTH = 1.0 def __init__(self, bounding_box, shape, label, label_pos=None, url=None, parent=None, **kwargs): super(DmgHtmlNodeItem, self).__init__(parent, **kwargs) self.url = url self._incoming_edges = set() self._outgoing_edges = set() self._brush = QBrush(self._color) self._label_pen = QPen() self._label_pen.setColor(self._color) self._label_pen.setJoinStyle(Qt.RoundJoin) self._label_pen.setWidthF(self._label_pen_width) self._graphics_item_pen = QPen(self._label_pen) self._graphics_item_pen.setWidthF(self._pen_width) self._label = QGraphicsTextItem() self._label.setHtml(label) label_rectangle = self._label.boundingRect() if label_pos is None: label_rectangle.moveCenter(bounding_box.center()) else: label_rectangle.moveCenter(label_pos) self._label.setPos(label_rectangle.x(), label_rectangle.y()) self.addToGroup(self._label) self._graphics_item = ShapeFactory.create(shape, bounding_box) if ShapeFactory.message is not None: print ShapeFactory.message self.addToGroup(self._graphics_item) self._brush.setColor(self._color) self._graphics_item_pen.setColor(self._color) self._label_pen.setColor(self._color) self._graphics_item.setPen(self._graphics_item_pen) self._highlight_level = kwargs.get('highlight_level', self.HIGHLIGHT_LEVEL) self._hovered_color = kwargs.get('hovered_color', self.HOVERED_COLOR) self._highlighted_color = kwargs.get('highlighted_color', self.HIGHLIGHTED_COLOR) self._highlighted_pen_width = kwargs.get('highlighted_pen_width', self.HIGHLIGHTED_PEN_WIDTH) self._highlighted_label_pen_width = kwargs.get('highlighted_label_pen_width', self.HIGHLIGHTED_LABEL_PEN_WIDTH) self.hover_shape = None self.setAcceptHoverEvents(True) def add_incoming_edge(self, edge): self._incoming_edges.add(edge) def add_outgoing_edge(self, edge): self._outgoing_edges.add(edge) def set_color(self, color=None): if color is None: color = self._color self._brush.setColor(color) self._graphics_item_pen.setColor(color) self._label.setDefaultTextColor(color) self._graphics_item.setPen(self._graphics_item_pen) def set_hover_shape(self, shape): self.hover_shape = shape def shape(self): if self.hover_shape is not None: path = QPainterPath() path.addRect(self.hover_shape) return path return super(GraphItem, self).shape() def hoverEnterEvent(self, event): self.set_color(self._highlighted_color) self._highlight_connections() def hoverLeaveEvent(self, event): self.set_color() self._highlight_connections(False) def _highlight_connections(self, highlighted=True): if highlighted: if self._highlight_level > 1: cyclic_edges = self._incoming_edges.intersection(self._outgoing_edges) # incoming edges in blue incoming_nodes = set() for incoming_edge in self._incoming_edges.difference(cyclic_edges): incoming_edge.set_color(self.COLOR_BLUE) if incoming_edge.from_node != self: incoming_nodes.add(incoming_edge.from_node) # outgoing edges in green outgoing_nodes = set() for outgoing_edge in self._outgoing_edges.difference(cyclic_edges): outgoing_edge.set_color(self.COLOR_GREEN) if outgoing_edge.to_node != self: outgoing_nodes.add(outgoing_edge.to_node) # incoming/outgoing edges in teal for edge in cyclic_edges: edge.set_color(self.COLOR_TEAL) if self._highlight_level > 2: cyclic_nodes = incoming_nodes.intersection(outgoing_nodes) # incoming nodes in blue for incoming_node in incoming_nodes.difference(cyclic_nodes): incoming_node.set_color(self.COLOR_BLUE) # outgoing nodes in green for outgoing_node in outgoing_nodes.difference(cyclic_nodes): outgoing_node.set_color(self.COLOR_GREEN) # incoming/outgoing nodes in teal for node in cyclic_nodes: node.set_color(self.COLOR_TEAL) else: if self._highlight_level > 1: for incoming_edge in self._incoming_edges: incoming_edge.set_color() if self.highlight_level > 2 and incoming_edge.from_node != self: incoming_edge.from_node.set_color() for outgoing_edge in self._outgoing_edges: outgoing_edge.set_color() if self.highlight_level > 2 and outgoing_edge.to_node != self: outgoing_edge.to_node.set_color() def highlight(self, highlighted=True): if highlighted: self._graphics_item_pen.setWidthF(self._highlighted_pen_width) else: self._graphics_item_pen.setWidthF(self._pen_width) self._graphics_item.setPen(self._graphics_item_pen)