fix merge conflict
This commit is contained in:
commit
22e773df1b
13 changed files with 396 additions and 281 deletions
|
@ -40,7 +40,7 @@ class Application(tk.Frame):
|
|||
def setup_app(self):
|
||||
self.master.title("CORE")
|
||||
self.master.geometry("1000x800")
|
||||
image = Images.get(ImageEnum.CORE.value)
|
||||
image = Images.get(ImageEnum.CORE)
|
||||
self.master.tk.call("wm", "iconphoto", self.master._w, image)
|
||||
self.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
|
|
95
coretk/coretk/configutils.py
Normal file
95
coretk/coretk/configutils.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
import enum
|
||||
import logging
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
|
||||
class ConfigType(enum.Enum):
|
||||
STRING = 10
|
||||
BOOL = 11
|
||||
|
||||
|
||||
def create_config(master, config, padx=2, pady=2):
|
||||
"""
|
||||
Creates a scrollable canvas with an embedded window for displaying configuration
|
||||
options. Will use grid layout to consume row 0 and columns 0-2.
|
||||
|
||||
:param master: master to add scrollable canvas to
|
||||
:param dict config: config option mapping keys to config options
|
||||
:param int padx: x padding for widgets
|
||||
:param int pady: y padding for widgets
|
||||
:return: widget value mapping
|
||||
"""
|
||||
master.rowconfigure(0, weight=1)
|
||||
master.columnconfigure(0, weight=1)
|
||||
master.columnconfigure(1, weight=1)
|
||||
|
||||
canvas = tk.Canvas(master, highlightthickness=0)
|
||||
canvas.grid(row=0, columnspan=2, sticky="nsew", padx=padx, pady=pady)
|
||||
canvas.columnconfigure(0, weight=1)
|
||||
canvas.rowconfigure(0, weight=1)
|
||||
|
||||
scroll_y = tk.Scrollbar(master, orient="vertical", command=canvas.yview)
|
||||
scroll_y.grid(row=0, column=2, sticky="ns")
|
||||
|
||||
frame = tk.Frame(canvas, padx=padx, pady=pady)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=3)
|
||||
|
||||
values = {}
|
||||
for index, key in enumerate(sorted(config)):
|
||||
option = config[key]
|
||||
label = tk.Label(frame, text=option.label)
|
||||
label.grid(row=index, pady=pady, padx=padx, sticky="ew")
|
||||
value = tk.StringVar()
|
||||
config_type = ConfigType(option.type)
|
||||
if config_type == ConfigType.BOOL:
|
||||
select = tuple(option.select)
|
||||
combobox = ttk.Combobox(frame, textvariable=value, values=select)
|
||||
combobox.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
if option.value == "1":
|
||||
value.set("On")
|
||||
else:
|
||||
value.set("Off")
|
||||
elif config_type == ConfigType.STRING:
|
||||
entry = tk.Entry(frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
else:
|
||||
logging.error("unhandled config option type: %s", config_type)
|
||||
values[key] = value
|
||||
|
||||
frame_id = canvas.create_window(0, 0, anchor="nw", window=frame)
|
||||
canvas.update_idletasks()
|
||||
canvas.configure(scrollregion=canvas.bbox("all"), yscrollcommand=scroll_y.set)
|
||||
|
||||
frame.bind(
|
||||
"<Configure>", lambda event: canvas.configure(scrollregion=canvas.bbox("all"))
|
||||
)
|
||||
canvas.bind(
|
||||
"<Configure>", lambda event: canvas.itemconfig(frame_id, width=event.width)
|
||||
)
|
||||
|
||||
return values
|
||||
|
||||
|
||||
def parse_config(options, values):
|
||||
"""
|
||||
Given a set of configurations, parse out values and transform them when needed.
|
||||
|
||||
:param dict options: option key mapping to configuration options
|
||||
:param dict values: option key mapping to widget values
|
||||
:return:
|
||||
"""
|
||||
config = {}
|
||||
for key in options:
|
||||
option = options[key]
|
||||
value = values[key]
|
||||
config_type = ConfigType(option.type)
|
||||
config_value = value.get()
|
||||
if config_type == ConfigType.BOOL:
|
||||
if config_value == "On":
|
||||
config_value = "1"
|
||||
else:
|
||||
config_value = "0"
|
||||
config[key] = config_value
|
||||
return config
|
|
@ -6,8 +6,8 @@ import os
|
|||
from collections import OrderedDict
|
||||
|
||||
from core.api.grpc import client, core_pb2
|
||||
from coretk.dialogs.sessions import SessionsDialog
|
||||
from coretk.linkinfo import Throughput
|
||||
from coretk.querysessiondrawing import SessionTable
|
||||
from coretk.wirelessconnection import WirelessConnection
|
||||
|
||||
|
||||
|
@ -18,12 +18,9 @@ class CoreGrpc:
|
|||
"""
|
||||
self.core = client.CoreGrpcClient()
|
||||
self.session_id = sid
|
||||
|
||||
self.node_ids = []
|
||||
|
||||
self.app = app
|
||||
self.master = app.master
|
||||
|
||||
# self.set_up()
|
||||
self.interface_helper = None
|
||||
self.throughput_draw = Throughput(app.canvas, self)
|
||||
self.wireless_draw = WirelessConnection(app.canvas, self)
|
||||
|
@ -64,16 +61,6 @@ class CoreGrpc:
|
|||
self.core.events(self.session_id, self.log_event)
|
||||
# self.core.throughputs(self.log_throughput)
|
||||
|
||||
def query_existing_sessions(self, sessions):
|
||||
"""
|
||||
Query for existing sessions and prompt to join one
|
||||
|
||||
:param repeated core_pb2.SessionSummary sessions: summaries of all the existing sessions
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
SessionTable(self, self.master)
|
||||
|
||||
def delete_session(self, custom_sid=None):
|
||||
if custom_sid is None:
|
||||
sid = self.session_id
|
||||
|
@ -102,18 +89,15 @@ class CoreGrpc:
|
|||
:return: existing sessions
|
||||
"""
|
||||
self.core.connect()
|
||||
|
||||
response = self.core.get_sessions()
|
||||
# logging.info("coregrpc.py: all sessions: %s", response)
|
||||
|
||||
# if there are no sessions, create a new session, else join a session
|
||||
sessions = response.sessions
|
||||
|
||||
if len(sessions) == 0:
|
||||
self.create_new_session()
|
||||
else:
|
||||
|
||||
self.query_existing_sessions(sessions)
|
||||
dialog = SessionsDialog(self.app, self.app)
|
||||
dialog.show()
|
||||
|
||||
def get_session_state(self):
|
||||
response = self.core.get_session(self.session_id)
|
||||
|
|
|
@ -594,7 +594,7 @@ class CoreMenubar(object):
|
|||
|
||||
session_menu.add_command(
|
||||
label="Change sessions...",
|
||||
command=action.session_change_sessions,
|
||||
command=self.menu_action.session_change_sessions,
|
||||
underline=0,
|
||||
)
|
||||
|
||||
|
@ -620,7 +620,7 @@ class CoreMenubar(object):
|
|||
underline=0,
|
||||
)
|
||||
session_menu.add_command(
|
||||
label="Options...", command=action.session_options, underline=0
|
||||
label="Options...", command=self.menu_action.session_options, underline=0
|
||||
)
|
||||
|
||||
self.menubar.add_cascade(label="Session", menu=session_menu, underline=0)
|
||||
|
|
|
@ -200,55 +200,55 @@ class CoreToolbar(object):
|
|||
def pick_router(self, main_button):
|
||||
logging.debug("Pick router option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.ROUTER.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.ROUTER))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.ROUTER.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.ROUTER)
|
||||
self.canvas.draw_node_name = "router"
|
||||
|
||||
def pick_host(self, main_button):
|
||||
logging.debug("Pick host option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.HOST.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.HOST))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.HOST.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.HOST)
|
||||
self.canvas.draw_node_name = "host"
|
||||
|
||||
def pick_pc(self, main_button):
|
||||
logging.debug("Pick PC option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.PC.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.PC))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.PC.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.PC)
|
||||
self.canvas.draw_node_name = "PC"
|
||||
|
||||
def pick_mdr(self, main_button):
|
||||
logging.debug("Pick MDR option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.MDR.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.MDR))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.MDR.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.MDR)
|
||||
self.canvas.draw_node_name = "mdr"
|
||||
|
||||
def pick_prouter(self, main_button):
|
||||
logging.debug("Pick prouter option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.PROUTER.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.PROUTER))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.PROUTER.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.PROUTER)
|
||||
self.canvas.draw_node_name = "prouter"
|
||||
|
||||
def pick_ovs(self, main_button):
|
||||
logging.debug("Pick OVS option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.OVS.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.OVS))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.OVS.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.OVS)
|
||||
self.canvas.draw_node_name = "OVS"
|
||||
|
||||
# TODO what graph node is this
|
||||
def pick_editnode(self, main_button):
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.EDITNODE.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.EDITNODE))
|
||||
logging.debug("Pick editnode option")
|
||||
|
||||
def draw_network_layer_options(self, network_layer_button):
|
||||
|
@ -262,13 +262,13 @@ class CoreToolbar(object):
|
|||
self.destroy_previous_frame()
|
||||
option_frame = tk.Frame(self.master, padx=1, pady=1)
|
||||
img_list = [
|
||||
Images.get(ImageEnum.ROUTER.value),
|
||||
Images.get(ImageEnum.HOST.value),
|
||||
Images.get(ImageEnum.PC.value),
|
||||
Images.get(ImageEnum.MDR.value),
|
||||
Images.get(ImageEnum.PROUTER.value),
|
||||
Images.get(ImageEnum.OVS.value),
|
||||
Images.get(ImageEnum.EDITNODE.value),
|
||||
Images.get(ImageEnum.ROUTER),
|
||||
Images.get(ImageEnum.HOST),
|
||||
Images.get(ImageEnum.PC),
|
||||
Images.get(ImageEnum.MDR),
|
||||
Images.get(ImageEnum.PROUTER),
|
||||
Images.get(ImageEnum.OVS),
|
||||
Images.get(ImageEnum.EDITNODE),
|
||||
]
|
||||
func_list = [
|
||||
self.pick_router,
|
||||
|
@ -312,7 +312,7 @@ class CoreToolbar(object):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
router_image = Images.get(ImageEnum.ROUTER.value)
|
||||
router_image = Images.get(ImageEnum.ROUTER)
|
||||
network_layer_button = tk.Radiobutton(
|
||||
self.edit_frame,
|
||||
indicatoron=False,
|
||||
|
@ -329,41 +329,41 @@ class CoreToolbar(object):
|
|||
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(ImageEnum.HUB.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.HUB))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.HUB.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.HUB)
|
||||
self.canvas.draw_node_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(ImageEnum.SWITCH.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.SWITCH))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.SWITCH.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.SWITCH)
|
||||
self.canvas.draw_node_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(ImageEnum.WLAN.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.WLAN))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.WLAN.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.WLAN)
|
||||
self.canvas.draw_node_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(ImageEnum.RJ45.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.RJ45))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.RJ45.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.RJ45)
|
||||
self.canvas.draw_node_name = "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(ImageEnum.TUNNEL.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.TUNNEL))
|
||||
self.canvas.mode = GraphMode.PICKNODE
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.TUNNEL.value)
|
||||
self.canvas.draw_node_image = Images.get(ImageEnum.TUNNEL)
|
||||
self.canvas.draw_node_name = "tunnel"
|
||||
|
||||
def pick_emane(self, main_button):
|
||||
|
@ -431,7 +431,7 @@ class CoreToolbar(object):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
hub_image = Images.get(ImageEnum.HUB.value)
|
||||
hub_image = Images.get(ImageEnum.HUB)
|
||||
link_layer_button = tk.Radiobutton(
|
||||
self.edit_frame,
|
||||
indicatoron=False,
|
||||
|
@ -447,22 +447,22 @@ class CoreToolbar(object):
|
|||
|
||||
def pick_marker(self, main_button):
|
||||
self.marker_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.MARKER.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.MARKER))
|
||||
logging.debug("Pick MARKER")
|
||||
|
||||
def pick_oval(self, main_button):
|
||||
self.marker_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.OVAL.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.OVAL))
|
||||
logging.debug("Pick OVAL")
|
||||
|
||||
def pick_rectangle(self, main_button):
|
||||
self.marker_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.RECTANGLE.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.RECTANGLE))
|
||||
logging.debug("Pick RECTANGLE")
|
||||
|
||||
def pick_text(self, main_button):
|
||||
self.marker_option_menu.destroy()
|
||||
main_button.configure(image=Images.get(ImageEnum.TEXT.value))
|
||||
main_button.configure(image=Images.get(ImageEnum.TEXT))
|
||||
logging.debug("Pick TEXT")
|
||||
|
||||
def draw_marker_options(self, main_button):
|
||||
|
@ -476,10 +476,10 @@ class CoreToolbar(object):
|
|||
self.destroy_previous_frame()
|
||||
option_frame = tk.Frame(self.master, padx=1, pady=1)
|
||||
img_list = [
|
||||
Images.get(ImageEnum.MARKER.value),
|
||||
Images.get(ImageEnum.OVAL.value),
|
||||
Images.get(ImageEnum.RECTANGLE.value),
|
||||
Images.get(ImageEnum.TEXT.value),
|
||||
Images.get(ImageEnum.MARKER),
|
||||
Images.get(ImageEnum.OVAL),
|
||||
Images.get(ImageEnum.RECTANGLE),
|
||||
Images.get(ImageEnum.TEXT),
|
||||
]
|
||||
func_list = [
|
||||
self.pick_marker,
|
||||
|
@ -508,7 +508,7 @@ class CoreToolbar(object):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
marker_image = Images.get(ImageEnum.MARKER.value)
|
||||
marker_image = Images.get(ImageEnum.MARKER)
|
||||
marker_main_button = tk.Radiobutton(
|
||||
self.edit_frame,
|
||||
indicatoron=False,
|
||||
|
@ -530,13 +530,13 @@ class CoreToolbar(object):
|
|||
"""
|
||||
self.create_regular_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.START.value),
|
||||
Images.get(ImageEnum.START),
|
||||
self.click_start_session_tool,
|
||||
"start the session",
|
||||
)
|
||||
self.create_radio_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.SELECT.value),
|
||||
Images.get(ImageEnum.SELECT),
|
||||
self.click_selection_tool,
|
||||
self.radio_value,
|
||||
1,
|
||||
|
@ -544,7 +544,7 @@ class CoreToolbar(object):
|
|||
)
|
||||
self.create_radio_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.LINK.value),
|
||||
Images.get(ImageEnum.LINK),
|
||||
self.click_link_tool,
|
||||
self.radio_value,
|
||||
2,
|
||||
|
@ -558,7 +558,7 @@ class CoreToolbar(object):
|
|||
def create_observe_button(self):
|
||||
menu_button = tk.Menubutton(
|
||||
self.edit_frame,
|
||||
image=Images.get(ImageEnum.OBSERVE.value),
|
||||
image=Images.get(ImageEnum.OBSERVE),
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
direction=tk.RIGHT,
|
||||
|
@ -615,13 +615,13 @@ class CoreToolbar(object):
|
|||
def create_runtime_toolbar(self):
|
||||
self.create_regular_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.STOP.value),
|
||||
Images.get(ImageEnum.STOP),
|
||||
self.click_stop_button,
|
||||
"stop the session",
|
||||
)
|
||||
self.create_radio_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.SELECT.value),
|
||||
Images.get(ImageEnum.SELECT),
|
||||
self.click_selection_tool,
|
||||
self.exec_radio_value,
|
||||
1,
|
||||
|
@ -630,7 +630,7 @@ class CoreToolbar(object):
|
|||
self.create_observe_button()
|
||||
self.create_radio_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.PLOT.value),
|
||||
Images.get(ImageEnum.PLOT),
|
||||
self.click_plot_button,
|
||||
self.exec_radio_value,
|
||||
2,
|
||||
|
@ -638,7 +638,7 @@ class CoreToolbar(object):
|
|||
)
|
||||
self.create_radio_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.MARKER.value),
|
||||
Images.get(ImageEnum.MARKER),
|
||||
self.click_marker_button,
|
||||
self.exec_radio_value,
|
||||
3,
|
||||
|
@ -646,16 +646,13 @@ class CoreToolbar(object):
|
|||
)
|
||||
self.create_radio_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.TWONODE.value),
|
||||
Images.get(ImageEnum.TWONODE),
|
||||
self.click_two_node_button,
|
||||
self.exec_radio_value,
|
||||
4,
|
||||
"run command from one node to another",
|
||||
)
|
||||
self.create_regular_button(
|
||||
self.edit_frame,
|
||||
Images.get(ImageEnum.RUN.value),
|
||||
self.click_run_button,
|
||||
"run",
|
||||
self.edit_frame, Images.get(ImageEnum.RUN), self.click_run_button, "run"
|
||||
)
|
||||
self.exec_radio_value.set(1)
|
||||
|
|
0
coretk/coretk/dialogs/__init__.py
Normal file
0
coretk/coretk/dialogs/__init__.py
Normal file
24
coretk/coretk/dialogs/dialog.py
Normal file
24
coretk/coretk/dialogs/dialog.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
import tkinter as tk
|
||||
|
||||
from coretk.images import ImageEnum, Images
|
||||
|
||||
|
||||
class Dialog(tk.Toplevel):
|
||||
def __init__(self, master, app, title, modal=False):
|
||||
super().__init__(master, padx=5, pady=5)
|
||||
self.withdraw()
|
||||
self.app = app
|
||||
self.modal = modal
|
||||
self.title(title)
|
||||
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
||||
image = Images.get(ImageEnum.CORE)
|
||||
self.tk.call("wm", "iconphoto", self._w, image)
|
||||
|
||||
def show(self):
|
||||
self.transient(self.master)
|
||||
self.focus_force()
|
||||
if self.modal:
|
||||
self.grab_set()
|
||||
self.update()
|
||||
self.deiconify()
|
||||
self.wait_window()
|
34
coretk/coretk/dialogs/sessionoptions.py
Normal file
34
coretk/coretk/dialogs/sessionoptions.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
|
||||
from coretk import configutils
|
||||
from coretk.dialogs.dialog import Dialog
|
||||
|
||||
PAD_X = 2
|
||||
PAD_Y = 2
|
||||
|
||||
|
||||
class SessionOptionsDialog(Dialog):
|
||||
def __init__(self, master, app):
|
||||
super().__init__(master, app, "Session Options", modal=True)
|
||||
self.options = None
|
||||
self.values = None
|
||||
self.save_button = tk.Button(self, text="Save", command=self.save)
|
||||
self.cancel_button = tk.Button(self, text="Cancel", command=self.destroy)
|
||||
self.draw()
|
||||
|
||||
def draw(self):
|
||||
session_id = self.master.core_grpc.session_id
|
||||
response = self.master.core_grpc.core.get_session_options(session_id)
|
||||
logging.info("session options: %s", response)
|
||||
self.options = response.config
|
||||
self.values = configutils.create_config(self, self.options, PAD_X, PAD_Y)
|
||||
self.save_button.grid(row=1, pady=PAD_Y, padx=PAD_X, sticky="ew")
|
||||
self.cancel_button.grid(row=1, column=1, pady=PAD_Y, padx=PAD_X, sticky="ew")
|
||||
|
||||
def save(self):
|
||||
config = configutils.parse_config(self.options, self.values)
|
||||
session_id = self.master.core_grpc.session_id
|
||||
response = self.master.core_grpc.core.set_session_options(session_id, config)
|
||||
logging.info("saved session config: %s", response)
|
||||
self.destroy()
|
159
coretk/coretk/dialogs/sessions.py
Normal file
159
coretk/coretk/dialogs/sessions.py
Normal file
|
@ -0,0 +1,159 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
from tkinter.ttk import Scrollbar, Treeview
|
||||
|
||||
from core.api.grpc import core_pb2
|
||||
from coretk.dialogs.dialog import Dialog
|
||||
from coretk.images import ImageEnum, Images
|
||||
|
||||
|
||||
class SessionsDialog(Dialog):
|
||||
def __init__(self, master, app):
|
||||
"""
|
||||
create session table instance
|
||||
|
||||
:param coretk.coregrpc.CoreGrpc grpc: coregrpc
|
||||
:param root.master master:
|
||||
"""
|
||||
super().__init__(master, app, "Sessions", modal=True)
|
||||
self.selected = False
|
||||
self.selected_id = None
|
||||
self.tree = None
|
||||
self.draw()
|
||||
|
||||
def draw(self):
|
||||
self.columnconfigure(0, weight=1)
|
||||
self.draw_description()
|
||||
self.draw_tree()
|
||||
self.draw_buttons()
|
||||
|
||||
def draw_description(self):
|
||||
"""
|
||||
write a short description
|
||||
:return: nothing
|
||||
"""
|
||||
label = tk.Label(
|
||||
self,
|
||||
text="Below is a list of active CORE sessions. Double-click to \n"
|
||||
"connect to an existing session. Usually, only sessions in \n"
|
||||
"the RUNTIME state persist in the daemon, except for the \n"
|
||||
"one you might be concurrently editting.",
|
||||
)
|
||||
label.grid(row=0, sticky="ew", pady=5)
|
||||
|
||||
def draw_tree(self):
|
||||
self.tree = Treeview(self, columns=("id", "state", "nodes"), show="headings")
|
||||
self.tree.grid(row=1, sticky="nsew")
|
||||
self.tree.column("id", stretch=tk.YES)
|
||||
self.tree.heading("id", text="ID")
|
||||
self.tree.column("state", stretch=tk.YES)
|
||||
self.tree.heading("state", text="State")
|
||||
self.tree.column("nodes", stretch=tk.YES)
|
||||
self.tree.heading("nodes", text="Node Count")
|
||||
|
||||
response = self.app.core_grpc.core.get_sessions()
|
||||
logging.info("sessions: %s", response)
|
||||
for index, session in enumerate(response.sessions):
|
||||
state_name = core_pb2.SessionState.Enum.Name(session.state)
|
||||
self.tree.insert(
|
||||
"",
|
||||
tk.END,
|
||||
text=str(session.id),
|
||||
values=(session.id, state_name, session.nodes),
|
||||
)
|
||||
self.tree.bind("<Double-1>", self.on_selected)
|
||||
self.tree.bind("<<TreeviewSelect>>", self.click_select)
|
||||
|
||||
yscrollbar = Scrollbar(self, orient="vertical", command=self.tree.yview)
|
||||
yscrollbar.grid(row=1, column=1, sticky="ns")
|
||||
self.tree.configure(yscrollcommand=yscrollbar.set)
|
||||
|
||||
xscrollbar = Scrollbar(self, orient="horizontal", command=self.tree.xview)
|
||||
xscrollbar.grid(row=2, sticky="ew", pady=5)
|
||||
self.tree.configure(xscrollcommand=xscrollbar.set)
|
||||
|
||||
def draw_buttons(self):
|
||||
frame = tk.Frame(self)
|
||||
for i in range(4):
|
||||
frame.columnconfigure(i, weight=1)
|
||||
frame.grid(row=3, sticky="ew")
|
||||
b = tk.Button(
|
||||
frame,
|
||||
image=Images.get(ImageEnum.DOCUMENTNEW),
|
||||
text="New",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_new,
|
||||
)
|
||||
b.grid(row=0, padx=2, sticky="ew")
|
||||
b = tk.Button(
|
||||
frame,
|
||||
image=Images.get(ImageEnum.FILEOPEN),
|
||||
text="Connect",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_connect,
|
||||
)
|
||||
b.grid(row=0, column=1, padx=2, sticky="ew")
|
||||
b = tk.Button(
|
||||
frame,
|
||||
image=Images.get(ImageEnum.EDITDELETE),
|
||||
text="Shutdown",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_shutdown,
|
||||
)
|
||||
b.grid(row=0, column=2, padx=2, sticky="ew")
|
||||
b = tk.Button(frame, text="Cancel", command=self.click_new)
|
||||
b.grid(row=0, column=3, padx=2, sticky="ew")
|
||||
|
||||
def click_new(self):
|
||||
self.app.core_grpc.create_new_session()
|
||||
self.destroy()
|
||||
|
||||
def click_select(self, event):
|
||||
item = self.tree.selection()
|
||||
session_id = int(self.tree.item(item, "text"))
|
||||
self.selected = True
|
||||
self.selected_id = session_id
|
||||
|
||||
def click_connect(self):
|
||||
"""
|
||||
if no session is selected yet, create a new one else join that session
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
if self.selected and self.selected_id is not None:
|
||||
self.join_session(self.selected_id)
|
||||
elif not self.selected and self.selected_id is None:
|
||||
self.click_new()
|
||||
else:
|
||||
logging.error("sessions invalid state")
|
||||
|
||||
def click_shutdown(self):
|
||||
"""
|
||||
if no session is currently selected create a new session else shut the selected
|
||||
session down.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
if self.selected and self.selected_id is not None:
|
||||
self.shutdown_session(self.selected_id)
|
||||
elif not self.selected and self.selected_id is None:
|
||||
self.click_new()
|
||||
else:
|
||||
logging.error("querysessiondrawing.py invalid state")
|
||||
|
||||
def join_session(self, session_id):
|
||||
response = self.app.core_grpc.core.get_session(session_id)
|
||||
self.app.core_grpc.session_id = session_id
|
||||
self.app.core_grpc.core.events(session_id, self.app.core_grpc.log_event)
|
||||
logging.info("entering session_id %s.... Result: %s", session_id, response)
|
||||
self.destroy()
|
||||
|
||||
def on_selected(self, event):
|
||||
item = self.tree.selection()
|
||||
sid = int(self.tree.item(item, "text"))
|
||||
self.join_session(sid)
|
||||
|
||||
def shutdown_session(self, sid):
|
||||
self.app.core_grpc.terminate_session(sid)
|
||||
self.click_new()
|
||||
self.destroy()
|
|
@ -94,7 +94,7 @@ class WlanAntennaManager:
|
|||
x - 16 + self.offset,
|
||||
y - 16,
|
||||
anchor=tk.CENTER,
|
||||
image=Images.get(ImageEnum.ANTENNA.value),
|
||||
image=Images.get(ImageEnum.ANTENNA),
|
||||
tags="antenna",
|
||||
)
|
||||
)
|
||||
|
|
|
@ -21,8 +21,8 @@ class Images:
|
|||
cls.images[name] = tk_image
|
||||
|
||||
@classmethod
|
||||
def get(cls, name):
|
||||
return cls.images[name]
|
||||
def get(cls, image):
|
||||
return cls.images[image.value]
|
||||
|
||||
@classmethod
|
||||
def convert_type_and_model_to_image(cls, node_type, node_model):
|
||||
|
@ -35,30 +35,31 @@ class Images:
|
|||
:return: the matching image and its name
|
||||
"""
|
||||
if node_type == core_pb2.NodeType.SWITCH:
|
||||
return Images.get(ImageEnum.SWITCH.value), "switch"
|
||||
return Images.get(ImageEnum.SWITCH), "switch"
|
||||
if node_type == core_pb2.NodeType.HUB:
|
||||
return Images.get(ImageEnum.HUB.value), "hub"
|
||||
return Images.get(ImageEnum.HUB), "hub"
|
||||
if node_type == core_pb2.NodeType.WIRELESS_LAN:
|
||||
return Images.get(ImageEnum.WLAN.value), "wlan"
|
||||
if node_type == core_pb2.NodeType.EMANE:
|
||||
return Images.get(ImageEnum.EMANE.value), "emane"
|
||||
|
||||
if node_type == core_pb2.NodeType.RJ45:
|
||||
return Images.get(ImageEnum.RJ45.value), "rj45"
|
||||
return Images.get(ImageEnum.RJ45), "rj45"
|
||||
if node_type == core_pb2.NodeType.TUNNEL:
|
||||
return Images.get(ImageEnum.TUNNEL.value), "tunnel"
|
||||
return Images.get(ImageEnum.TUNNEL), "tunnel"
|
||||
if node_type == core_pb2.NodeType.DEFAULT:
|
||||
if node_model == "router":
|
||||
return Images.get(ImageEnum.ROUTER.value), "router"
|
||||
return Images.get(ImageEnum.ROUTER), "router"
|
||||
if node_model == "host":
|
||||
return Images.get((ImageEnum.HOST.value)), "host"
|
||||
return Images.get(ImageEnum.HOST), "host"
|
||||
if node_model == "PC":
|
||||
return Images.get(ImageEnum.PC.value), "PC"
|
||||
return Images.get(ImageEnum.PC), "PC"
|
||||
if node_model == "mdr":
|
||||
return Images.get(ImageEnum.MDR.value), "mdr"
|
||||
return Images.get(ImageEnum.MDR), "mdr"
|
||||
if node_model == "prouter":
|
||||
return Images.get(ImageEnum.PROUTER.value), "prouter"
|
||||
return Images.get(ImageEnum.PROUTER), "prouter"
|
||||
if node_model == "OVS":
|
||||
return Images.get(ImageEnum.OVS.value), "ovs"
|
||||
return Images.get(ImageEnum.OVS), "ovs"
|
||||
else:
|
||||
logging.debug("INVALID INPUT OR NOT CONSIDERED YET")
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import webbrowser
|
|||
from tkinter import filedialog, messagebox
|
||||
|
||||
from core.api.grpc import core_pb2
|
||||
from coretk.dialogs.sessionoptions import SessionOptionsDialog
|
||||
from coretk.dialogs.sessions import SessionsDialog
|
||||
from coretk.setwallpaper import CanvasWallpaper
|
||||
from coretk.sizeandscale import SizeAndScale
|
||||
|
||||
|
@ -290,10 +292,6 @@ def widgets_configure_throughput():
|
|||
logging.debug("Click widgets configure throughput")
|
||||
|
||||
|
||||
def session_change_sessions():
|
||||
logging.debug("Click session change sessions")
|
||||
|
||||
|
||||
def session_node_types():
|
||||
logging.debug("Click session node types")
|
||||
|
||||
|
@ -314,10 +312,6 @@ def session_emulation_servers():
|
|||
logging.debug("Click session emulation servers")
|
||||
|
||||
|
||||
def session_options():
|
||||
logging.debug("Click session options")
|
||||
|
||||
|
||||
def help_about():
|
||||
logging.debug("Click help About")
|
||||
|
||||
|
@ -429,3 +423,13 @@ class MenuAction:
|
|||
|
||||
def help_core_documentation(self):
|
||||
webbrowser.open_new("http://coreemu.github.io/core/")
|
||||
|
||||
def session_options(self):
|
||||
logging.debug("Click session options")
|
||||
dialog = SessionOptionsDialog(self.application, self.application)
|
||||
dialog.show()
|
||||
|
||||
def session_change_sessions(self):
|
||||
logging.debug("Click session change sessions")
|
||||
dialog = SessionsDialog(self.application, self.application)
|
||||
dialog.show()
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
from tkinter.ttk import Scrollbar, Treeview
|
||||
|
||||
from coretk.images import ImageEnum, Images
|
||||
|
||||
|
||||
class SessionTable:
|
||||
def __init__(self, grpc, master):
|
||||
"""
|
||||
create session table instance
|
||||
:param coretk.coregrpc.CoreGrpc grpc: coregrpc
|
||||
:param root.master master:
|
||||
"""
|
||||
self.grpc = grpc
|
||||
self.selected = False
|
||||
self.selected_sid = None
|
||||
self.master = master
|
||||
self.top = tk.Toplevel(self.master)
|
||||
self.description_definition()
|
||||
self.top.title("CORE sessions")
|
||||
|
||||
self.tree = Treeview(self.top)
|
||||
# self.tree.pack(side=tk.TOP)
|
||||
self.tree.grid(row=1, column=0, columnspan=2)
|
||||
self.draw_scrollbar()
|
||||
self.draw()
|
||||
|
||||
def description_definition(self):
|
||||
"""
|
||||
write a short description
|
||||
:return: nothing
|
||||
"""
|
||||
lable = tk.Label(
|
||||
self.top,
|
||||
text="Below is a list of active CORE sessions. Double-click to "
|
||||
"\nconnect to an existing session. Usually, only sessions in "
|
||||
"\nthe RUNTIME state persist in the daemon, except for the "
|
||||
"\none you might be concurrently editting.",
|
||||
)
|
||||
lable.grid(sticky=tk.W)
|
||||
|
||||
def column_definition(self):
|
||||
# self.tree["columns"] = ("name", "nodecount", "filename", "date")
|
||||
self.tree["columns"] = "nodecount"
|
||||
self.tree.column("#0", width=300, minwidth=30)
|
||||
# self.tree.column("name", width=72, miwidth=30)
|
||||
self.tree.column("nodecount", width=300, minwidth=30)
|
||||
# self.tree.column("filename", width=92, minwidth=30)
|
||||
# self.tree.column("date", width=170, minwidth=30)
|
||||
|
||||
def draw_scrollbar(self):
|
||||
yscrollbar = Scrollbar(self.top, orient="vertical", command=self.tree.yview)
|
||||
yscrollbar.grid(row=1, column=3, sticky=tk.N + tk.S + tk.W)
|
||||
self.tree.configure(yscrollcommand=yscrollbar.set)
|
||||
|
||||
xscrollbar = Scrollbar(self.top, orient="horizontal", command=self.tree.xview)
|
||||
xscrollbar.grid(row=2, columnspan=2, sticky=tk.E + tk.W + tk.S)
|
||||
self.tree.configure(xscrollcommand=xscrollbar.set)
|
||||
|
||||
def heading_definition(self):
|
||||
self.tree.heading("#0", text="ID", anchor=tk.W)
|
||||
# self.tree.heading("name", text="Name", anchor=tk.CENTER)
|
||||
self.tree.heading("nodecount", text="Node Count", anchor=tk.W)
|
||||
# self.tree.heading("filename", text="Filename", anchor=tk.CENTER)
|
||||
# self.tree.heading("date", text="Date", anchor=tk.CENTER)
|
||||
|
||||
def enter_session(self, sid):
|
||||
self.top.destroy()
|
||||
response = self.grpc.core.get_session(sid)
|
||||
self.grpc.session_id = sid
|
||||
self.grpc.core.events(sid, self.grpc.log_event)
|
||||
logging.info("Entering session_id %s.... Result: %s", sid, response)
|
||||
|
||||
def new_session(self):
|
||||
self.top.destroy()
|
||||
self.grpc.create_new_session()
|
||||
|
||||
def on_selected(self, event):
|
||||
item = self.tree.selection()
|
||||
sid = int(self.tree.item(item, "text"))
|
||||
self.enter_session(sid)
|
||||
|
||||
def click_select(self, event):
|
||||
# logging.debug("Click on %s ", event)
|
||||
item = self.tree.selection()
|
||||
sid = int(self.tree.item(item, "text"))
|
||||
self.selected = True
|
||||
self.selected_sid = sid
|
||||
|
||||
def session_definition(self):
|
||||
response = self.grpc.core.get_sessions()
|
||||
# logging.info("querysessiondrawing.py Get all sessions %s", response)
|
||||
index = 1
|
||||
for session in response.sessions:
|
||||
self.tree.insert(
|
||||
"", index, None, text=str(session.id), values=(str(session.nodes))
|
||||
)
|
||||
index = index + 1
|
||||
self.tree.bind("<Double-1>", self.on_selected)
|
||||
self.tree.bind("<<TreeviewSelect>>", self.click_select)
|
||||
|
||||
def click_connect(self):
|
||||
"""
|
||||
if no session is selected yet, create a new one else join that session
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
if self.selected and self.selected_sid is not None:
|
||||
self.enter_session(self.selected_sid)
|
||||
elif not self.selected and self.selected_sid is None:
|
||||
self.new_session()
|
||||
else:
|
||||
logging.error("querysessiondrawing.py invalid state")
|
||||
|
||||
def shutdown_session(self, sid):
|
||||
self.grpc.terminate_session(sid)
|
||||
self.new_session()
|
||||
self.top.destroy()
|
||||
|
||||
def click_shutdown(self):
|
||||
"""
|
||||
if no session is currently selected create a new session else shut the selected session down
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
if self.selected and self.selected_sid is not None:
|
||||
self.shutdown_session(self.selected_sid)
|
||||
elif not self.selected and self.selected_sid is None:
|
||||
self.new_session()
|
||||
else:
|
||||
logging.error("querysessiondrawing.py invalid state")
|
||||
# if self.selected and self.selected_sid is not None:
|
||||
|
||||
def draw_buttons(self):
|
||||
f = tk.Frame(self.top)
|
||||
f.grid(row=3, sticky=tk.W)
|
||||
|
||||
b = tk.Button(
|
||||
f,
|
||||
image=Images.get(ImageEnum.DOCUMENTNEW.value),
|
||||
text="New",
|
||||
compound=tk.LEFT,
|
||||
command=self.new_session,
|
||||
)
|
||||
b.pack(side=tk.LEFT, padx=3, pady=4)
|
||||
b = tk.Button(
|
||||
f,
|
||||
image=Images.get(ImageEnum.FILEOPEN.value),
|
||||
text="Connect",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_connect,
|
||||
)
|
||||
b.pack(side=tk.LEFT, padx=3, pady=4)
|
||||
b = tk.Button(
|
||||
f,
|
||||
image=Images.get(ImageEnum.EDITDELETE.value),
|
||||
text="Shutdown",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_shutdown,
|
||||
)
|
||||
b.pack(side=tk.LEFT, padx=3, pady=4)
|
||||
b = tk.Button(f, text="Cancel", command=self.new_session)
|
||||
b.pack(side=tk.LEFT, padx=3, pady=4)
|
||||
|
||||
def center(self):
|
||||
window_width = self.master.winfo_width()
|
||||
window_height = self.master.winfo_height()
|
||||
self.top.update()
|
||||
top_level_width = self.top.winfo_width()
|
||||
top_level_height = self.top.winfo_height()
|
||||
x = window_width / 2 - top_level_width / 2
|
||||
y = window_height / 2 - top_level_height / 2
|
||||
|
||||
self.top.geometry("+%d+%d" % (x, y))
|
||||
|
||||
def draw(self):
|
||||
self.column_definition()
|
||||
self.heading_definition()
|
||||
self.session_definition()
|
||||
self.draw_buttons()
|
||||
self.center()
|
||||
self.top.wait_window()
|
Loading…
Reference in a new issue