From 5a8984de106d613e64d03b23069579c9abd2048b Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 1 May 2020 23:36:33 -0700 Subject: [PATCH] pygui some delete node/link cleanup and added unlink option to node context menu for an easier unlinking --- daemon/core/gui/coreclient.py | 24 +++++++++--------------- daemon/core/gui/graph/graph.py | 29 ++++++++++++++++++++++------- daemon/core/gui/graph/node.py | 18 ++++++++++++++++++ 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/daemon/core/gui/coreclient.py b/daemon/core/gui/coreclient.py index 8c05a30f..fc4fc64f 100644 --- a/daemon/core/gui/coreclient.py +++ b/daemon/core/gui/coreclient.py @@ -6,7 +6,7 @@ import logging import os from pathlib import Path from tkinter import messagebox -from typing import TYPE_CHECKING, Dict, List +from typing import TYPE_CHECKING, Dict, Iterable, List import grpc @@ -830,27 +830,21 @@ class CoreClient: ) return node - def delete_graph_nodes(self, canvas_nodes: List[core_pb2.Node]): + def deleted_graph_nodes(self, canvas_nodes: List[core_pb2.Node]): """ remove the nodes selected by the user and anything related to that node such as link, configurations, interfaces """ - edges = set() - removed_links = [] for canvas_node in canvas_nodes: node_id = canvas_node.core_node.id - if node_id not in self.canvas_nodes: - logging.error("unknown node: %s", node_id) - continue del self.canvas_nodes[node_id] - for edge in canvas_node.edges: - if edge in edges: - continue - edges.add(edge) - edge = self.links.pop(edge.token, None) - if edge is not None: - removed_links.append(edge.link) - self.interfaces_manager.removed(removed_links) + + def deleted_graph_edges(self, edges: Iterable[CanvasEdge]) -> None: + links = [] + for edge in edges: + del self.links[edge.token] + links.append(edge.link) + self.interfaces_manager.removed(links) def create_interface(self, canvas_node: CanvasNode) -> core_pb2.Interface: node = canvas_node.core_node diff --git a/daemon/core/gui/graph/graph.py b/daemon/core/gui/graph/graph.py index 9e60f131..22d21b51 100644 --- a/daemon/core/gui/graph/graph.py +++ b/daemon/core/gui/graph/graph.py @@ -517,15 +517,13 @@ class CanvasGraph(tk.Canvas): canvas_node.delete() nodes.append(canvas_node) is_wireless = NodeUtils.is_wireless_node(canvas_node.core_node.type) - # delete related edges for edge in canvas_node.edges: if edge in edges: continue edges.add(edge) - self.edges.pop(edge.token, None) + del self.edges[edge.token] edge.delete() - # update node connected to edge being deleted other_id = edge.src other_interface = edge.src_interface @@ -534,10 +532,8 @@ class CanvasGraph(tk.Canvas): other_interface = edge.dst_interface other_node = self.nodes[other_id] other_node.edges.remove(edge) - try: + if other_interface in other_node.interfaces: other_node.interfaces.remove(other_interface) - except ValueError: - pass if is_wireless: other_node.delete_antenna() @@ -547,7 +543,26 @@ class CanvasGraph(tk.Canvas): shape.delete() self.selection.clear() - self.core.delete_graph_nodes(nodes) + self.core.deleted_graph_nodes(nodes) + self.core.deleted_graph_edges(edges) + + def delete_edge(self, edge: CanvasEdge): + edge.delete() + del self.edges[edge.token] + src_node = self.nodes[edge.src] + src_node.edges.discard(edge) + if edge.src_interface in src_node.interfaces: + src_node.interfaces.remove(edge.src_interface) + dst_node = self.nodes[edge.dst] + dst_node.edges.discard(edge) + if edge.dst_interface in dst_node.interfaces: + dst_node.interfaces.remove(edge.dst_interface) + src_wireless = NodeUtils.is_wireless_node(src_node.core_node.type) + if src_wireless: + dst_node.delete_antenna() + dst_wireless = NodeUtils.is_wireless_node(dst_node.core_node.type) + if dst_wireless: + src_node.delete_antenna() def zoom(self, event: tk.Event, factor: float = None): if not factor: diff --git a/daemon/core/gui/graph/node.py b/daemon/core/gui/graph/node.py index 90896284..5b3aed10 100644 --- a/daemon/core/gui/graph/node.py +++ b/daemon/core/gui/graph/node.py @@ -1,3 +1,4 @@ +import functools import logging import tkinter as tk from typing import TYPE_CHECKING @@ -15,6 +16,7 @@ from core.gui.dialogs.nodeservice import NodeServiceDialog from core.gui.dialogs.wlanconfig import WlanConfigDialog from core.gui.errors import show_grpc_error from core.gui.graph import tags +from core.gui.graph.edges import CanvasEdge from core.gui.graph.tooltip import CanvasTooltip from core.gui.images import ImageEnum, Images from core.gui.nodeutils import ANTENNA_SIZE, NodeUtils @@ -230,6 +232,18 @@ class CanvasNode: label="Link To Selected", command=self.wireless_link_selected ) context.add_command(label="Select Members", state=tk.DISABLED) + unlink_menu = tk.Menu(context) + for edge in self.edges: + other_id = edge.src + if self.id == other_id: + other_id = edge.dst + other_node = self.canvas.nodes[other_id] + func_unlink = functools.partial(self.click_unlink, edge) + unlink_menu.add_command( + label=other_node.core_node.name, command=func_unlink + ) + themes.style_menu(unlink_menu) + context.add_cascade(label="Unlink", menu=unlink_menu) edit_menu = tk.Menu(context) themes.style_menu(edit_menu) edit_menu.add_command(label="Cut", command=self.click_cut) @@ -242,6 +256,10 @@ class CanvasNode: self.canvas_copy() self.canvas_delete() + def click_unlink(self, edge: CanvasEdge) -> None: + self.canvas.delete_edge(edge) + self.app.core.deleted_graph_edges([edge]) + def canvas_delete(self) -> None: self.canvas.clear_selection() self.canvas.selection[self.id] = self