diff --git a/src/cutecoin/gui/views/wot.py b/src/cutecoin/gui/views/wot.py index ce64aca6aaca8d4dc87ef885a6a51e0f6f5fc020..ccc6c1627dbd878afd0fdc80971270e9a4810add 100644 --- a/src/cutecoin/gui/views/wot.py +++ b/src/cutecoin/gui/views/wot.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- import math -from PyQt5.QtGui import QPainter, QBrush, QPen, QPolygonF, QColor, QRadialGradient,\ +from PyQt5.QtGui import QPainter, QBrush, QPen, QPolygonF, QColor, QRadialGradient, \ QPainterPath, QMouseEvent, QWheelEvent, QTransform, QCursor from PyQt5.QtCore import Qt, QRectF, QLineF, QPoint, QPointF, QSizeF, qFuzzyCompare, pyqtSignal -from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsEllipseItem,\ - QGraphicsSimpleTextItem, QGraphicsLineItem, QMenu, QAction, QGraphicsSceneHoverEvent,\ +from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsEllipseItem, \ + QGraphicsSimpleTextItem, QGraphicsLineItem, QMenu, QAction, QGraphicsSceneHoverEvent, \ QGraphicsSceneContextMenuEvent NODE_STATUS_HIGHLIGHTED = 1 @@ -48,14 +48,13 @@ class WotView(QGraphicsView): self.scale(sc, sc) self.centerOn(self.mapToScene(event.pos())) event.accept() - #Â act normally on scrollbar + # Â act normally on scrollbar else: #Â transmit event to parent class wheelevent super(QGraphicsView, self).wheelEvent(event) class Scene(QGraphicsScene): - # This defines signals taking string arguments node_clicked = pyqtSignal(dict, name='nodeClicked') node_signed = pyqtSignal(dict, name='nodeSigned') @@ -73,7 +72,9 @@ class Scene(QGraphicsScene): self.lastDragPos = QPoint() self.setItemIndexMethod(QGraphicsScene.NoIndex) - #Â axis of the scene for debug purpose + # list of nodes in scene + self.nodes = dict() + # Â axis of the scene for debug purpose # self.addLine(-100, 0, 100, 0) # self.addLine(0, -100, 0, 100) @@ -88,6 +89,7 @@ class Scene(QGraphicsScene): """ node = Node(metadata, pos) self.addItem(node) + self.nodes[node.id] = node return node def add_arc(self, source_node, destination_node, metadata): @@ -110,7 +112,7 @@ class Scene(QGraphicsScene): :param dict graph: graph to draw """ - #Â clear scene + # Â clear scene self.clear() # capture selected node (to draw it in the center) @@ -140,7 +142,8 @@ class Scene(QGraphicsScene): y = 0 x = -200 # sort by text - nodes = ((k, v) for (k, v) in sorted(graph.items(), key=lambda kv: kv[1]['text'].lower()) if selected_id in (arc['id'] for arc in v['arcs'])) + nodes = ((k, v) for (k, v) in sorted(graph.items(), key=lambda kv: kv[1]['text'].lower()) if + selected_id in (arc['id'] for arc in v['arcs'])) # add nodes and arcs for _id, certifier_node in nodes: node = self.add_node(certifier_node, (x, y)) @@ -151,6 +154,31 @@ class Scene(QGraphicsScene): self.update() + def update_path(self, path): + x = 0 + y = 0 + for json_node in path: + if json_node['status'] & NODE_STATUS_SELECTED: + previous_node = json_node + y -= 100 + continue + node = self.add_node(json_node, (x, y)) + skip_reverse_arc = False + for arc in json_node['arcs']: + if arc['id'] == previous_node['id']: + #print("arc from %s to %s" % (node.id, previous_node['id'])) + self.add_arc(node, self.nodes[previous_node['id']], arc) + skip_reverse_arc = True + break + if not skip_reverse_arc: + for arc in previous_node['arcs']: + if arc['id'] == json_node['id']: + #print("arc from %s to %s" % (previous_node['id'], node.id)) + self.add_arc(self.nodes[previous_node['id']], node, arc) + + previous_node = json_node + y -= 100 + class Node(QGraphicsEllipseItem): def __init__(self, metadata, x_y): @@ -166,6 +194,7 @@ class Node(QGraphicsEllipseItem): super(Node, self).__init__() self.metadata = metadata + self.id = metadata['id'] self.status_wallet = self.metadata['status'] & NODE_STATUS_HIGHLIGHTED self.status_member = not self.metadata['status'] & NODE_STATUS_OUT self.text = self.metadata['text'] @@ -203,8 +232,9 @@ class Node(QGraphicsEllipseItem): self.text_item.boundingRect().height() * 2 ) - #Â set anchor to the center - self.setTransform(QTransform().translate(-self.boundingRect().width()/2.0, -self.boundingRect().height()/2.0)) + # Â set anchor to the center + self.setTransform( + QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) self.setPos(x, y) #print(x, y) #Â center text in ellipse @@ -245,7 +275,7 @@ class Node(QGraphicsEllipseItem): :param event: scene context menu event """ - #Â no menu on the wallet node + # Â no menu on the wallet node if self.status_wallet: return None #Â create node context menus @@ -294,6 +324,7 @@ class Node(QGraphicsEllipseItem): # trigger scene signal self.scene().node_contact.emit(self.metadata) + class Arc(QGraphicsLineItem): def __init__(self, source_node, destination_node, metadata): """ @@ -319,7 +350,7 @@ class Arc(QGraphicsLineItem): self.setAcceptedMouseButtons(Qt.NoButton) - #Â cursor change on hover + # Â cursor change on hover self.setAcceptHoverEvents(True) self.adjust() self.setZValue(0) @@ -405,11 +436,9 @@ class Arc(QGraphicsLineItem): if line.dy() >= 0: angle = (2.0 * math.pi) - angle - #Â arrow in the middle of the arc - hpx = (line.p2().x() + line.p1().x()) / 2.0 - hpy = (line.p2().y() - line.p1().y()) / 2.0 - if line.dy() < 0: - hpy = -hpy + # Â arrow in the middle of the arc + hpx = line.p1().x() + (line.dx() / 2.0) + hpy = line.p1().y() + (line.dy() / 2.0) head_point = QPointF(hpx, hpy) painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) @@ -440,17 +469,17 @@ class Arc(QGraphicsLineItem): # detection mouse hover on arc path path = QPainterPath() path.addPolygon(QPolygonF([self.line().p1(), self.line().p2()])) - #Â add handles at the start and end of arc + # Â add handles at the start and end of arc path.addRect(QRectF( - self.line().p1().x()-5, - self.line().p1().y()-5, - self.line().p1().x()+5, - self.line().p1().y()+5 + self.line().p1().x() - 5, + self.line().p1().y() - 5, + self.line().p1().x() + 5, + self.line().p1().y() + 5 )) path.addRect(QRectF( - self.line().p2().x()-5, - self.line().p2().y()-5, - self.line().p2().x()+5, - self.line().p2().y()+5 + self.line().p2().x() - 5, + self.line().p2().y() - 5, + self.line().p2().x() + 5, + self.line().p2().y() + 5 )) return path diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py index c4082f40f9e9ed43aae3f54d7b830b519badbaf4..da2b697bb08e27a36d151ae147dfe6ab7ce3b237 100644 --- a/src/cutecoin/gui/wot_tab.py +++ b/src/cutecoin/gui/wot_tab.py @@ -62,7 +62,8 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): :param dict metadata: Graph node metadata of the identity """ - print("draw graph !!!!!!!!!!!! - " + metadata['text']) + logging.debug("draw graph !!!!!!!!!!!! - " + metadata['text']) + # create Person from node metadata person = get_person_from_metadata(metadata) person_account = Person(self.account.name, self.account.pubkey) @@ -95,13 +96,15 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): # populate graph with certified-by self.add_certified_list_to_graph(graph, certified_list, person, person_account) + # draw graph in qt scene + self.graphicsView.scene().update_wot(graph) + # if selected member is not the account member... if person.pubkey != person_account.pubkey: # add path from selected member to account member - self.get_path_from_member(graph, person, person_account) - - # draw graph in qt scene - self.graphicsView.scene().update_wot(graph) + path = self.get_path_from_member(graph, person, person_account) + if path: + self.graphicsView.scene().update_path(path) def reset(self): """ @@ -181,35 +184,29 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): if person_account.pubkey not in graph_tmp.keys(): # recursively feed graph searching for account node... self.feed_graph_to_find_account(graph_tmp, graph_tmp[person_selected.pubkey]['nodes'], person_account, list()) - print(graph_tmp.keys()) if len(graph_tmp[person_selected.pubkey]['nodes']) > 0: # calculate path of nodes between person and person_account path = self.find_shortest_path(graph_tmp, graph_tmp[person_selected.pubkey], graph_tmp[person_account.pubkey]) if path: - for node in path: - print(node['text']) + logging.debug([node['text'] for node in path]) else: - print('no path...') + logging.debug('no wot path') return path def feed_graph_to_find_account(self, graph, nodes, person_account, done=list()): - print('feed graph on %d nodes' % len(nodes)) for node in tuple(nodes): - print("len done = %d " % len(done)) if node['id'] in tuple(done): continue person_selected = Person(node['text'], node['id']) certifier_list = person_selected.certifiers_of(self.community) self.add_certifier_list_to_graph(graph, certifier_list, person_selected, person_account) if person_account.pubkey in tuple(graph.keys()): - print("ACCOUNT IN CERTFIERS END!") return False certified_list = person_selected.certified_by(self.community) self.add_certified_list_to_graph(graph, certified_list, person_selected, person_account) if person_account.pubkey in tuple(graph.keys()): - print("ACCOUNT IN CERTIFIED END!") return False if node['id'] not in tuple(done): done.append(node['id']) @@ -222,16 +219,13 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): return True def find_shortest_path(self, graph, start, end, path=list()): - #print('start:', start) path = path + [start] if start['id'] == end['id']: return path if start['id'] not in graph.keys(): return None shortest = None - print('scan nodes of ' + start['text']) for node in tuple(graph[start['id']]['nodes']): - print("try path from node " + node['text']) if node not in path: newpath = self.find_shortest_path(graph, node, end, path) if newpath: @@ -281,7 +275,6 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): } #Â add arc to certifier graph[certifier['pubkey']]['arcs'].append(arc) - print("CERTIFIER GRAPH LEN = %d " % len(graph[person.pubkey]['nodes'])) # if certifier node not in person nodes if graph[certifier['pubkey']] not in tuple(graph[person.pubkey]['nodes']): #Â add certifier node to person node @@ -337,7 +330,6 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): if new_arc: # add arc in graph graph[person.pubkey]['arcs'].append(arc) - print("CERTIFIED GRAPH LEN = %d " % len(graph[person.pubkey]['nodes'])) # if certified node not in person nodes if graph[certified['pubkey']] not in tuple(graph[person.pubkey]['nodes']): # add certified node to person node