pygui: initial changes to allow multiple wired links between nodes, updated to commonize logic for creating edges and adjustments in the UI for several edge related cases

This commit is contained in:
Blake Harnden 2020-10-12 20:28:27 -07:00
parent 96dddb687d
commit 29bd6ef7f8
5 changed files with 119 additions and 114 deletions

View file

@ -21,8 +21,10 @@ from core.gui.graph.edges import (
EDGE_WIDTH,
CanvasEdge,
CanvasWirelessEdge,
Edge,
arc_edges,
create_edge_token,
create_wireless_token,
)
from core.gui.graph.enums import GraphMode, ScaleOption
from core.gui.graph.node import CanvasNode
@ -69,9 +71,9 @@ class CanvasGraph(tk.Canvas):
self.selected: Optional[int] = None
self.node_draw: Optional[NodeDraw] = None
self.nodes: Dict[int, CanvasNode] = {}
self.edges: Dict[int, CanvasEdge] = {}
self.edges: Dict[str, CanvasEdge] = {}
self.shapes: Dict[int, Shape] = {}
self.wireless_edges: Dict[Tuple[int, ...], CanvasWirelessEdge] = {}
self.wireless_edges: Dict[str, CanvasWirelessEdge] = {}
# map wireless/EMANE node to the set of MDRs connected to that node
self.wireless_network: Dict[int, Set[int]] = {}
@ -206,14 +208,9 @@ class CanvasGraph(tk.Canvas):
iface_id = iface_throughput.iface_id
throughput = iface_throughput.throughput
iface_to_edge_id = (node_id, iface_id)
token = self.core.iface_to_edge.get(iface_to_edge_id)
if not token:
continue
edge = self.edges.get(token)
edge = self.core.iface_to_edge.get(iface_to_edge_id)
if edge:
edge.set_throughput(throughput)
else:
del self.core.iface_to_edge[iface_to_edge_id]
def draw_grid(self) -> None:
"""
@ -230,7 +227,7 @@ class CanvasGraph(tk.Canvas):
self.tag_lower(self.rect)
def add_wired_edge(self, src: CanvasNode, dst: CanvasNode, link: Link) -> None:
token = create_edge_token(src.id, dst.id)
token = create_edge_token(src.id, dst.id, link)
if token in self.edges and link.options.unidirectional:
edge = self.edges[token]
edge.asymmetric_link = link
@ -240,72 +237,50 @@ class CanvasGraph(tk.Canvas):
src_pos = (node1.position.x, node1.position.y)
dst_pos = (node2.position.x, node2.position.y)
edge = CanvasEdge(self, src.id, src_pos, dst_pos)
edge.linked_wireless = self.is_linked_wireless(src.id, dst.id)
edge.token = token
edge.dst = dst.id
edge.set_link(link)
edge.check_wireless()
src.edges.add(edge)
dst.edges.add(edge)
self.edges[edge.token] = edge
self.core.links[edge.token] = edge
if link.iface1:
iface1 = link.iface1
self.core.iface_to_edge[(node1.id, iface1.id)] = token
src.ifaces[iface1.id] = iface1
edge.src_iface = iface1
if link.iface2:
iface2 = link.iface2
self.core.iface_to_edge[(node2.id, iface2.id)] = edge.token
dst.ifaces[iface2.id] = iface2
edge.dst_iface = iface2
self.complete_edge(src, dst, edge)
def delete_wired_edge(self, src: CanvasNode, dst: CanvasNode) -> None:
token = create_edge_token(src.id, dst.id)
def delete_wired_edge(self, src: CanvasNode, dst: CanvasNode, link: Link) -> None:
token = create_edge_token(src.id, dst.id, link)
edge = self.edges.get(token)
if not edge:
return
self.delete_edge(edge)
if edge:
self.delete_edge(edge)
def update_wired_edge(self, src: CanvasNode, dst: CanvasNode, link: Link) -> None:
token = create_edge_token(src.id, dst.id)
token = create_edge_token(src.id, dst.id, link)
edge = self.edges.get(token)
if not edge:
return
edge.link.options = deepcopy(link.options)
if edge:
edge.link.options = deepcopy(link.options)
def add_wireless_edge(self, src: CanvasNode, dst: CanvasNode, link: Link) -> None:
network_id = link.network_id if link.network_id else None
token = create_edge_token(src.id, dst.id, network_id)
token = create_wireless_token(src.id, dst.id, network_id)
if token in self.wireless_edges:
logging.warning("ignoring link that already exists: %s", link)
return
src_pos = self.coords(src.id)
dst_pos = self.coords(dst.id)
edge = CanvasWirelessEdge(self, src.id, dst.id, src_pos, dst_pos, token, link)
edge = CanvasWirelessEdge(
self, src.id, dst.id, network_id, token, src_pos, dst_pos, link
)
self.wireless_edges[token] = edge
src.wireless_edges.add(edge)
dst.wireless_edges.add(edge)
self.tag_raise(src.id)
self.tag_raise(dst.id)
# update arcs when there are multiple links
common_edges = list(src.wireless_edges & dst.wireless_edges)
arc_edges(common_edges)
self.arc_common_edges(edge)
def delete_wireless_edge(
self, src: CanvasNode, dst: CanvasNode, link: Link
) -> None:
network_id = link.network_id if link.network_id else None
token = create_edge_token(src.id, dst.id, network_id)
token = create_wireless_token(src.id, dst.id, network_id)
if token not in self.wireless_edges:
return
edge = self.wireless_edges.pop(token)
edge.delete()
src.wireless_edges.remove(edge)
dst.wireless_edges.remove(edge)
# update arcs when there are multiple links
common_edges = list(src.wireless_edges & dst.wireless_edges)
arc_edges(common_edges)
self.arc_common_edges(edge)
def update_wireless_edge(
self, src: CanvasNode, dst: CanvasNode, link: Link
@ -313,7 +288,7 @@ class CanvasGraph(tk.Canvas):
if not link.label:
return
network_id = link.network_id if link.network_id else None
token = create_edge_token(src.id, dst.id, network_id)
token = create_wireless_token(src.id, dst.id, network_id)
if token not in self.wireless_edges:
self.add_wireless_edge(src, dst, link)
else:
@ -454,12 +429,6 @@ class CanvasGraph(tk.Canvas):
edge.delete()
return
# ignore repeated edges
token = create_edge_token(edge.src, self.selected)
if token in self.edges:
edge.delete()
return
# rj45 nodes can only support one link
if NodeUtils.is_rj45_node(src_node.core_node.type) and src_node.edges:
edge.delete()
@ -468,14 +437,15 @@ class CanvasGraph(tk.Canvas):
edge.delete()
return
# set dst node and snap edge to center
linked_wireless = self.is_linked_wireless(src_node.id, self.selected)
edge.complete(self.selected, linked_wireless)
# finalize edge creation
self.complete_edge(src_node, dst_node, edge)
self.edges[edge.token] = edge
src_node.edges.add(edge)
dst_node.edges.add(edge)
self.core.create_link(edge, src_node, dst_node)
def arc_common_edges(self, edge: Edge) -> None:
src_node = self.nodes[edge.src]
dst_node = self.nodes[edge.dst]
common_edges = list(src_node.edges & dst_node.edges)
common_edges += list(src_node.wireless_edges & dst_node.wireless_edges)
arc_edges(common_edges)
def select_object(self, object_id: int, choose_multiple: bool = False) -> None:
"""
@ -572,6 +542,7 @@ class CanvasGraph(tk.Canvas):
if dst_wireless:
src_node.delete_antenna()
self.core.deleted_canvas_edges([edge])
self.arc_common_edges(edge)
def zoom(self, event: tk.Event, factor: float = None) -> None:
if not factor:
@ -903,20 +874,41 @@ class CanvasGraph(tk.Canvas):
def is_selection_mode(self) -> bool:
return self.mode == GraphMode.SELECT
def create_edge(self, source: CanvasNode, dest: CanvasNode) -> None:
def create_edge(self, src: CanvasNode, dst: CanvasNode) -> CanvasEdge:
"""
create an edge between source node and destination node
"""
token = create_edge_token(source.id, dest.id)
if token not in self.edges:
pos = (source.core_node.position.x, source.core_node.position.y)
edge = CanvasEdge(self, source.id, pos, pos)
linked_wireless = self.is_linked_wireless(source.id, dest.id)
edge.complete(dest.id, linked_wireless)
self.edges[edge.token] = edge
self.nodes[source.id].edges.add(edge)
self.nodes[dest.id].edges.add(edge)
self.core.create_link(edge, source, dest)
pos = (src.core_node.position.x, src.core_node.position.y)
edge = CanvasEdge(self, src.id, pos, pos)
self.complete_edge(src, dst, edge)
return edge
def complete_edge(
self,
src: CanvasNode,
dst: CanvasNode,
edge: CanvasEdge,
link: Optional[Link] = None,
) -> None:
linked_wireless = self.is_linked_wireless(src.id, dst.id)
edge.complete(dst.id, linked_wireless)
src.edges.add(edge)
dst.edges.add(edge)
if link is None:
link = self.core.create_link(edge, src, dst)
if link.iface1:
iface1 = link.iface1
src.ifaces[iface1.id] = iface1
edge.src_iface = iface1
if link.iface2:
iface2 = link.iface2
dst.ifaces[iface2.id] = iface2
edge.dst_iface = iface2
edge.set_link(link)
edge.token = create_edge_token(src.id, dst.id, edge.link)
self.arc_common_edges(edge)
self.edges[edge.token] = edge
self.core.save_edge(edge, src, dst)
def copy(self) -> None:
if self.core.is_runtime():
@ -970,13 +962,12 @@ class CanvasGraph(tk.Canvas):
if edge.src not in to_copy_ids or edge.dst not in to_copy_ids:
if canvas_node.id == edge.src:
dst_node = self.nodes[edge.dst]
self.create_edge(node, dst_node)
token = create_edge_token(node.id, dst_node.id)
copy_edge = self.create_edge(node, dst_node)
elif canvas_node.id == edge.dst:
src_node = self.nodes[edge.src]
self.create_edge(src_node, node)
token = create_edge_token(src_node.id, node.id)
copy_edge = self.edges[token]
copy_edge = self.create_edge(src_node, node)
else:
continue
copy_link = copy_edge.link
iface1_id = copy_link.iface1.id if copy_link.iface1 else None
iface2_id = copy_link.iface2.id if copy_link.iface2 else None
@ -1003,13 +994,11 @@ class CanvasGraph(tk.Canvas):
# copy link and link config
for edge in to_copy_edges:
src_node_id = copy_map[edge.token[0]]
dst_node_id = copy_map[edge.token[1]]
src_node_id = copy_map[edge.src]
dst_node_id = copy_map[edge.dst]
src_node_copy = self.nodes[src_node_id]
dst_node_copy = self.nodes[dst_node_id]
self.create_edge(src_node_copy, dst_node_copy)
token = create_edge_token(src_node_copy.id, dst_node_copy.id)
copy_edge = self.edges[token]
copy_edge = self.create_edge(src_node_copy, dst_node_copy)
copy_link = copy_edge.link
iface1_id = copy_link.iface1.id if copy_link.iface1 else None
iface2_id = copy_link.iface2.id if copy_link.iface2 else None