pygui: refactored how edges determine if they are linked wireless, removed wireless network tracking that was not being used by the canvas manager, added helper function to nodes to check if they are of wireless type

This commit is contained in:
Blake Harnden 2021-01-03 22:08:09 -08:00
parent 63282134f5
commit 685b21924c
3 changed files with 42 additions and 69 deletions

View file

@ -12,7 +12,7 @@ from core.gui.dialogs.linkconfig import LinkConfigurationDialog
from core.gui.frames.link import EdgeInfoFrame, WirelessEdgeInfoFrame from core.gui.frames.link import EdgeInfoFrame, WirelessEdgeInfoFrame
from core.gui.graph import tags from core.gui.graph import tags
from core.gui.images import ImageEnum from core.gui.images import ImageEnum
from core.gui.nodeutils import ICON_SIZE, NodeUtils from core.gui.nodeutils import ICON_SIZE
from core.gui.utils import bandwidth_text, delay_jitter_text from core.gui.utils import bandwidth_text, delay_jitter_text
if TYPE_CHECKING: if TYPE_CHECKING:
@ -175,6 +175,9 @@ class Edge:
self.dst_label2: Optional[int] = None self.dst_label2: Optional[int] = None
self.color: str = EDGE_COLOR self.color: str = EDGE_COLOR
self.width: int = EDGE_WIDTH self.width: int = EDGE_WIDTH
self.linked_wireless: bool = False
if self.dst:
self.linked_wireless = self.src.is_wireless() or self.dst.is_wireless()
def scaled_width(self) -> float: def scaled_width(self) -> float:
return self.width * self.app.app_scale return self.width * self.app.app_scale
@ -213,14 +216,14 @@ class Edge:
common_edges += list(self.src.wireless_edges & self.dst.wireless_edges) common_edges += list(self.src.wireless_edges & self.dst.wireless_edges)
arc_edges(common_edges) arc_edges(common_edges)
def is_same_canvas(self) -> bool: def has_shadows(self) -> bool:
# actively drawing same canvas link # still drawing
if not self.dst: if not self.dst:
return True return False
return self.src.canvas == self.dst.canvas return self.src.canvas != self.dst.canvas
def draw(self, state: str) -> None: def draw(self, state: str) -> None:
if self.is_same_canvas(): if not self.has_shadows():
self.id = self.draw_edge(self.src.canvas, self.src, self.src, state) self.id = self.draw_edge(self.src.canvas, self.src, self.src, state)
else: else:
# draw shadow nodes and 2 lines # draw shadow nodes and 2 lines
@ -258,7 +261,7 @@ class Edge:
def redraw(self) -> None: def redraw(self) -> None:
self.src.canvas.itemconfig(self.id, width=self.scaled_width(), fill=self.color) self.src.canvas.itemconfig(self.id, width=self.scaled_width(), fill=self.color)
self.move_src() self.move_src()
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.itemconfig( self.dst.canvas.itemconfig(
self.id2, width=self.scaled_width(), fill=self.color self.id2, width=self.scaled_width(), fill=self.color
) )
@ -276,7 +279,7 @@ class Edge:
justify=tk.CENTER, justify=tk.CENTER,
state=self.manager.show_link_labels.state(), state=self.manager.show_link_labels.state(),
) )
if not self.is_same_canvas(): if self.has_shadows():
_, _, x, y, _, _ = self.dst.canvas.coords(self.id2) _, _, x, y, _, _ = self.dst.canvas.coords(self.id2)
self.middle_label2 = self.dst.canvas.create_text( self.middle_label2 = self.dst.canvas.create_text(
x, x,
@ -289,13 +292,13 @@ class Edge:
) )
else: else:
self.src.canvas.itemconfig(self.middle_label, text=text) self.src.canvas.itemconfig(self.middle_label, text=text)
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.itemconfig(self.middle_label2, text=text) self.dst.canvas.itemconfig(self.middle_label2, text=text)
def clear_middle_label(self) -> None: def clear_middle_label(self) -> None:
self.src.canvas.delete(self.middle_label) self.src.canvas.delete(self.middle_label)
self.middle_label = None self.middle_label = None
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.delete(self.middle_label2) self.dst.canvas.delete(self.middle_label2)
self.middle_label2 = None self.middle_label2 = None
@ -311,7 +314,7 @@ class Edge:
tags=tags.LINK_LABEL, tags=tags.LINK_LABEL,
state=self.manager.show_link_labels.state(), state=self.manager.show_link_labels.state(),
) )
if not self.is_same_canvas(): if self.has_shadows():
src_x, src_y, _, _, dst_x, dst_y = self.dst.canvas.coords(self.id2) src_x, src_y, _, _, dst_x, dst_y = self.dst.canvas.coords(self.id2)
src_pos, _ = node_label_positions(src_x, src_y, dst_x, dst_y) src_pos, _ = node_label_positions(src_x, src_y, dst_x, dst_y)
self.src_label2 = self.dst.canvas.create_text( self.src_label2 = self.dst.canvas.create_text(
@ -324,7 +327,7 @@ class Edge:
) )
else: else:
self.src.canvas.itemconfig(self.src_label, text=text) self.src.canvas.itemconfig(self.src_label, text=text)
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.itemconfig(self.src_label2, text=text) self.dst.canvas.itemconfig(self.src_label2, text=text)
def dst_label_text(self, text: str) -> None: def dst_label_text(self, text: str) -> None:
@ -339,7 +342,7 @@ class Edge:
tags=tags.LINK_LABEL, tags=tags.LINK_LABEL,
state=self.manager.show_link_labels.state(), state=self.manager.show_link_labels.state(),
) )
if not self.is_same_canvas(): if self.has_shadows():
src_x, src_y, _, _, dst_x, dst_y = self.dst.canvas.coords(self.id2) src_x, src_y, _, _, dst_x, dst_y = self.dst.canvas.coords(self.id2)
_, dst_pos = node_label_positions(src_x, src_y, dst_x, dst_y) _, dst_pos = node_label_positions(src_x, src_y, dst_x, dst_y)
self.dst_label2 = self.dst.canvas.create_text( self.dst_label2 = self.dst.canvas.create_text(
@ -352,7 +355,7 @@ class Edge:
) )
else: else:
self.src.canvas.itemconfig(self.dst_label, text=text) self.src.canvas.itemconfig(self.dst_label, text=text)
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.itemconfig(self.dst_label2, text=text) self.dst.canvas.itemconfig(self.dst_label2, text=text)
def drawing(self, pos: Tuple[float, float]) -> None: def drawing(self, pos: Tuple[float, float]) -> None:
@ -384,7 +387,7 @@ class Edge:
def move_dst(self) -> None: def move_dst(self) -> None:
dst_pos = self.dst.position() dst_pos = self.dst.position()
if self.is_same_canvas(): if not self.has_shadows():
src_x, src_y, _, _, _, _ = self.dst.canvas.coords(self.id) src_x, src_y, _, _, _, _ = self.dst.canvas.coords(self.id)
src_pos = src_x, src_y src_pos = src_x, src_y
self.moved(src_pos, dst_pos) self.moved(src_pos, dst_pos)
@ -498,7 +501,6 @@ class CanvasEdge(Edge):
self.text_src: Optional[int] = None self.text_src: Optional[int] = None
self.text_dst: Optional[int] = None self.text_dst: Optional[int] = None
self.link: Optional[Link] = None self.link: Optional[Link] = None
self.linked_wireless: bool = False
self.asymmetric_link: Optional[Link] = None self.asymmetric_link: Optional[Link] = None
self.throughput: Optional[float] = None self.throughput: Optional[float] = None
self.draw(tk.NORMAL) self.draw(tk.NORMAL)
@ -511,7 +513,7 @@ class CanvasEdge(Edge):
show_context = functools.partial(self.show_context, self.src.canvas) show_context = functools.partial(self.show_context, self.src.canvas)
self.src.canvas.tag_bind(self.id, "<ButtonRelease-3>", show_context) self.src.canvas.tag_bind(self.id, "<ButtonRelease-3>", show_context)
self.src.canvas.tag_bind(self.id, "<Button-1>", self.show_info) self.src.canvas.tag_bind(self.id, "<Button-1>", self.show_info)
if self.dst and not self.is_same_canvas(): if self.dst and self.has_shadows():
show_context = functools.partial(self.show_context, self.dst.canvas) show_context = functools.partial(self.show_context, self.dst.canvas)
self.dst.canvas.tag_bind(self.id2, "<ButtonRelease-3>", show_context) self.dst.canvas.tag_bind(self.id2, "<ButtonRelease-3>", show_context)
self.dst.canvas.tag_bind(self.id2, "<Button-1>", self.show_info) self.dst.canvas.tag_bind(self.id2, "<Button-1>", self.show_info)
@ -554,16 +556,16 @@ class CanvasEdge(Edge):
if self.link.options.loss == EDGE_LOSS: if self.link.options.loss == EDGE_LOSS:
state = tk.HIDDEN state = tk.HIDDEN
self.src.canvas.addtag_withtag(tags.LOSS_EDGES, self.id) self.src.canvas.addtag_withtag(tags.LOSS_EDGES, self.id)
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.addtag_withtag(tags.LOSS_EDGES, self.id2) self.dst.canvas.addtag_withtag(tags.LOSS_EDGES, self.id2)
else: else:
state = tk.NORMAL state = tk.NORMAL
self.src.canvas.dtag(self.id, tags.LOSS_EDGES) self.src.canvas.dtag(self.id, tags.LOSS_EDGES)
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.dtag(self.id2, tags.LOSS_EDGES) self.dst.canvas.dtag(self.id2, tags.LOSS_EDGES)
if self.manager.show_loss_links.state() == tk.HIDDEN: if self.manager.show_loss_links.state() == tk.HIDDEN:
self.src.canvas.itemconfigure(self.id, state=state) self.src.canvas.itemconfigure(self.id, state=state)
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.itemconfigure(self.id2, state=state) self.dst.canvas.itemconfigure(self.id2, state=state)
def set_throughput(self, throughput: float) -> None: def set_throughput(self, throughput: float) -> None:
@ -577,7 +579,7 @@ class CanvasEdge(Edge):
color = self.color color = self.color
width = self.scaled_width() width = self.scaled_width()
self.src.canvas.itemconfig(self.id, fill=color, width=width) self.src.canvas.itemconfig(self.id, fill=color, width=width)
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.itemconfig(self.id2, fill=color, width=width) self.dst.canvas.itemconfig(self.id2, fill=color, width=width)
def clear_throughput(self) -> None: def clear_throughput(self) -> None:
@ -585,9 +587,9 @@ class CanvasEdge(Edge):
if not self.linked_wireless: if not self.linked_wireless:
self.draw_link_options() self.draw_link_options()
def complete(self, dst: "CanvasNode", linked_wireless: bool) -> None: def complete(self, dst: "CanvasNode") -> None:
self.dst = dst self.dst = dst
self.linked_wireless = linked_wireless self.linked_wireless = self.src.is_wireless() or self.dst.is_wireless()
self.move_dst() self.move_dst()
self.check_wireless() self.check_wireless()
logging.debug("draw wired link from node %s to node %s", self.src, dst) logging.debug("draw wired link from node %s to node %s", self.src, dst)
@ -597,30 +599,21 @@ class CanvasEdge(Edge):
return return
self.src.canvas.itemconfig(self.id, state=tk.HIDDEN) self.src.canvas.itemconfig(self.id, state=tk.HIDDEN)
self.src.canvas.dtag(self.id, tags.EDGE) self.src.canvas.dtag(self.id, tags.EDGE)
self._check_antenna() if self.has_shadows():
if not self.is_same_canvas():
self.dst.canvas.itemconfig(self.id2, state=tk.HIDDEN) self.dst.canvas.itemconfig(self.id2, state=tk.HIDDEN)
self.dst.canvas.dtag(self.id2, tags.EDGE) self.dst.canvas.dtag(self.id2, tags.EDGE)
self._check_antenna() if self.src.is_wireless() and not self.dst.is_wireless():
self.dst.add_antenna()
def _check_antenna(self) -> None: elif not self.src.is_wireless() and self.dst.is_wireless():
src_node_type = self.src.core_node.type self.src.add_antenna()
dst_node_type = self.dst.core_node.type else:
is_src_wireless = NodeUtils.is_wireless_node(src_node_type) self.src.add_antenna()
is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type)
if is_src_wireless or is_dst_wireless:
if is_src_wireless and not is_dst_wireless:
self.dst.add_antenna()
elif not is_src_wireless and is_dst_wireless:
self.src.add_antenna()
else:
self.src.add_antenna()
def reset(self) -> None: def reset(self) -> None:
self.src.canvas.delete(self.middle_label) self.src.canvas.delete(self.middle_label)
self.middle_label = None self.middle_label = None
self.src.canvas.itemconfig(self.id, fill=self.color, width=self.scaled_width()) self.src.canvas.itemconfig(self.id, fill=self.color, width=self.scaled_width())
if not self.is_same_canvas(): if self.has_shadows():
self.dst.canvas.delete(self.middle_label2) self.dst.canvas.delete(self.middle_label2)
self.middle_label2 = None self.middle_label2 = None
self.dst.canvas.itemconfig( self.dst.canvas.itemconfig(
@ -691,11 +684,9 @@ class CanvasEdge(Edge):
del self.src.ifaces[self.link.iface1.id] del self.src.ifaces[self.link.iface1.id]
if self.link.iface2: if self.link.iface2:
del self.dst.ifaces[self.link.iface2.id] del self.dst.ifaces[self.link.iface2.id]
src_wireless = NodeUtils.is_wireless_node(self.src.core_node.type) if self.src.is_wireless():
if src_wireless:
self.dst.delete_antenna() self.dst.delete_antenna()
dst_wireless = NodeUtils.is_wireless_node(self.dst.core_node.type) if self.dst.is_wireless():
if dst_wireless:
self.src.delete_antenna() self.src.delete_antenna()
self.app.core.deleted_canvas_edges([self]) self.app.core.deleted_canvas_edges([self])
super().delete() super().delete()

View file

@ -2,7 +2,7 @@ import logging
import tkinter as tk import tkinter as tk
from copy import deepcopy from copy import deepcopy
from tkinter import BooleanVar, messagebox, ttk from tkinter import BooleanVar, messagebox, ttk
from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Tuple, ValuesView from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, ValuesView
from core.api.grpc.wrappers import Link, LinkType, Node, Session, ThroughputsEvent from core.api.grpc.wrappers import Link, LinkType, Node, Session, ThroughputsEvent
from core.gui.graph import tags from core.gui.graph import tags
@ -52,9 +52,7 @@ class CanvasManager:
self.node_draw: Optional[NodeDraw] = None self.node_draw: Optional[NodeDraw] = None
self.canvases: Dict[int, CanvasGraph] = {} self.canvases: Dict[int, CanvasGraph] = {}
# canvas object storage # global edge management
# TODO: validate this
self.wireless_network: Dict[int, Set[int]] = {}
self.edges: Dict[str, CanvasEdge] = {} self.edges: Dict[str, CanvasEdge] = {}
self.wireless_edges: Dict[str, CanvasWirelessEdge] = {} self.wireless_edges: Dict[str, CanvasWirelessEdge] = {}
@ -361,8 +359,7 @@ class CanvasManager:
self, edge: CanvasEdge, dst: CanvasNode, link: Optional[Link] = None self, edge: CanvasEdge, dst: CanvasNode, link: Optional[Link] = None
) -> None: ) -> None:
src = edge.src src = edge.src
linked_wireless = self.is_linked_wireless(src, dst) edge.complete(dst)
edge.complete(dst, linked_wireless)
if link is None: if link is None:
link = self.core.create_link(edge, src, dst) link = self.core.create_link(edge, src, dst)
edge.link = link edge.link = link
@ -381,23 +378,5 @@ class CanvasManager:
self.edges[edge.token] = edge self.edges[edge.token] = edge
self.core.save_edge(edge, src, dst) self.core.save_edge(edge, src, dst)
edge.src.canvas.organize() edge.src.canvas.organize()
if not edge.is_same_canvas(): if edge.has_shadows():
edge.dst.canvas.organize() edge.dst.canvas.organize()
def is_linked_wireless(self, src: CanvasNode, dst: CanvasNode) -> bool:
src_node_type = src.core_node.type
dst_node_type = dst.core_node.type
is_src_wireless = NodeUtils.is_wireless_node(src_node_type)
is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type)
# update the wlan/EMANE network
wlan_network = self.wireless_network
if is_src_wireless and not is_dst_wireless:
if src not in wlan_network:
wlan_network[src.core_node.id] = set()
wlan_network[src.core_node.id].add(dst.core_node.id)
elif not is_src_wireless and is_dst_wireless:
if dst not in wlan_network:
wlan_network[dst.core_node.id] = set()
wlan_network[dst.core_node.id].add(src.core_node.id)
return is_src_wireless or is_dst_wireless

View file

@ -406,3 +406,6 @@ class CanvasNode:
return False return False
# valid link # valid link
return True return True
def is_wireless(self) -> bool:
return NodeUtils.is_wireless_node(self.core_node.type)