From 3c7bf57b5cf736c1c45e7ea921a9cd33a0ca0c53 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 27 Nov 2019 14:25:29 -0800 Subject: [PATCH 1/4] simplified select logic to check against known nodes and modified get_selected to avoid returning the canvas id --- coretk/coretk/graph.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/coretk/coretk/graph.py b/coretk/coretk/graph.py index 274073df..d9b9e1e3 100644 --- a/coretk/coretk/graph.py +++ b/coretk/coretk/graph.py @@ -238,19 +238,15 @@ class CanvasGraph(tk.Canvas): :return: the item that the mouse point to """ overlapping = self.find_overlapping(event.x, event.y, event.x, event.y) - nodes = set(self.find_withtag("node")) selected = None for _id in overlapping: if self.drawing_edge and self.drawing_edge.id == _id: continue - if _id in nodes: + if _id in self.nodes: selected = _id break - if selected is None: - selected = _id - return selected def click_release(self, event): @@ -362,9 +358,7 @@ class CanvasGraph(tk.Canvas): self.core.delete_graph_nodes(nodes) def add_node(self, x, y): - plot_id = self.find_all()[0] - logging.info("add node event: %s - %s", plot_id, self.selected) - if self.selected == plot_id: + if self.selected is None: core_node = self.core.create_node( int(x), int(y), self.node_draw.node_type, self.node_draw.model ) @@ -648,7 +642,7 @@ class CanvasNode: self.moving = None def motion(self, event): - if self.canvas.mode == GraphMode.EDGE or self.canvas.mode == GraphMode.NODE: + if self.canvas.mode == GraphMode.EDGE: return x, y = self.canvas.canvas_xy(event) self.move(x, y) From 693d7beeb77bef8c569c350dc497c69daa2434ae Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 27 Nov 2019 15:40:54 -0800 Subject: [PATCH 2/4] updated remove antenna logic to simplify, updated wireless edges to be objects --- coretk/coretk/coreclient.py | 16 +++++++-- coretk/coretk/graph.py | 51 +++++++++++++++++++++++---- coretk/coretk/nodedelete.py | 53 ++++++----------------------- coretk/coretk/wirelessconnection.py | 51 --------------------------- 4 files changed, 69 insertions(+), 102 deletions(-) delete mode 100644 coretk/coretk/wirelessconnection.py diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index 1671a0fe..fec00a73 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -121,13 +121,12 @@ class CoreClient: def handle_events(self, event): if event.HasField("link_event"): logging.info("link event: %s", event) - self.app.canvas.wireless_draw.handle_link_event(event.link_event) + self.handle_link_event(event.link_event) elif event.HasField("session_event"): logging.info("session event: %s", event) session_event = event.session_event if session_event.event <= core_pb2.SessionState.SHUTDOWN: self.state = event.session_event.event - # mobility start elif session_event.event in {7, 8, 9}: node_id = session_event.node_id dialog = self.mobility_players.get(node_id) @@ -145,6 +144,19 @@ class CoreClient: else: logging.info("unhandled event: %s", event) + def handle_link_event(self, event): + node_one_id = event.link.node_one_id + node_two_id = event.link.node_two_id + canvas_node_one = self.canvas_nodes[node_one_id] + canvas_node_two = self.canvas_nodes[node_two_id] + + if event.message_type == core_pb2.MessageType.ADD: + self.app.canvas.add_wireless_edge(canvas_node_one, canvas_node_two) + elif event.message_type == core_pb2.MessageType.DELETE: + self.app.canvas.delete_wireless_edge(canvas_node_one, canvas_node_two) + else: + logging.warning("unknown link event: %s", event.message_type) + def handle_node_event(self, event): if event.source == "gui": return diff --git a/coretk/coretk/graph.py b/coretk/coretk/graph.py index d9b9e1e3..6c38b83c 100644 --- a/coretk/coretk/graph.py +++ b/coretk/coretk/graph.py @@ -17,7 +17,6 @@ from coretk.images import Images from coretk.linkinfo import LinkInfo, Throughput from coretk.nodedelete import CanvasComponentManagement from coretk.nodeutils import NodeUtils -from coretk.wirelessconnection import WirelessConnection NODE_TEXT_OFFSET = 5 @@ -50,6 +49,7 @@ class CanvasGraph(tk.Canvas): self.context = None self.nodes = {} self.edges = {} + self.wireless_edges = {} self.drawing_edge = None self.grid = None self.canvas_management = CanvasComponentManagement(self, core) @@ -58,7 +58,6 @@ class CanvasGraph(tk.Canvas): self.core = core self.helper = GraphHelper(self, core) self.throughput_draw = Throughput(self, core) - self.wireless_draw = WirelessConnection(self, core) # background related self.wallpaper_id = None @@ -120,8 +119,8 @@ class CanvasGraph(tk.Canvas): self.selected = None self.nodes.clear() self.edges.clear() + self.wireless_edges.clear() self.drawing_edge = None - self.wireless_draw.map.clear() self.draw_session(session) def setup_bindings(self): @@ -162,6 +161,25 @@ class CanvasGraph(tk.Canvas): self.tag_lower("gridline") self.tag_lower(self.grid) + def add_wireless_edge(self, src, dst): + token = tuple(sorted((src.id, dst.id))) + x1, y1 = self.coords(src.id) + x2, y2 = self.coords(dst.id) + position = (x1, y1, x2, y2) + edge = CanvasWirelessEdge(token, position, src.id, dst.id, self) + 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) + + def delete_wireless_edge(self, src, dst): + token = tuple(sorted((src.id, dst.id))) + edge = self.wireless_edges.pop(token) + edge.delete() + src.wireless_edges.remove(edge) + dst.wireless_edges.remove(edge) + def draw_session(self, session): """ Draw existing session. @@ -187,7 +205,7 @@ class CanvasGraph(tk.Canvas): canvas_node_two = self.core.canvas_nodes[link.node_two_id] node_two = canvas_node_two.core_node if link.type == core_pb2.LinkType.WIRELESS: - self.wireless_draw.add_connection(link.node_one_id, link.node_two_id) + self.add_wireless_edge(canvas_node_one, canvas_node_two) else: is_node_one_wireless = NodeUtils.is_wireless_node(node_one.type) is_node_two_wireless = NodeUtils.is_wireless_node(node_two.type) @@ -492,6 +510,20 @@ class CanvasGraph(tk.Canvas): self.itemconfig("gridline", state=tk.HIDDEN) +class CanvasWirelessEdge: + def __init__(self, token, position, src, dst, canvas): + self.token = token + self.src = src + self.dst = dst + self.canvas = canvas + self.id = self.canvas.create_line( + *position, tags="wireless", width=1.5, fill="#009933" + ) + + def delete(self): + self.canvas.delete(self.id) + + class CanvasEdge: """ Canvas edge class @@ -580,7 +612,7 @@ class CanvasNode: self.canvas.tag_bind(self.id, "", self.on_leave) self.edges = set() self.interfaces = [] - self.wlans = [] + self.wireless_edges = set() self.moving = None def redraw(self): @@ -605,7 +637,14 @@ class CanvasNode: else: self.canvas.coords(edge.id, x1, y1, x, y) edge.link_info.recalculate_info() - self.canvas.helper.update_wlan_connection(old_x, old_y, x, y, self.wlans) + for edge in self.wireless_edges: + x1, y1, x2, y2 = self.canvas.coords(edge.id) + if edge.src == self.id: + self.canvas.coords(edge.id, x, y, x2, y2) + else: + self.canvas.coords(edge.id, x1, y1, x, y) + if self.app.core.is_runtime(): + self.app.core.edit_node(self.core_node.id, int(x), int(y)) def on_enter(self, event): if self.app.core.is_runtime() and self.app.core.observer: diff --git a/coretk/coretk/nodedelete.py b/coretk/coretk/nodedelete.py index 341f95ef..a4de5f0d 100644 --- a/coretk/coretk/nodedelete.py +++ b/coretk/coretk/nodedelete.py @@ -1,7 +1,7 @@ """ manage deletion """ -from core.api.grpc import core_pb2 +from coretk.nodeutils import NodeUtils class CanvasComponentManagement: @@ -48,48 +48,6 @@ class CanvasComponentManagement: edges = set() nodes = [] - node_to_wlink = {} - for link_tuple in self.canvas.wireless_draw.map: - nid_one, nid_two = link_tuple - if nid_one not in node_to_wlink: - node_to_wlink[nid_one] = [] - if nid_two not in node_to_wlink: - node_to_wlink[nid_two] = [] - node_to_wlink[nid_one].append(link_tuple) - node_to_wlink[nid_two].append(link_tuple) - - # delete antennas and wireless links - for cnid in self.selected: - canvas_node = self.canvas.nodes[cnid] - if canvas_node.core_node.type != core_pb2.NodeType.WIRELESS_LAN: - canvas_node.antenna_draw.delete_antennas() - else: - for e in canvas_node.edges: - link_proto = self.app.links[e.token] - node_one_id, node_two_id = ( - link_proto.node_one_id, - link_proto.node_two_id, - ) - if node_one_id == canvas_node.core_node.id: - neighbor_id = node_two_id - else: - neighbor_id = node_one_id - neighbor = self.app.canvas_nodes[neighbor_id] - if neighbor.core_node.type != core_pb2.NodeType.WIRELESS_LAN: - neighbor.antenna_draw.delete_antenna() - - for link_tuple in node_to_wlink.get(canvas_node.core_node.id, []): - nid_one, nid_two = link_tuple - if link_tuple in self.canvas.wireless_draw.map: - self.canvas.delete(self.canvas.wireless_draw.map[link_tuple]) - link_cid = self.canvas.wireless_draw.map.pop(link_tuple, None) - canvas_node_one = self.app.canvas_nodes[nid_one] - canvas_node_two = self.app.canvas_nodes[nid_two] - if link_cid in canvas_node_one.wlans: - canvas_node_one.wlans.remove(link_cid) - if link_cid in canvas_node_two.wlans: - canvas_node_two.wlans.remove(link_cid) - for node_id in list(self.selected): bbox_id = self.selected[node_id] canvas_node = self.canvas.nodes.pop(node_id) @@ -97,6 +55,13 @@ class CanvasComponentManagement: self.canvas.delete(node_id) self.canvas.delete(bbox_id) self.canvas.delete(canvas_node.text_id) + + # delete antennas + is_wireless = NodeUtils.is_wireless_node(canvas_node.core_node.type) + if is_wireless: + canvas_node.antenna_draw.delete_antennas() + + # delete related edges for edge in canvas_node.edges: if edge in edges: continue @@ -116,5 +81,7 @@ class CanvasComponentManagement: other_node.interfaces.remove(other_interface) except ValueError: pass + if is_wireless: + other_node.antenna_draw.delete_antenna() self.selected.clear() return nodes diff --git a/coretk/coretk/wirelessconnection.py b/coretk/coretk/wirelessconnection.py deleted file mode 100644 index dd51723b..00000000 --- a/coretk/coretk/wirelessconnection.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Wireless connection handler -""" -from core.api.grpc import core_pb2 - - -class WirelessConnection: - def __init__(self, canvas, core): - self.canvas = canvas - self.core = core - # map a (node_one_id, node_two_id) to a wlan canvas id - self.map = {} - - def add_connection(self, node_one_id, node_two_id): - canvas_node_one = self.core.canvas_nodes[node_one_id] - canvas_node_two = self.core.canvas_nodes[node_two_id] - key = tuple(sorted((node_one_id, node_two_id))) - if key not in self.map: - x1, y1 = self.canvas.coords(canvas_node_one.id) - x2, y2 = self.canvas.coords(canvas_node_two.id) - wlan_canvas_id = self.canvas.create_line( - x1, y1, x2, y2, fill="#009933", tags="wireless", width=1.5 - ) - self.map[key] = wlan_canvas_id - canvas_node_one.wlans.append(wlan_canvas_id) - canvas_node_two.wlans.append(wlan_canvas_id) - else: - print("in map") - self.canvas.itemconfig(self.map[key], state="normal") - - def delete_connection(self, node_one_id, node_two_id): - canvas_node_one = self.core.canvas_nodes[node_one_id] - canvas_node_two = self.core.canvas_nodes[node_two_id] - key = tuple(sorted((node_one_id, node_two_id))) - wlan_canvas_id = self.map[key] - canvas_node_one.wlans.remove(wlan_canvas_id) - canvas_node_two.wlans.remove(wlan_canvas_id) - self.canvas.delete(wlan_canvas_id) - self.map.pop(key, None) - - def handle_link_event(self, link_event): - if link_event.message_type == core_pb2.MessageType.ADD: - self.add_connection( - link_event.link.node_one_id, link_event.link.node_two_id - ) - self.canvas.tag_raise("node") - - if link_event.message_type == core_pb2.MessageType.DELETE: - self.delete_connection( - link_event.link.node_one_id, link_event.link.node_two_id - ) From b30b8ab83de6d4bd494fbcd21e10a0b93592be6a Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 27 Nov 2019 16:14:14 -0800 Subject: [PATCH 3/4] updated status bar text to be centered --- coretk/coretk/status.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/coretk/coretk/status.py b/coretk/coretk/status.py index ea31d6fc..c4263e85 100644 --- a/coretk/coretk/status.py +++ b/coretk/coretk/status.py @@ -28,16 +28,20 @@ class StatusBar(ttk.Frame): self.progress_bar = ttk.Progressbar( self, orient="horizontal", mode="indeterminate" ) - self.progress_bar.grid(row=0, column=0, sticky="nsew") - self.status = ttk.Label(self, textvariable=self.statusvar) + self.progress_bar.grid(row=0, column=0, sticky="ew") + + self.status = ttk.Label(self, textvariable=self.statusvar, anchor=tk.CENTER) self.statusvar.set("status") - self.status.grid(row=0, column=1, sticky="nsew") - self.zoom = ttk.Label(self, text="zoom") - self.zoom.grid(row=0, column=2) - self.cpu_usage = ttk.Label(self, text="cpu usage") - self.cpu_usage.grid(row=0, column=3) - self.emulation_light = ttk.Label(self, text="emulation light") - self.emulation_light.grid(row=0, column=4) + self.status.grid(row=0, column=1, sticky="ew") + + self.zoom = ttk.Label(self, text="zoom", anchor=tk.CENTER) + self.zoom.grid(row=0, column=2, sticky="ew") + + self.cpu_usage = ttk.Label(self, text="cpu usage", anchor=tk.CENTER) + self.cpu_usage.grid(row=0, column=3, sticky="ew") + + self.emulation_light = ttk.Label(self, text="emulation light", anchor=tk.CENTER) + self.emulation_light.grid(row=0, column=4, sticky="ew") def start_session_callback(self, process_time): num_nodes = len(self.app.core.canvas_nodes) From 6a8e0c8360a523faa2904eca8ba26deffa5cffef Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 27 Nov 2019 16:27:53 -0800 Subject: [PATCH 4/4] fixed app quit when grpc fails, fixed quitting when not stopping the running session --- coretk/coretk/menuaction.py | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/coretk/coretk/menuaction.py b/coretk/coretk/menuaction.py index 5b1cec9e..d8dc89cb 100644 --- a/coretk/coretk/menuaction.py +++ b/coretk/coretk/menuaction.py @@ -8,6 +8,8 @@ import time import webbrowser from tkinter import filedialog, messagebox +import grpc + from core.api.grpc import core_pb2 from coretk.appconfig import XML_PATH from coretk.dialogs.canvasbackground import CanvasBackgroundDialog @@ -30,6 +32,7 @@ class MenuAction: self.app = app def cleanup_old_session(self, quitapp=False): + logging.info("cleaning up old session") start = time.time() self.app.core.stop_session() self.app.core.delete_session() @@ -47,27 +50,31 @@ class MenuAction: logging.info( "menuaction.py: clean_nodes_links_and_set_configuration() Exiting the program" ) - state = self.app.core.get_session_state() + try: + state = self.app.core.get_session_state() - if ( - state == core_pb2.SessionState.SHUTDOWN - or state == core_pb2.SessionState.DEFINITION - ): - self.app.core.delete_session() - if quitapp: - self.app.quit() - else: - msgbox = messagebox.askyesnocancel("stop", "Stop the running session?") - if msgbox or msgbox is False: - if msgbox: + if ( + state == core_pb2.SessionState.SHUTDOWN + or state == core_pb2.SessionState.DEFINITION + ): + self.app.core.delete_session() + if quitapp: + self.app.quit() + else: + result = messagebox.askyesnocancel("stop", "Stop the running session?") + if result: self.app.statusbar.progress_bar.start(5) thread = threading.Thread( target=self.cleanup_old_session, args=([quitapp]) ) + thread.daemon = True thread.start() - - # self.app.core.stop_session() - # self.app.core.delete_session() + elif quitapp: + self.app.quit() + except grpc.RpcError: + logging.error("error getting session state") + if quitapp: + self.app.quit() def on_quit(self, event=None): """ @@ -76,7 +83,6 @@ class MenuAction: :return: nothing """ self.prompt_save_running_session(quitapp=True) - # self.app.quit() def file_save_as_xml(self, event=None): logging.info("menuaction.py file_save_as_xml()")