diff --git a/daemon/core/gui/data/icons/observe.gif b/daemon/core/gui/data/icons/observe.gif deleted file mode 100644 index 6b66e730..00000000 Binary files a/daemon/core/gui/data/icons/observe.gif and /dev/null differ diff --git a/daemon/core/gui/data/icons/observe.png b/daemon/core/gui/data/icons/observe.png new file mode 100644 index 00000000..e32005da Binary files /dev/null and b/daemon/core/gui/data/icons/observe.png differ diff --git a/daemon/core/gui/dialogs/observers.py b/daemon/core/gui/dialogs/observers.py index 6911e1b8..d1812b64 100644 --- a/daemon/core/gui/dialogs/observers.py +++ b/daemon/core/gui/dialogs/observers.py @@ -104,7 +104,8 @@ class ObserverDialog(Dialog): self.observers.insert(tk.END, name) self.name.set("") self.cmd.set("") - self.app.menubar.draw_custom_observers() + self.app.menubar.observers_menu.draw_custom() + self.app.toolbar.observers_menu.draw_custom() else: messagebox.showerror("Observer Error", f"{name} already exists") @@ -132,7 +133,8 @@ class ObserverDialog(Dialog): self.observers.selection_clear(0, tk.END) self.save_button.config(state=tk.DISABLED) self.delete_button.config(state=tk.DISABLED) - self.app.menubar.draw_custom_observers() + self.app.menubar.observers_menu.draw_custom() + self.app.toolbar.observers_menu.draw_custom() def handle_observer_change(self, event: tk.Event): selection = self.observers.curselection() diff --git a/daemon/core/gui/menubar.py b/daemon/core/gui/menubar.py index 69db0092..62a9ceae 100644 --- a/daemon/core/gui/menubar.py +++ b/daemon/core/gui/menubar.py @@ -23,23 +23,13 @@ from core.gui.dialogs.sessionoptions import SessionOptionsDialog from core.gui.dialogs.sessions import SessionsDialog from core.gui.dialogs.throughput import ThroughputDialog from core.gui.nodeutils import ICON_SIZE +from core.gui.observers import ObserversMenu from core.gui.task import ProgressTask if TYPE_CHECKING: from core.gui.app import Application MAX_FILES = 3 -OBSERVERS = { - "List Processes": "ps", - "Show Interfaces": "ip address", - "IPV4 Routes": "ip -4 route", - "IPV6 Routes": "ip -6 route", - "Listening Sockets": "ss -tuwnl", - "IPv4 MFC Entries": "ip -4 mroute show", - "IPv6 MFC Entries": "ip -6 mroute show", - "Firewall Rules": "iptables -L", - "IPSec Policies": "setkey -DP", -} class Menubar(tk.Menu): @@ -58,8 +48,6 @@ class Menubar(tk.Menu): self.recent_menu = None self.edit_menu = None self.observers_menu = None - self.observers_var = tk.StringVar(value=tk.NONE) - self.observers_custom_index = None self.draw() def draw(self) -> None: @@ -201,42 +189,9 @@ class Menubar(tk.Menu): """ Create observer widget menu item and create the sub menu items inside """ - self.observers_menu = tk.Menu(widget_menu) - self.observers_menu.add_command( - label="Edit Observers", command=self.click_edit_observer_widgets - ) - self.observers_menu.add_separator() - self.observers_menu.add_radiobutton( - label="None", - variable=self.observers_var, - value="none", - command=lambda: self.core.set_observer(None), - ) - for name in sorted(OBSERVERS): - cmd = OBSERVERS[name] - self.observers_menu.add_radiobutton( - label=name, - variable=self.observers_var, - value=name, - command=partial(self.core.set_observer, cmd), - ) - self.observers_custom_index = self.observers_menu.index(tk.END) + 1 - self.draw_custom_observers() + self.observers_menu = ObserversMenu(widget_menu, self.app) widget_menu.add_cascade(label="Observer Widgets", menu=self.observers_menu) - def draw_custom_observers(self) -> None: - current_observers_index = self.observers_menu.index(tk.END) + 1 - if self.observers_custom_index < current_observers_index: - self.observers_menu.delete(self.observers_custom_index, tk.END) - for name in sorted(self.core.custom_observers): - observer = self.core.custom_observers[name] - self.observers_menu.add_radiobutton( - label=name, - variable=self.observers_var, - value=name, - command=partial(self.core.set_observer, observer.cmd), - ) - def create_adjacency_menu(self, widget_menu: tk.Menu) -> None: """ Create adjacency menu item and the sub menu items inside diff --git a/daemon/core/gui/observers.py b/daemon/core/gui/observers.py new file mode 100644 index 00000000..27d0a26e --- /dev/null +++ b/daemon/core/gui/observers.py @@ -0,0 +1,66 @@ +import tkinter as tk +from functools import partial +from typing import TYPE_CHECKING + +from core.gui.dialogs.observers import ObserverDialog + +if TYPE_CHECKING: + from core.gui.app import Application + +OBSERVERS = { + "List Processes": "ps", + "Show Interfaces": "ip address", + "IPV4 Routes": "ip -4 route", + "IPV6 Routes": "ip -6 route", + "Listening Sockets": "ss -tuwnl", + "IPv4 MFC Entries": "ip -4 mroute show", + "IPv6 MFC Entries": "ip -6 mroute show", + "Firewall Rules": "iptables -L", + "IPSec Policies": "setkey -DP", +} + + +class ObserversMenu(tk.Menu): + def __init__(self, master: tk.BaseWidget, app: "Application") -> None: + super().__init__(master) + self.app = app + self.observer = tk.StringVar(value=tk.NONE) + self.custom_index = 0 + self.draw() + + def draw(self) -> None: + self.add_command(label="Edit Observers", command=self.click_edit) + self.add_separator() + self.add_radiobutton( + label="None", + variable=self.observer, + value="none", + command=lambda: self.app.core.set_observer(None), + ) + for name in sorted(OBSERVERS): + cmd = OBSERVERS[name] + self.add_radiobutton( + label=name, + variable=self.observer, + value=name, + command=partial(self.app.core.set_observer, cmd), + ) + self.custom_index = self.index(tk.END) + 1 + self.draw_custom() + + def draw_custom(self) -> None: + current_index = self.index(tk.END) + 1 + if self.custom_index < current_index: + self.delete(self.custom_index, tk.END) + for name in sorted(self.app.core.custom_observers): + observer = self.app.core.custom_observers[name] + self.add_radiobutton( + label=name, + variable=self.observer, + value=name, + command=partial(self.app.core.set_observer, observer.cmd), + ) + + def click_edit(self) -> None: + dialog = ObserverDialog(self.app) + dialog.show() diff --git a/daemon/core/gui/toolbar.py b/daemon/core/gui/toolbar.py index da20948e..54fac126 100644 --- a/daemon/core/gui/toolbar.py +++ b/daemon/core/gui/toolbar.py @@ -15,6 +15,7 @@ from core.gui.graph.enums import GraphMode from core.gui.graph.shapeutils import ShapeType, is_marker from core.gui.images import ImageEnum from core.gui.nodeutils import NodeDraw, NodeUtils +from core.gui.observers import ObserversMenu from core.gui.task import ProgressTask from core.gui.themes import Styles from core.gui.tooltip import Tooltip @@ -184,6 +185,9 @@ class Toolbar(ttk.Frame): self.marker_frame = None self.picker = None + # observers + self.observers_menu = None + # these variables help keep track of what images being drawn so that scaling # is possible since PhotoImage does not have resize method self.current_node = NodeUtils.NODES[0] @@ -244,6 +248,7 @@ class Toolbar(ttk.Frame): self.runtime_select_button = self.runtime_frame.create_button( ImageEnum.SELECT, self.click_runtime_selection, "Selection Tool", radio=True ) + self.create_observe_button() self.runtime_marker_button = self.runtime_frame.create_button( ImageEnum.MARKER, self.click_marker_button, "Marker Tool", radio=True ) @@ -381,25 +386,10 @@ class Toolbar(ttk.Frame): menu_button = ttk.Menubutton( self.runtime_frame, image=image, direction=tk.RIGHT ) + menu_button.image = image menu_button.grid(sticky="ew") - menu = tk.Menu(menu_button, tearoff=0) - menu_button["menu"] = menu - menu.add_command(label="None") - menu.add_command(label="processes") - menu.add_command(label="ifconfig") - menu.add_command(label="IPv4 routes") - menu.add_command(label="IPv6 routes") - menu.add_command(label="OSPFv2 neighbors") - menu.add_command(label="OSPFv3 neighbors") - menu.add_command(label="Listening sockets") - menu.add_command(label="IPv4 MFC entries") - menu.add_command(label="IPv6 MFC entries") - menu.add_command(label="firewall rules") - menu.add_command(label="IPSec policies") - menu.add_command(label="docker logs") - menu.add_command(label="OSPFv3 MDR level") - menu.add_command(label="PIM neighbors") - menu.add_command(label="Edit...") + self.observers_menu = ObserversMenu(menu_button, self.app) + menu_button["menu"] = self.observers_menu def click_stop(self) -> None: """