From cbd593eed6034aa72c0b4d73bbfe1d1c60a44a72 Mon Sep 17 00:00:00 2001 From: Huy Pham <42948410+hpham@users.noreply.github.com> Date: Tue, 1 Oct 2019 16:25:26 -0700 Subject: [PATCH] finish the basics of toolbar and start working on simple grpc --- coretk/coretk/app.py | 17 ++++- coretk/coretk/coregrpc.py | 83 +++++++++++++++++++++++++ coretk/coretk/coretoolbar.py | 116 +++++++++++++++++------------------ coretk/coretk/graph.py | 105 +++++++++++++++++++++---------- coretk/coretk/images.py | 28 +++++++++ 5 files changed, 254 insertions(+), 95 deletions(-) create mode 100644 coretk/coretk/coregrpc.py diff --git a/coretk/coretk/app.py b/coretk/coretk/app.py index 1b27587f..9102f4d1 100644 --- a/coretk/coretk/app.py +++ b/coretk/coretk/app.py @@ -1,6 +1,8 @@ import logging import tkinter as tk +import coretk.images as images +from coretk.coregrpc import CoreGrpc from coretk.coremenubar import CoreMenubar from coretk.coretoolbar import CoreToolbar from coretk.graph import CanvasGraph @@ -13,11 +15,16 @@ class Application(tk.Frame): self.load_images() self.setup_app() self.menubar = None + self.canvas = None + self.core_grpc = CoreGrpc() self.create_menu() self.create_widgets() def load_images(self): - Images.load("core", "core-icon.png") + images.load_core_images(Images) + + def close_grpc(self): + self.core_grpc.close() def setup_app(self): self.master.title("CORE") @@ -40,11 +47,14 @@ class Application(tk.Frame): core_editbar.create_toolbar() self.canvas = CanvasGraph( - master=self, background="#cccccc", scrollregion=(0, 0, 1000, 1000) + grpc=self.core_grpc, + master=self, + background="#cccccc", + scrollregion=(0, 0, 1000, 1000), ) self.canvas.pack(fill=tk.BOTH, expand=True) - # self.canvas.create_rectangle(0, 0, 1000, 750, outline="#000000", fill="#ffffff", width=1) + core_editbar.update_canvas(self.canvas) scroll_x = tk.Scrollbar( self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview @@ -69,3 +79,4 @@ if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG) app = Application() app.mainloop() + app.close_grpc() diff --git a/coretk/coretk/coregrpc.py b/coretk/coretk/coregrpc.py new file mode 100644 index 00000000..268c3a13 --- /dev/null +++ b/coretk/coretk/coregrpc.py @@ -0,0 +1,83 @@ +""" +Incorporate grpc into python tkinter GUI +""" +import logging + +from core.api.grpc import client, core_pb2 + + +class CoreGrpc: + def __init__(self): + """ + Create a CoreGrpc instance + """ + self.core = client.CoreGrpcClient() + self.session_id = None + self.set_up() + + def log_event(self, event): + logging.info("event: %s", event) + + def set_up(self): + """ + Create session, handle events session may broadcast, change session state + + :return: nothing + """ + self.core.connect() + # create session + response = self.core.create_session() + logging.info("created session: %s", response) + + # handle events session may broadcast + self.session_id = response.session_id + self.core.events(self.session_id, self.log_event) + + # change session state + response = self.core.set_session_state( + self.session_id, core_pb2.SessionState.CONFIGURATION + ) + logging.info("set session state: %s", response) + + def get_session_id(self): + return self.session_id + + # TODO add checkings to the function + def add_node(self, x, y, node_name): + link_layer_nodes = ["switch", "hub", "wlan", "rj45", "tunnel"] + network_layer_nodes = ["default"] + node = None + if node_name in link_layer_nodes: + if node_name == "switch": + node = core_pb2.Node(type=core_pb2.NodeType.SWITCH) + elif node_name == "hub": + node = core_pb2.Node(type=core_pb2.NodeType.HUB) + elif node_name == "wlan": + node = core_pb2.Node(type=core_pb2.NodeType.WIRELESS_LAN) + elif node_name == "rj45": + node = core_pb2.Node(type=core_pb2.NodeType.RJ45) + elif node_name == "tunnel": + node = core_pb2.Node(type=core_pb2.NodeType.TUNNEL) + + elif node_name in network_layer_nodes: + position = core_pb2.Position(x=x, y=y) + node = core_pb2.Node(position=position) + else: + return + response = self.core.add_node(self.session_id, node) + logging.info("created %s: %s", node_name, response) + return response.node_id + + def edit_node(self, session_id, node_id, x, y): + position = core_pb2.Position(x=x, y=y) + response = self.core.edit_node(session_id, node_id, position) + logging.info("updated node id %s: %s", node_id, response) + + def close(self): + """ + Clean ups when done using grpc + + :return: nothing + """ + logging.debug("Close grpc") + self.core.close() diff --git a/coretk/coretk/coretoolbar.py b/coretk/coretk/coretoolbar.py index df646488..d4009f1b 100644 --- a/coretk/coretk/coretoolbar.py +++ b/coretk/coretk/coretoolbar.py @@ -36,57 +36,17 @@ class CoreToolbar(object): self.network_layer_option_menu = None # variables used by canvas graph - self.mode = GraphMode.SELECT + self.image_to_draw = None + self.canvas = None - def load_toolbar_images(self): + def update_canvas(self, canvas): """ - Load the images that appear in core toolbar + Update canvas variable in CoreToolbar class + :param tkinter.Canvas canvas: core canvas :return: nothing """ - Images.load("core", "core-icon.png") - Images.load("start", "start.gif") - Images.load("switch", "lanswitch.gif") - Images.load("marker", "marker.gif") - Images.load("router", "router.gif") - Images.load("select", "select.gif") - Images.load("link", "link.gif") - Images.load("hub", "hub.gif") - Images.load("wlan", "wlan.gif") - Images.load("rj45", "rj45.gif") - Images.load("tunnel", "tunnel.gif") - Images.load("oval", "oval.gif") - Images.load("rectangle", "rectangle.gif") - Images.load("text", "text.gif") - Images.load("host", "host.gif") - Images.load("pc", "pc.gif") - Images.load("mdr", "mdr.gif") - Images.load("prouter", "router_green.gif") - Images.load("ovs", "OVS.gif") - Images.load("editnode", "document-properties.gif") - Images.load("run", "run.gif") - Images.load("plot", "plot.gif") - Images.load("twonode", "twonode.gif") - Images.load("stop", "stop.gif") - Images.load("observe", "observe.gif") - - def get_graph_mode(self): - """ - Retrieve current graph mode - - :rtype: int - :return: current graph mode - """ - return self.mode - - def set_graph_mode(self, mode): - """ - Set graph mode - - :param int mode: graph mode - :return: nothing - """ - self.mode = mode + self.canvas = canvas def destroy_previous_frame(self): """ @@ -189,47 +149,67 @@ class CoreToolbar(object): def click_selection_tool(self): logging.debug("Click SELECTION TOOL") - self.set_graph_mode(GraphMode.SELECT) + self.canvas.mode = GraphMode.SELECT def click_start_stop_session_tool(self): logging.debug("Click START STOP SESSION button") self.destroy_children_widgets(self.edit_frame) + self.canvas.set_canvas_mode(GraphMode.SELECT) self.create_runtime_toolbar() def click_link_tool(self): logging.debug("Click LINK button") - self.set_graph_mode(GraphMode.EDGE) + self.canvas.set_canvas_mode(GraphMode.EDGE) def pick_router(self, main_button): + logging.debug("Pick router option") self.network_layer_option_menu.destroy() main_button.configure(image=Images.get("router")) - logging.debug("Pick router option") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("router")) + self.canvas.set_drawing_name("default") def pick_host(self, main_button): + logging.debug("Pick host option") self.network_layer_option_menu.destroy() main_button.configure(image=Images.get("host")) - logging.debug("Pick host option") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("host")) + self.canvas.set_drawing_name("default") def pick_pc(self, main_button): + logging.debug("Pick PC option") self.network_layer_option_menu.destroy() main_button.configure(image=Images.get("pc")) - logging.debug("Pick PC option") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("pc")) + self.canvas.set_drawing_name("default") def pick_mdr(self, main_button): + logging.debug("Pick MDR option") self.network_layer_option_menu.destroy() main_button.configure(image=Images.get("mdr")) - logging.debug("Pick MDR option") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("mdr")) + self.canvas.set_drawing_name("default") def pick_prouter(self, main_button): + logging.debug("Pick prouter option") self.network_layer_option_menu.destroy() main_button.configure(image=Images.get("prouter")) - logging.debug("Pick prouter option") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("prouter")) + self.canvas.set_drawing_name("default") def pick_ovs(self, main_button): + logging.debug("Pick OVS option") self.network_layer_option_menu.destroy() main_button.configure(image=Images.get("ovs")) - logging.debug("Pick OVS option") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("ovs")) + self.canvas.set_drawing_name("default") + # TODO what graph node is this def pick_editnode(self, main_button): self.network_layer_option_menu.destroy() main_button.configure(image=Images.get("editnode")) @@ -311,29 +291,43 @@ class CoreToolbar(object): CreateToolTip(network_layer_button, "Network-layer virtual nodes") def pick_hub(self, main_button): + logging.debug("Pick link-layer node HUB") self.link_layer_option_menu.destroy() main_button.configure(image=Images.get("hub")) - logging.debug("Pick link-layer node HUB") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("hub")) + self.canvas.set_drawing_name("hub") def pick_switch(self, main_button): + logging.debug("Pick link-layer node SWITCH") self.link_layer_option_menu.destroy() main_button.configure(image=Images.get("switch")) - logging.debug("Pick link-layer node SWITCH") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("switch")) + self.canvas.set_drawing_name("switch") def pick_wlan(self, main_button): + logging.debug("Pick link-layer node WLAN") self.link_layer_option_menu.destroy() main_button.configure(image=Images.get("wlan")) - logging.debug("Pick link-layer node WLAN") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("wlan")) + self.canvas.set_drawing_name("wlan") def pick_rj45(self, main_button): + logging.debug("Pick link-layer node RJ45") self.link_layer_option_menu.destroy() main_button.configure(image=Images.get("rj45")) - logging.debug("Pick link-layer node RJ45") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("rj45")) def pick_tunnel(self, main_button): + logging.debug("Pick link-layer node TUNNEL") self.link_layer_option_menu.destroy() main_button.configure(image=Images.get("tunnel")) - logging.debug("Pick link-layer node TUNNEL") + self.canvas.set_canvas_mode(GraphMode.PICKNODE) + self.canvas.set_drawing_image(Images.get("tunnel")) + self.canvas.set_drawing_image(Images.get("tunnel")) def draw_link_layer_options(self, link_layer_button): """ @@ -482,7 +476,7 @@ class CoreToolbar(object): CreateToolTip(marker_main_button, "background annotation tools") def create_toolbar(self): - self.load_toolbar_images() + # self.load_toolbar_images() self.create_regular_button( self.edit_frame, Images.get("start"), @@ -508,6 +502,7 @@ class CoreToolbar(object): self.create_network_layer_button() self.create_link_layer_button() self.create_marker_button() + self.radio_value.set(1) def create_observe_button(self): menu_button = tk.Menubutton( @@ -599,3 +594,4 @@ class CoreToolbar(object): self.create_regular_button( self.edit_frame, Images.get("run"), self.click_run_button, "run" ) + self.exec_radio_value.set(1) diff --git a/coretk/coretk/graph.py b/coretk/coretk/graph.py index bf85b8cb..06f16488 100644 --- a/coretk/coretk/graph.py +++ b/coretk/coretk/graph.py @@ -2,23 +2,25 @@ import enum import logging import tkinter as tk -from coretk.images import Images - class GraphMode(enum.Enum): SELECT = 0 EDGE = 1 - NODE = 2 + PICKNODE = 2 + NODE = 3 + OTHER = 4 class CanvasGraph(tk.Canvas): - def __init__(self, master=None, cnf=None, **kwargs): + def __init__(self, grpc=None, master=None, cnf=None, **kwargs): if cnf is None: cnf = {} kwargs["highlightthickness"] = 0 super().__init__(master, cnf, **kwargs) - + self.core_grpc = grpc self.mode = GraphMode.SELECT + self.draw_node_image = None + self.draw_node_name = None self.selected = None self.node_context = None self.nodes = {} @@ -29,6 +31,15 @@ class CanvasGraph(tk.Canvas): self.setup_bindings() self.draw_grid() + def set_canvas_mode(self, mode): + self.mode = mode + + def set_drawing_image(self, img): + self.draw_node_image = img + + def set_drawing_name(self, name): + self.draw_node_name = name + def draw_grid(self, width=1000, height=750): """ Create grid @@ -70,9 +81,9 @@ class CanvasGraph(tk.Canvas): self.bind("", self.click_release) self.bind("", self.click_motion) self.bind("", self.context) - self.bind("e", self.set_mode) - self.bind("s", self.set_mode) - self.bind("n", self.set_mode) + # self.bind("e", self.set_mode) + # self.bind("s", self.set_mode) + # self.bind("n", self.set_mode) def canvas_xy(self, event): """ @@ -124,7 +135,9 @@ class CanvasGraph(tk.Canvas): self.handle_edge_release(event) elif self.mode == GraphMode.NODE: x, y = self.canvas_xy(event) - self.add_node(x, y, "switch") + self.add_node(x, y, self.draw_node_image, self.draw_node_name) + elif self.mode == GraphMode.PICKNODE: + self.mode = GraphMode.NODE def handle_edge_release(self, event): edge = self.drawing_edge @@ -194,25 +207,39 @@ class CanvasGraph(tk.Canvas): logging.debug(f"node context: {selected}") self.node_context.post(event.x_root, event.y_root) - def set_mode(self, event): - """ - Set canvas mode according to the hot key that has been pressed + # def set_mode(self, event): + # """ + # Set canvas mode according to the hot key that has been pressed + # + # :param event: key event + # :return: nothing + # """ + # logging.debug(f"mode event: {event}") + # if event.char == "e": + # self.mode = GraphMode.EDGE + # elif event.char == "s": + # self.mode = GraphMode.SELECT + # elif event.char == "n": + # self.mode = GraphMode.NODE + # logging.debug(f"graph mode: {self.mode}") - :param event: key event - :return: nothing - """ - logging.debug(f"mode event: {event}") - if event.char == "e": - self.mode = GraphMode.EDGE - elif event.char == "s": - self.mode = GraphMode.SELECT - elif event.char == "n": - self.mode = GraphMode.NODE - logging.debug(f"graph mode: {self.mode}") + # def add_node(self, x, y, image_name): + # image = Images.get(image_name) + # node = CanvasNode(x, y, image, self) + # self.nodes[node.id] = node + # return node - def add_node(self, x, y, image_name): - image = Images.get(image_name) - node = CanvasNode(x, y, image, self) + def add_node(self, x, y, image, node_name): + core_session_id = self.core_grpc.get_session_id() + core_node_id = self.core_grpc.add_node(int(x), int(y), node_name) + node = CanvasNode( + core_session_id=core_session_id, + core_node_id=core_node_id, + x=x, + y=y, + image=image, + canvas=self, + ) self.nodes[node.id] = node return node @@ -250,22 +277,23 @@ class CanvasEdge: self.canvas.coords(self.id, x1, y1, x, y) self.canvas.lift(self.src) self.canvas.lift(self.dst) - # self.canvas.create_line(0,0,10,10) - # print(x1,y1,x,y) - # self.canvas.create_line(x1+1, y1+1, x+1, y+1) def delete(self): self.canvas.delete(self.id) class CanvasNode: - def __init__(self, x, y, image, canvas): + def __init__(self, core_session_id, core_node_id, x, y, image, canvas): self.image = image self.canvas = canvas self.id = self.canvas.create_image( x, y, anchor=tk.CENTER, image=self.image, tags="node" ) - self.name = f"Node {self.id}" + self.x_coord = x + self.y_coord = y + self.core_session_id = core_session_id + self.core_node_id = core_node_id + self.name = f"Node {self.core_node_id}" self.text_id = self.canvas.create_text(x, y + 20, text=self.name) self.canvas.tag_bind(self.id, "", self.click_press) self.canvas.tag_bind(self.id, "", self.click_release) @@ -274,16 +302,29 @@ class CanvasNode: self.edges = set() self.moving = None + def get_coords(self): + return self.x_coord, self.y_coord + + def update_coords(self): + self.x_coord, self.y_coord = self.canvas.coords(self.id) + def click_press(self, event): logging.debug(f"click press {self.name}: {event}") self.moving = self.canvas.canvas_xy(event) def click_release(self, event): logging.debug(f"click release {self.name}: {event}") + self.update_coords() + self.canvas.core_grpc.edit_node( + self.core_session_id, + self.core_node_id, + int(self.x_coord), + int(self.y_coord), + ) self.moving = None def motion(self, event): - if self.canvas.mode == GraphMode.EDGE: + if self.canvas.mode == GraphMode.EDGE or self.canvas.mode == GraphMode.NODE: return x, y = self.canvas.canvas_xy(event) moving_x, moving_y = self.moving diff --git a/coretk/coretk/images.py b/coretk/coretk/images.py index 4ca2b5ac..71758cc2 100644 --- a/coretk/coretk/images.py +++ b/coretk/coretk/images.py @@ -18,3 +18,31 @@ class Images: @classmethod def get(cls, name): return cls.images[name] + + +def load_core_images(images): + images.load("core", "core-icon.png") + images.load("start", "start.gif") + images.load("switch", "lanswitch.gif") + images.load("marker", "marker.gif") + images.load("router", "router.gif") + images.load("select", "select.gif") + images.load("link", "link.gif") + images.load("hub", "hub.gif") + images.load("wlan", "wlan.gif") + images.load("rj45", "rj45.gif") + images.load("tunnel", "tunnel.gif") + images.load("oval", "oval.gif") + images.load("rectangle", "rectangle.gif") + images.load("text", "text.gif") + images.load("host", "host.gif") + images.load("pc", "pc.gif") + images.load("mdr", "mdr.gif") + images.load("prouter", "router_green.gif") + images.load("ovs", "OVS.gif") + images.load("editnode", "document-properties.gif") + images.load("run", "run.gif") + images.load("plot", "plot.gif") + images.load("twonode", "twonode.gif") + images.load("stop", "stop.gif") + images.load("observe", "observe.gif")