Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-11 16:36:33 -08:00
commit 66c9063d2e
22 changed files with 546 additions and 429 deletions

View file

@ -1,7 +1,7 @@
import logging
import tkinter as tk
from coretk import appdirs
from coretk import appconfig
from coretk.coreclient import CoreClient
from coretk.graph import CanvasGraph
from coretk.images import ImageEnum, Images
@ -26,7 +26,7 @@ class Application(tk.Frame):
self.radiovar = tk.IntVar(value=1)
self.show_grid_var = tk.IntVar(value=1)
self.adjust_to_dim_var = tk.IntVar(value=0)
self.config = appdirs.read_config()
self.config = appconfig.read()
self.core = CoreClient(self)
self.setup_app()
self.draw()
@ -70,10 +70,13 @@ class Application(tk.Frame):
menu_action = MenuAction(self, self.master)
menu_action.on_quit()
def save_config(self):
appconfig.save(self.config)
if __name__ == "__main__":
log_format = "%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s"
logging.basicConfig(level=logging.DEBUG, format=log_format)
appdirs.check_directory()
appconfig.check_directory()
app = Application()
app.mainloop()

View file

@ -1,4 +1,5 @@
import logging
import os
import shutil
from pathlib import Path
@ -18,6 +19,20 @@ CONFIG_PATH = HOME_PATH.joinpath("gui.yaml")
LOCAL_ICONS_PATH = Path(__file__).parent.joinpath("icons").absolute()
LOCAL_BACKGROUND_PATH = Path(__file__).parent.joinpath("backgrounds").absolute()
# configuration data
TERMINALS = [
"$TERM",
"gnome-terminal --window --",
"lxterminal -e",
"konsole -e",
"xterm -e",
"aterm -e",
"eterm -e",
"rxvt -e",
"xfce4-terminal -x",
]
EDITORS = ["$EDITOR", "vim", "emacs", "gedit", "nano", "vi"]
class IndentDumper(yaml.Dumper):
def increase_indent(self, flow=False, indentless=False):
@ -42,18 +57,33 @@ def check_directory():
for background in LOCAL_BACKGROUND_PATH.glob("*"):
new_background = BACKGROUNDS_PATH.joinpath(background.name)
shutil.copy(background, new_background)
if "TERM" in os.environ:
terminal = TERMINALS[0]
else:
terminal = TERMINALS[1]
if "EDITOR" in os.environ:
editor = EDITORS[0]
else:
editor = EDITORS[1]
config = {
"preferences": {
"editor": editor,
"terminal": terminal,
"gui3d": "/usr/local/bin/std3d.sh",
},
"servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}],
"nodes": [],
"observers": [{"name": "hello", "cmd": "echo hello"}],
}
save_config(config)
save(config)
def read_config():
def read():
with CONFIG_PATH.open("r") as f:
return yaml.load(f, Loader=yaml.SafeLoader)
def save_config(config):
def save(config):
with CONFIG_PATH.open("w") as f:
yaml.dump(config, f, Dumper=IndentDumper, default_flow_style=False)

View file

@ -18,25 +18,14 @@ class CanvasTooltip:
"""
def __init__(
self,
canvas,
tag_or_id,
*,
bg="#FFFFEA",
pad=(5, 3, 5, 3),
text="canvas info",
waittime=400,
wraplength=250
self, canvas, *, bg="#FFFFEA", pad=(5, 3, 5, 3), waittime=400, wraplength=600
):
# in miliseconds, originally 500
self.waittime = waittime
# in pixels, originally 180
self.wraplength = wraplength
self.canvas = canvas
self.text = text
self.canvas.tag_bind(tag_or_id, "<Enter>", self.on_enter)
self.canvas.tag_bind(tag_or_id, "<Leave>", self.on_leave)
self.canvas.tag_bind(tag_or_id, "<ButtonPress>", self.on_leave)
self.text = tk.StringVar()
self.bg = bg
self.pad = pad
self.id = None
@ -61,18 +50,13 @@ class CanvasTooltip:
def show(self, event=None):
def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
c = canvas
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()
width, height = (
pad[0] + label.winfo_reqwidth() + pad[2],
pad[1] + label.winfo_reqheight() + pad[3],
)
mouse_x, mouse_y = c.winfo_pointerxy()
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x2, y2 = x1 + width, y1 + height
@ -84,20 +68,14 @@ class CanvasTooltip:
y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0)
if offscreen:
if x_delta:
x1 = mouse_x - tip_delta[0] - width
if y_delta:
y1 = mouse_y - tip_delta[1] - height
offscreen_again = y1 < 0 # out on the top
if offscreen_again:
y1 = 0
return x1, y1
bg = self.bg
@ -111,21 +89,18 @@ class CanvasTooltip:
self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw, background=bg, borderwidth=0)
win.grid()
label = ttk.Label(
win,
text=self.text,
textvariable=self.text,
justify=tk.LEFT,
background=bg,
relief=tk.SOLID,
borderwidth=0,
wraplength=self.wraplength,
)
label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.NSEW)
win.grid()
x, y = tip_pos_calculator(canvas, label)
self.tw.wm_geometry("+%d+%d" % (x, y))
def hide(self):

View file

@ -16,6 +16,17 @@ from coretk.wlannodeconfig import WlanNodeConfig
NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"}
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
OBSERVERS = {
"processes": "ps",
"ifconfig": "ifconfig",
"IPV4 Routes": "ip -4 ro",
"IPV6 Routes": "ip -6 ro",
"Listening sockets": "netstat -tuwnl",
"IPv4 MFC entries": "ip -4 mroute show",
"IPv6 MFC entries": "ip -6 mroute show",
"firewall rules": "iptables -L",
"IPSec policies": "setkey -DP",
}
class Node:
@ -74,6 +85,12 @@ class CustomNode:
self.services = services
class Observer:
def __init__(self, name, cmd):
self.name = name
self.cmd = cmd
class CoreClient:
def __init__(self, app):
"""
@ -86,13 +103,16 @@ class CoreClient:
self.master = app.master
self.interface_helper = None
self.services = {}
self.observer = None
# loaded configuration data
self.servers = {}
self.custom_nodes = {}
self.custom_observers = {}
self.read_config()
# data for managing the current session
self.state = None
self.nodes = {}
self.edges = {}
self.hooks = {}
@ -107,27 +127,36 @@ class CoreClient:
self.emane_config = None
self.serviceconfig_manager = ServiceNodeConfig(app)
def set_observer(self, value):
self.observer = value
def read_config(self):
# read distributed server
for server_config in self.app.config["servers"]:
server = CoreServer(
server_config["name"], server_config["address"], server_config["port"]
)
for config in self.app.config.get("servers", []):
server = CoreServer(config["name"], config["address"], config["port"])
self.servers[server.name] = server
# read custom nodes
for node in self.app.config["nodes"]:
image_file = node["image"]
for config in self.app.config.get("nodes", []):
image_file = config["image"]
image = Images.get_custom(image_file)
custom_node = CustomNode(
node["name"], image, image_file, set(node["services"])
config["name"], image, image_file, set(config["services"])
)
self.custom_nodes[custom_node.name] = custom_node
# read observers
for config in self.app.config.get("observers", []):
observer = Observer(config["name"], config["cmd"])
self.custom_observers[observer.name] = observer
def handle_events(self, event):
logging.info("event: %s", event)
if event.link_event is not None:
if event.HasField("link_event"):
self.app.canvas.wireless_draw.hangle_link_event(event.link_event)
elif event.HasField("session_event"):
if event.session_event.event <= core_pb2.SessionState.SHUTDOWN:
self.state = event.session_event.event
def handle_throughputs(self, event):
interface_throughputs = event.interface_throughputs
@ -161,7 +190,7 @@ class CoreClient:
response = self.client.get_session(self.session_id)
logging.info("joining session(%s): %s", self.session_id, response)
session = response.session
session_state = session.state
self.state = session.state
self.client.events(self.session_id, self.handle_events)
# get hooks
@ -209,11 +238,14 @@ class CoreClient:
self.app.canvas.canvas_reset_and_redraw(session)
# draw tool bar appropritate with session state
if session_state == core_pb2.SessionState.RUNTIME:
if self.is_runtime():
self.app.toolbar.runtime_frame.tkraise()
else:
self.app.toolbar.design_frame.tkraise()
def is_runtime(self):
return self.state == core_pb2.SessionState.RUNTIME
def create_new_session(self):
"""
Create a new session
@ -769,3 +801,7 @@ class CoreClient:
)
configs.append(config_proto)
return configs
def run(self, node_id):
logging.info("running node(%s) cmd: %s", node_id, self.observer)
return self.client.node_command(self.session_id, node_id, self.observer).output

View file

@ -4,11 +4,11 @@ set wallpaper
import enum
import logging
import tkinter as tk
from tkinter import filedialog
from tkinter import filedialog, ttk
from PIL import Image, ImageTk
from coretk.appdirs import BACKGROUNDS_PATH
from coretk.appconfig import BACKGROUNDS_PATH
from coretk.dialogs.dialog import Dialog
@ -39,7 +39,6 @@ class CanvasBackgroundDialog(Dialog):
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_image()
self.draw_image_label()
self.draw_image_selection()
@ -48,65 +47,67 @@ class CanvasBackgroundDialog(Dialog):
self.draw_buttons()
def draw_image(self):
self.image_label = tk.Label(
self, text="(image preview)", height=8, width=32, bg="white"
self.image_label = ttk.Label(
self, text="(image preview)", width=32, anchor=tk.CENTER
)
self.image_label.grid(row=0, column=0, pady=5, sticky="nsew")
self.image_label.grid(row=0, column=0, pady=5)
def draw_image_label(self):
label = tk.Label(self, text="Image filename: ")
label = ttk.Label(self, text="Image filename: ")
label.grid(row=1, column=0, sticky="ew")
def draw_image_selection(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.columnconfigure(0, weight=2)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1)
frame.grid(row=2, column=0, sticky="ew")
entry = tk.Entry(frame, textvariable=self.file_name)
entry = ttk.Entry(frame, textvariable=self.file_name)
entry.focus()
entry.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="...", command=self.click_open_image)
button = ttk.Button(frame, text="...", command=self.click_open_image)
button.grid(row=0, column=1, sticky="ew")
button = tk.Button(frame, text="Clear", command=self.click_clear)
button = ttk.Button(frame, text="Clear", command=self.click_clear)
button.grid(row=0, column=2, sticky="ew")
def draw_options(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1)
frame.columnconfigure(3, weight=1)
frame.grid(row=3, column=0, sticky="ew")
button = tk.Radiobutton(
button = ttk.Radiobutton(
frame, text="upper-left", value=1, variable=self.radiovar
)
button.grid(row=0, column=0, sticky="ew")
self.options.append(button)
button = tk.Radiobutton(frame, text="centered", value=2, variable=self.radiovar)
button = ttk.Radiobutton(
frame, text="centered", value=2, variable=self.radiovar
)
button.grid(row=0, column=1, sticky="ew")
self.options.append(button)
button = tk.Radiobutton(frame, text="scaled", value=3, variable=self.radiovar)
button = ttk.Radiobutton(frame, text="scaled", value=3, variable=self.radiovar)
button.grid(row=0, column=2, sticky="ew")
self.options.append(button)
button = tk.Radiobutton(frame, text="titled", value=4, variable=self.radiovar)
button = ttk.Radiobutton(frame, text="titled", value=4, variable=self.radiovar)
button.grid(row=0, column=3, sticky="ew")
self.options.append(button)
def draw_additional_options(self):
checkbutton = tk.Checkbutton(
checkbutton = ttk.Checkbutton(
self, text="Show grid", variable=self.show_grid_var
)
checkbutton.grid(row=4, column=0, sticky="ew", padx=5)
checkbutton = tk.Checkbutton(
checkbutton = ttk.Checkbutton(
self,
text="Adjust canvas size to image dimensions",
variable=self.adjust_to_dim_var,
@ -118,15 +119,15 @@ class CanvasBackgroundDialog(Dialog):
self.adjust_to_dim_var.set(0)
def draw_buttons(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(row=6, column=0, pady=5, sticky="ew")
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
button = tk.Button(frame, text="Apply", command=self.click_apply)
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_open_image(self):
@ -144,7 +145,7 @@ class CanvasBackgroundDialog(Dialog):
img = Image.open(filename)
img = img.resize((width, height), Image.ANTIALIAS)
tk_img = ImageTk.PhotoImage(img)
self.image_label.config(image=tk_img, width=width, height=height)
self.image_label.config(image=tk_img, width=width)
self.image_label.image = tk_img
def click_clear(self):
@ -156,7 +157,7 @@ class CanvasBackgroundDialog(Dialog):
# delete entry
self.file_name.set("")
# delete display image
self.image_label.config(image="", width=32, height=8)
self.image_label.config(image="", width=32)
def click_adjust_canvas(self):
# deselect all radio buttons and grey them out

View file

@ -2,7 +2,7 @@
size and scale
"""
import tkinter as tk
from tkinter import font
from tkinter import font, ttk
from coretk.dialogs.canvasbackground import ScaleOption
from coretk.dialogs.dialog import Dialog
@ -49,120 +49,120 @@ class SizeAndScaleDialog(Dialog):
self.draw_buttons()
def draw_size(self):
label = tk.Label(self, text="Size", font=self.section_font)
label = ttk.Label(self, text="Size", font=self.section_font)
label.grid(sticky="w")
# draw size row 1
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1)
label = tk.Label(frame, text="Width")
label = ttk.Label(frame, text="Width")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.pixel_width)
entry = ttk.Entry(frame, textvariable=self.pixel_width)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="x Height")
label = ttk.Label(frame, text="x Height")
label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.pixel_height)
entry = ttk.Entry(frame, textvariable=self.pixel_height)
entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Pixels")
label = ttk.Label(frame, text="Pixels")
label.grid(row=0, column=4, sticky="w")
# draw size row 2
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1)
label = tk.Label(frame, text="Width")
label = ttk.Label(frame, text="Width")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.meters_width)
entry = ttk.Entry(frame, textvariable=self.meters_width)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="x Height")
label = ttk.Label(frame, text="x Height")
label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.meters_height)
entry = ttk.Entry(frame, textvariable=self.meters_height)
entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Meters")
label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=4, sticky="w")
def draw_scale(self):
label = tk.Label(self, text="Scale", font=self.section_font)
label = ttk.Label(self, text="Scale", font=self.section_font)
label.grid(sticky="w")
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = tk.Label(frame, text="100 Pixels =")
label = ttk.Label(frame, text="100 Pixels =")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.scale)
entry = ttk.Entry(frame, textvariable=self.scale)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Meters")
label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=2, sticky="w")
def draw_reference_point(self):
label = tk.Label(self, text="Reference point", font=self.section_font)
label = ttk.Label(self, text="Reference point", font=self.section_font)
label.grid(sticky="w")
label = tk.Label(
label = ttk.Label(
self, text="Default is (0, 0), the upper left corner of the canvas"
)
label.grid(sticky="w")
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1)
label = tk.Label(frame, text="X")
label = ttk.Label(frame, text="X")
label.grid(row=0, column=0, sticky="w")
x_var = tk.StringVar(value=0)
entry = tk.Entry(frame, textvariable=x_var)
entry = ttk.Entry(frame, textvariable=x_var)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Y")
label = ttk.Label(frame, text="Y")
label.grid(row=0, column=2, sticky="w")
y_var = tk.StringVar(value=0)
entry = tk.Entry(frame, textvariable=y_var)
entry = ttk.Entry(frame, textvariable=y_var)
entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(self, text="Translates To")
label = ttk.Label(self, text="Translates To")
label.grid(sticky="w")
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1)
frame.columnconfigure(5, weight=1)
label = tk.Label(frame, text="Lat")
label = ttk.Label(frame, text="Lat")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.lat)
entry = ttk.Entry(frame, textvariable=self.lat)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Lon")
label = ttk.Label(frame, text="Lon")
label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.lon)
entry = ttk.Entry(frame, textvariable=self.lon)
entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Alt")
label = ttk.Label(frame, text="Alt")
label.grid(row=0, column=4, sticky="w")
entry = tk.Entry(frame, textvariable=self.alt)
entry = ttk.Entry(frame, textvariable=self.alt)
entry.grid(row=0, column=5, sticky="ew")
def draw_save_as_default(self):
button = tk.Checkbutton(
button = ttk.Checkbutton(
self, text="Save as default?", variable=self.save_default
)
button.grid(sticky="w", pady=3)
def draw_buttons(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
frame.grid(sticky="ew")
button = tk.Button(frame, text="Apply", command=self.click_apply)
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, pady=5, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, pady=5, sticky="ew")
def redraw_grid(self):

View file

@ -1,8 +1,8 @@
import logging
import tkinter as tk
from pathlib import Path
from tkinter import ttk
from coretk import appdirs
from coretk.coreclient import CustomNode
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog
@ -22,7 +22,7 @@ class ServicesSelectDialog(Dialog):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(stick="nsew")
frame.rowconfigure(0, weight=1)
for i in range(3):
@ -44,13 +44,13 @@ class ServicesSelectDialog(Dialog):
for service in sorted(self.current_services):
self.current.listbox.insert(tk.END, service)
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(stick="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.destroy)
button = ttk.Button(frame, text="Save", command=self.destroy)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.click_cancel)
button = ttk.Button(frame, text="Cancel", command=self.click_cancel)
button.grid(row=0, column=1, sticky="ew")
# trigger group change
@ -103,7 +103,7 @@ class CustomNodesDialog(Dialog):
self.draw_buttons()
def draw_node_config(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
@ -114,45 +114,45 @@ class CustomNodesDialog(Dialog):
for name in sorted(self.app.core.custom_nodes):
self.nodes_list.listbox.insert(tk.END, name)
frame = tk.Frame(frame)
frame = ttk.Frame(frame)
frame.grid(row=0, column=2, sticky="nsew")
frame.columnconfigure(0, weight=1)
entry = tk.Entry(frame, textvariable=self.name)
entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(sticky="ew")
self.image_button = tk.Button(frame, text="Icon", command=self.click_icon)
self.image_button = ttk.Button(frame, text="Icon", command=self.click_icon)
self.image_button.grid(sticky="ew")
button = tk.Button(frame, text="Services", command=self.click_services)
button = ttk.Button(frame, text="Services", command=self.click_services)
button.grid(sticky="ew")
def draw_node_buttons(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create)
button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.edit_button = tk.Button(
self.edit_button = ttk.Button(
frame, text="Edit", state=tk.DISABLED, command=self.click_edit
)
self.edit_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button(
self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_buttons(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.click_save)
button = ttk.Button(frame, text="Save", command=self.click_save)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def reset_values(self):
@ -189,7 +189,8 @@ class CustomNodesDialog(Dialog):
}
)
logging.info("saving custom nodes: %s", self.app.config["nodes"])
appdirs.save_config(self.app.config)
self.app.save_config()
self.destroy()
def click_create(self):
name = self.name.get()

View file

@ -58,18 +58,18 @@ class EmaneConfiguration(Dialog):
print("not implemented")
def node_name_and_image(self):
f = tk.Frame(self, bg="#d9d9d9")
f = ttk.Frame(self)
lbl = tk.Label(f, text="Node name:", bg="#d9d9d9")
lbl = ttk.Label(f, text="Node name:")
lbl.grid(row=0, column=0, padx=2, pady=2)
e = tk.Entry(f, textvariable=self.create_text_variable(""), bg="white")
e = ttk.Entry(f, textvariable=self.create_text_variable(""))
e.grid(row=0, column=1, padx=2, pady=2)
cbb = ttk.Combobox(f, values=["(none)", "core1", "core2"], state="readonly")
cbb.current(0)
cbb.grid(row=0, column=2, padx=2, pady=2)
b = tk.Button(f, image=self.canvas_node.image)
b = ttk.Button(f, image=self.canvas_node.image)
b.grid(row=0, column=3, padx=2, pady=2)
f.grid(row=0, column=0, sticky="nsew")
@ -96,13 +96,13 @@ class EmaneConfiguration(Dialog):
self.emane_config_frame.draw_config()
self.emane_config_frame.grid(sticky="nsew")
frame = tk.Frame(self.emane_dialog)
frame = ttk.Frame(self.emane_dialog)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
b1 = tk.Button(frame, text="Appy", command=self.save_emane_option)
b1 = ttk.Button(frame, text="Appy", command=self.save_emane_option)
b1.grid(row=0, column=0, sticky="ew")
b2 = tk.Button(frame, text="Cancel", command=self.emane_dialog.destroy)
b2 = ttk.Button(frame, text="Cancel", command=self.emane_dialog.destroy)
b2.grid(row=0, column=1, sticky="ew")
self.emane_dialog.show()
@ -170,35 +170,33 @@ class EmaneConfiguration(Dialog):
self.model_config_frame.grid(sticky="nsew")
self.model_config_frame.draw_config()
frame = tk.Frame(self.emane_model_dialog)
frame = ttk.Frame(self.emane_model_dialog)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
b1 = tk.Button(frame, text="Apply", command=self.save_emane_model_options)
b1 = ttk.Button(frame, text="Apply", command=self.save_emane_model_options)
b1.grid(row=0, column=0, sticky="ew")
b2 = tk.Button(frame, text="Cancel", command=self.emane_model_dialog.destroy)
b2 = ttk.Button(frame, text="Cancel", command=self.emane_model_dialog.destroy)
b2.grid(row=0, column=1, sticky="ew")
self.emane_model_dialog.show()
def draw_option_buttons(self, parent):
f = tk.Frame(parent, bg="#d9d9d9")
f = ttk.Frame(parent)
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
b = tk.Button(
b = ttk.Button(
f,
text=self.emane_models[0] + " options",
image=Images.get(ImageEnum.EDITNODE),
compound=tk.RIGHT,
bg="#d9d9d9",
command=self.draw_model_options,
)
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(
b = ttk.Button(
f,
text="EMANE options",
image=Images.get(ImageEnum.EDITNODE),
compound=tk.RIGHT,
bg="#d9d9d9",
command=self.draw_emane_options,
)
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
@ -233,21 +231,14 @@ class EmaneConfiguration(Dialog):
self.emane_models = [x.split("_")[1] for x in response.models]
# create combo box and its binding
f = tk.Frame(
parent,
bg="#d9d9d9",
highlightbackground="#b3b3b3",
highlightcolor="#b3b3b3",
highlightthickness=0.5,
bd=0,
)
f = ttk.Frame(parent)
self.emane_model_combobox = ttk.Combobox(
f, values=self.emane_models, state="readonly"
)
self.emane_model_combobox.grid()
self.emane_model_combobox.current(0)
self.emane_model_combobox.bind("<<ComboboxSelected>>", self.combobox_select)
f.grid(row=3, column=0, sticky=tk.W + tk.E)
f.grid(row=3, column=0, sticky="ew")
def draw_text_label_and_entry(self, parent, label_text, entry_text):
"""
@ -257,10 +248,10 @@ class EmaneConfiguration(Dialog):
"""
var = tk.StringVar()
var.set(entry_text)
f = tk.Frame(parent)
lbl = tk.Label(f, text=label_text)
f = ttk.Frame(parent)
lbl = ttk.Label(f, text=label_text)
lbl.grid(row=0, column=0)
e = tk.Entry(f, textvariable=var, bg="white")
e = ttk.Entry(f, textvariable=var)
e.grid(row=0, column=1)
f.grid(stick=tk.W, padx=2, pady=2)
@ -271,44 +262,33 @@ class EmaneConfiguration(Dialog):
:return: nothing
"""
# draw label
lbl = tk.Label(self, text="Emane")
lbl = ttk.Label(self, text="Emane")
lbl.grid(row=1, column=0)
# main frame that has emane wiki, a short description, emane models and the configure buttons
f = tk.Frame(
self,
bg="#d9d9d9",
highlightbackground="#b3b3b3",
highlightcolor="#b3b3b3",
highlightthickness=0.5,
bd=0,
relief=tk.RAISED,
)
f = ttk.Frame(self)
f.columnconfigure(0, weight=1)
b = tk.Button(
b = ttk.Button(
f,
image=Images.get(ImageEnum.EDITNODE),
text="EMANE Wiki",
compound=tk.RIGHT,
relief=tk.RAISED,
bg="#d9d9d9",
command=lambda: webbrowser.open_new(
"https://github.com/adjacentlink/emane/wiki"
),
)
b.grid(row=0, column=0, sticky=tk.W)
b.grid(row=0, column=0, sticky="w")
lbl = tk.Label(
lbl = ttk.Label(
f,
text="The EMANE emulation system provides more complex wireless radio emulation "
"\nusing pluggable MAC and PHY modules. Refer to the wiki for configuration option details",
bg="#d9d9d9",
)
lbl.grid(row=1, column=0, sticky="nsew")
lbl = tk.Label(f, text="EMANE Models", bg="#d9d9d9")
lbl.grid(row=2, column=0, sticky=tk.W)
lbl = ttk.Label(f, text="EMANE Models")
lbl.grid(row=2, column=0, sticky="w")
self.draw_emane_models(f)
self.draw_option_buttons(f)
@ -325,12 +305,12 @@ class EmaneConfiguration(Dialog):
:return:
"""
f = tk.Frame(self, bg="#d9d9d9")
f = ttk.Frame(self)
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
b = tk.Button(f, text="Link to all routers", bg="#d9d9d9")
b = ttk.Button(f, text="Link to all routers")
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(f, text="Choose WLAN members", bg="#d9d9d9")
b = ttk.Button(f, text="Choose WLAN members")
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(row=5, column=0, sticky="nsew")
@ -340,12 +320,12 @@ class EmaneConfiguration(Dialog):
self.destroy()
def draw_apply_and_cancel(self):
f = tk.Frame(self, bg="#d9d9d9")
f = ttk.Frame(self)
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
b = tk.Button(f, text="Apply", bg="#d9d9d9", command=self.apply)
b = ttk.Button(f, text="Apply", command=self.apply)
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(f, text="Cancel", bg="#d9d9d9", command=self.destroy)
b = ttk.Button(f, text="Cancel", command=self.destroy)
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(sticky="nsew")

View file

@ -19,14 +19,14 @@ class HookDialog(Dialog):
self.rowconfigure(1, weight=1)
# name and states
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(row=0, sticky="ew", pady=2)
frame.columnconfigure(0, weight=2)
frame.columnconfigure(1, weight=7)
frame.columnconfigure(2, weight=1)
label = tk.Label(frame, text="Name")
label = ttk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="ew")
entry = tk.Entry(frame, textvariable=self.name)
entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew")
values = tuple(x for x in core_pb2.SessionState.Enum.keys() if x != "NONE")
initial_state = core_pb2.SessionState.Enum.Name(core_pb2.SessionState.RUNTIME)
@ -39,7 +39,7 @@ class HookDialog(Dialog):
combobox.bind("<<ComboboxSelected>>", self.state_change)
# data
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
frame.grid(row=1, sticky="nsew", pady=2)
@ -53,19 +53,19 @@ class HookDialog(Dialog):
),
)
self.data.grid(row=0, column=0, sticky="nsew")
scrollbar = tk.Scrollbar(frame)
scrollbar = ttk.Scrollbar(frame)
scrollbar.grid(row=0, column=1, sticky="ns")
self.data.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.data.yview)
# button row
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(row=2, sticky="ew", pady=2)
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=lambda: self.save())
button = ttk.Button(frame, text="Save", command=lambda: self.save())
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=lambda: self.destroy())
button = ttk.Button(frame, text="Cancel", command=lambda: self.destroy())
button.grid(row=0, column=1, sticky="ew")
def state_change(self, event):
@ -106,21 +106,21 @@ class HooksDialog(Dialog):
self.listbox.bind("<<ListboxSelect>>", self.select)
for hook_file in self.app.core.hooks:
self.listbox.insert(tk.END, hook_file)
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(row=1, sticky="ew")
for i in range(4):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create)
button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.edit_button = tk.Button(
self.edit_button = ttk.Button(
frame, text="Edit", state=tk.DISABLED, command=self.click_edit
)
self.edit_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button(
self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
button = tk.Button(frame, text="Cancel", command=lambda: self.destroy())
button = ttk.Button(frame, text="Cancel", command=lambda: self.destroy())
button.grid(row=0, column=3, sticky="ew")
def click_create(self):

View file

@ -1,7 +1,7 @@
import tkinter as tk
from tkinter import filedialog
from tkinter import filedialog, ttk
from coretk.appdirs import ICONS_PATH
from coretk.appconfig import ICONS_PATH
from coretk.dialogs.dialog import Dialog
from coretk.images import Images
@ -18,30 +18,30 @@ class IconDialog(Dialog):
self.columnconfigure(0, weight=1)
# row one
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(row=0, column=0, pady=2, sticky="ew")
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=3)
label = tk.Label(frame, text="Image")
label = ttk.Label(frame, text="Image")
label.grid(row=0, column=0, sticky="ew")
entry = tk.Entry(frame, textvariable=self.file_path)
entry = ttk.Entry(frame, textvariable=self.file_path)
entry.grid(row=0, column=1, sticky="ew")
button = tk.Button(frame, text="...", command=self.click_file)
button = ttk.Button(frame, text="...", command=self.click_file)
button.grid(row=0, column=2)
# row two
self.image_label = tk.Label(self, image=self.image)
self.image_label = ttk.Label(self, image=self.image, anchor=tk.CENTER)
self.image_label.grid(row=1, column=0, pady=2, sticky="ew")
# row three
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(row=2, column=0, sticky="ew")
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
button = tk.Button(frame, text="Apply", command=self.destroy)
button = ttk.Button(frame, text="Apply", command=self.destroy)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.click_cancel)
button = ttk.Button(frame, text="Cancel", command=self.click_cancel)
button.grid(row=0, column=1, sticky="ew")
def click_file(self):

View file

@ -0,0 +1,149 @@
import tkinter as tk
from tkinter import ttk
from coretk.coreclient import Observer
from coretk.dialogs.dialog import Dialog
class ObserverDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Observer Widgets", modal=True)
self.observers = None
self.save_button = None
self.delete_button = None
self.selected = None
self.selected_index = None
self.name = tk.StringVar()
self.cmd = tk.StringVar()
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_listbox()
self.draw_form_fields()
self.draw_config_buttons()
self.draw_apply_buttons()
def draw_listbox(self):
frame = ttk.Frame(self)
frame.grid(sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=0, column=1, sticky="ns")
self.observers = tk.Listbox(
frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set
)
self.observers.grid(row=0, column=0, sticky="nsew")
self.observers.bind("<<ListboxSelect>>", self.handle_observer_change)
for name in sorted(self.app.core.custom_observers):
self.observers.insert(tk.END, name)
scrollbar.config(command=self.observers.yview)
def draw_form_fields(self):
frame = ttk.Frame(self)
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew")
label = ttk.Label(frame, text="Command")
label.grid(row=1, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.cmd)
entry.grid(row=1, column=1, sticky="ew")
def draw_config_buttons(self):
frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.save_button = ttk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save
)
self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_apply_buttons(self):
frame = ttk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Save", command=self.click_save_config)
button.grid(row=0, column=0, sticky="ew")
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_save_config(self):
observers = []
for name in sorted(self.app.core.custom_observers):
observer = self.app.core.custom_observers[name]
observers.append({"name": observer.name, "cmd": observer.cmd})
self.app.config["observers"] = observers
self.app.save_config()
self.destroy()
def click_create(self):
name = self.name.get()
if name not in self.app.core.custom_observers:
cmd = self.cmd.get()
observer = Observer(name, cmd)
self.app.core.custom_observers[name] = observer
self.observers.insert(tk.END, name)
def click_save(self):
name = self.name.get()
if self.selected:
previous_name = self.selected
self.selected = name
observer = self.app.core.custom_observers.pop(previous_name)
observer.name = name
observer.cmd = self.cmd.get()
self.app.core.custom_observers[name] = observer
self.observers.delete(self.selected_index)
self.observers.insert(self.selected_index, name)
self.observers.selection_set(self.selected_index)
def click_delete(self):
if self.selected:
self.observers.delete(self.selected_index)
del self.app.core.custom_observers[self.selected]
self.selected = None
self.selected_index = None
self.name.set("")
self.cmd.set("")
self.observers.selection_clear(0, tk.END)
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)
def handle_observer_change(self, event):
selection = self.observers.curselection()
if selection:
self.selected_index = selection[0]
self.selected = self.observers.get(self.selected_index)
observer = self.app.core.custom_observers[self.selected]
self.name.set(observer.name)
self.cmd.set(observer.cmd)
self.save_button.config(state=tk.NORMAL)
self.delete_button.config(state=tk.NORMAL)
else:
self.selected_index = None
self.selected = None
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)

View file

@ -1,148 +0,0 @@
import tkinter as tk
from coretk.dialogs.dialog import Dialog
class Widget:
def __init__(self, name, command):
self.name = name
self.command = command
class ObserverWidgetsDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Observer Widgets", modal=True)
self.config_widgets = {}
self.widgets = None
self.save_button = None
self.delete_button = None
self.selected = None
self.selected_index = None
self.name = tk.StringVar()
self.command = tk.StringVar()
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_widgets()
self.draw_widget_fields()
self.draw_widget_buttons()
self.draw_apply_buttons()
def draw_widgets(self):
frame = tk.Frame(self)
frame.grid(sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=0, column=1, sticky="ns")
self.widgets = tk.Listbox(
frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set
)
self.widgets.grid(row=0, column=0, sticky="nsew")
self.widgets.bind("<<ListboxSelect>>", self.handle_widget_change)
scrollbar.config(command=self.widgets.yview)
def draw_widget_fields(self):
frame = tk.Frame(self)
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = tk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Command")
label.grid(row=1, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.command)
entry.grid(row=1, column=1, sticky="ew")
def draw_widget_buttons(self):
frame = tk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.save_button = tk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save
)
self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_apply_buttons(self):
frame = tk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(
frame, text="Save Configuration", command=self.click_save_configuration
)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_save_configuration(self):
pass
def click_create(self):
name = self.name.get()
if name not in self.config_widgets:
command = self.command.get()
widget = Widget(name, command)
self.config_widgets[name] = widget
self.widgets.insert(tk.END, name)
def click_save(self):
name = self.name.get()
if self.selected:
previous_name = self.selected
self.selected = name
widget = self.config_widgets.pop(previous_name)
widget.name = name
widget.command = self.command.get()
self.config_widgets[name] = widget
self.widgets.delete(self.selected_index)
self.widgets.insert(self.selected_index, name)
self.widgets.selection_set(self.selected_index)
def click_delete(self):
if self.selected:
self.widgets.delete(self.selected_index)
del self.config_widgets[self.selected]
self.selected = None
self.selected_index = None
self.name.set("")
self.command.set("")
self.widgets.selection_clear(0, tk.END)
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)
def handle_widget_change(self, event):
selection = self.widgets.curselection()
if selection:
self.selected_index = selection[0]
self.selected = self.widgets.get(self.selected_index)
widget = self.config_widgets[self.selected]
self.name.set(widget.name)
self.command.set(widget.command)
self.save_button.config(state=tk.NORMAL)
self.delete_button.config(state=tk.NORMAL)
else:
self.selected_index = None
self.selected = None
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)

View file

@ -0,0 +1,67 @@
import tkinter as tk
from tkinter import ttk
from coretk import appconfig
from coretk.dialogs.dialog import Dialog
class PreferencesDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Preferences", modal=True)
preferences = self.app.config["preferences"]
self.editor = tk.StringVar(value=preferences["editor"])
self.terminal = tk.StringVar(value=preferences["terminal"])
self.gui3d = tk.StringVar(value=preferences["gui3d"])
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.draw_programs()
self.draw_buttons()
def draw_programs(self):
frame = ttk.LabelFrame(self, text="Programs")
frame.grid(sticky="ew", pady=2)
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Editor")
label.grid(row=0, column=0, pady=2, padx=2, sticky="w")
combobox = ttk.Combobox(
frame, textvariable=self.editor, values=appconfig.EDITORS, state="readonly"
)
combobox.grid(row=0, column=1, sticky="ew")
label = ttk.Label(frame, text="Terminal")
label.grid(row=1, column=0, pady=2, padx=2, sticky="w")
combobox = ttk.Combobox(
frame,
textvariable=self.terminal,
values=appconfig.TERMINALS,
state="readonly",
)
combobox.grid(row=1, column=1, sticky="ew")
label = ttk.Label(frame, text="3D GUI")
label.grid(row=2, column=0, pady=2, padx=2, sticky="w")
entry = ttk.Entry(frame, textvariable=self.gui3d)
entry.grid(row=2, column=1, sticky="ew")
def draw_buttons(self):
frame = ttk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Save", command=self.click_save)
button.grid(row=0, column=0, sticky="ew")
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_save(self):
preferences = self.app.config["preferences"]
preferences["terminal"] = self.terminal.get()
preferences["editor"] = self.editor.get()
preferences["gui3d"] = self.gui3d.get()
self.app.save_config()
self.destroy()

View file

@ -1,6 +1,6 @@
import tkinter as tk
from tkinter import ttk
from coretk import appdirs
from coretk.coreclient import CoreServer
from coretk.dialogs.dialog import Dialog
@ -31,12 +31,12 @@ class ServersDialog(Dialog):
self.draw_apply_buttons()
def draw_servers(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(pady=2, sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=0, column=1, sticky="ns")
self.servers = tk.Listbox(
@ -51,61 +51,61 @@ class ServersDialog(Dialog):
scrollbar.config(command=self.servers.yview)
def draw_server_configuration(self):
label = tk.Label(self, text="Server Configuration")
label = ttk.Label(self, text="Server Configuration")
label.grid(pady=2, sticky="ew")
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew")
frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1)
frame.columnconfigure(5, weight=1)
label = tk.Label(frame, text="Name")
label = ttk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.name)
entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Address")
label = ttk.Label(frame, text="Address")
label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.address)
entry = ttk.Entry(frame, textvariable=self.address)
entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Port")
label = ttk.Label(frame, text="Port")
label.grid(row=0, column=4, sticky="w")
entry = tk.Entry(frame, textvariable=self.port)
entry = ttk.Entry(frame, textvariable=self.port)
entry.grid(row=0, column=5, sticky="ew")
def draw_servers_buttons(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create)
button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.save_button = tk.Button(
self.save_button = ttk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save
)
self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button(
self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_apply_buttons(self):
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(
button = ttk.Button(
frame, text="Save Configuration", command=self.click_save_configuration
)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_save_configuration(self):
@ -116,7 +116,8 @@ class ServersDialog(Dialog):
{"name": server.name, "address": server.address, "port": server.port}
)
self.app.config["servers"] = servers
appdirs.save_config(self.app.config)
self.app.save_config()
self.destroy()
def click_create(self):
name = self.name.get()

View file

@ -1,5 +1,5 @@
import logging
import tkinter as tk
from tkinter import ttk
from coretk.dialogs.dialog import Dialog
from coretk.widgets import ConfigFrame
@ -26,13 +26,13 @@ class SessionOptionsDialog(Dialog):
self.config_frame.draw_config()
self.config_frame.grid(sticky="nsew")
frame = tk.Frame(self)
frame = ttk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.save)
button = ttk.Button(frame, text="Save", command=self.save)
button.grid(row=0, column=0, pady=PAD_Y, padx=PAD_X, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, pady=PAD_Y, padx=PAD_X, sticky="ew")
def save(self):

View file

@ -1,6 +1,6 @@
import logging
import tkinter as tk
from tkinter.ttk import Scrollbar, Treeview
from tkinter import ttk
from core.api.grpc import core_pb2
from coretk.dialogs.dialog import Dialog
@ -9,12 +9,6 @@ from coretk.images import ImageEnum, Images
class SessionsDialog(Dialog):
def __init__(self, master, app):
"""
create session table instance
:param coretk.coreclient.CoreClient grpc: coregrpc
:param root.master master:
"""
super().__init__(master, app, "Sessions", modal=True)
self.selected = False
self.selected_id = None
@ -32,7 +26,7 @@ class SessionsDialog(Dialog):
write a short description
:return: nothing
"""
label = tk.Label(
label = ttk.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"
@ -42,7 +36,9 @@ class SessionsDialog(Dialog):
label.grid(row=0, sticky="ew", pady=5)
def draw_tree(self):
self.tree = Treeview(self, columns=("id", "state", "nodes"), show="headings")
self.tree = ttk.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")
@ -64,20 +60,20 @@ class SessionsDialog(Dialog):
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 = ttk.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 = ttk.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)
frame = ttk.Frame(self)
for i in range(4):
frame.columnconfigure(i, weight=1)
frame.grid(row=3, sticky="ew")
b = tk.Button(
b = ttk.Button(
frame,
image=Images.get(ImageEnum.DOCUMENTNEW),
text="New",
@ -85,7 +81,7 @@ class SessionsDialog(Dialog):
command=self.click_new,
)
b.grid(row=0, padx=2, sticky="ew")
b = tk.Button(
b = ttk.Button(
frame,
image=Images.get(ImageEnum.FILEOPEN),
text="Connect",
@ -93,7 +89,7 @@ class SessionsDialog(Dialog):
command=self.click_connect,
)
b.grid(row=0, column=1, padx=2, sticky="ew")
b = tk.Button(
b = ttk.Button(
frame,
image=Images.get(ImageEnum.EDITDELETE),
text="Shutdown",
@ -101,7 +97,7 @@ class SessionsDialog(Dialog):
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 = ttk.Button(frame, text="Cancel", command=self.click_new)
b.grid(row=0, column=3, padx=2, sticky="ew")
def click_new(self):

View file

@ -150,7 +150,7 @@ class CanvasGraph(tk.Canvas):
node.type, node.model
)
n = CanvasNode(
node.position.x, node.position.y, image, name, self, node.id
node.position.x, node.position.y, image, name, self.master, node.id
)
self.nodes[n.id] = n
core_id_to_canvas_id[node.id] = n.id
@ -419,14 +419,7 @@ class CanvasGraph(tk.Canvas):
plot_id = self.find_all()[0]
logging.info("add node event: %s - %s", plot_id, self.selected)
if self.selected == plot_id:
node = CanvasNode(
x=x,
y=y,
image=image,
node_type=node_name,
canvas=self,
core_id=self.core.peek_id(),
)
node = CanvasNode(x, y, image, node_name, self.master, self.core.peek_id())
self.nodes[node.id] = node
self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name)
return node
@ -491,10 +484,11 @@ class CanvasEdge:
class CanvasNode:
def __init__(self, x, y, image, node_type, canvas, core_id):
def __init__(self, x, y, image, node_type, app, core_id):
self.image = image
self.node_type = node_type
self.canvas = canvas
self.app = app
self.canvas = app.canvas
self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node"
)
@ -506,19 +500,30 @@ class CanvasNode:
x, y + 20, text=self.name, tags="nodename"
)
self.antenna_draw = WlanAntennaManager(self.canvas, self.id)
self.tooltip = CanvasTooltip(self.canvas)
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion)
self.canvas.tag_bind(self.id, "<Button-3>", self.context)
self.canvas.tag_bind(self.id, "<Double-Button-1>", self.double_click)
self.canvas.tag_bind(self.id, "<Control-1>", self.select_multiple)
self.tooltip = CanvasTooltip(self.canvas, self.id, text=self.name)
self.canvas.tag_bind(self.id, "<Enter>", self.on_enter)
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
self.edges = set()
self.wlans = []
self.moving = None
def on_enter(self, event):
if self.app.core.is_runtime() and self.app.core.observer:
self.tooltip.text.set("waiting...")
self.tooltip.on_enter(event)
output = self.app.core.run(self.core_id)
self.tooltip.text.set(output)
def on_leave(self, event):
self.tooltip.on_leave(event)
def click(self, event):
print("click")

View file

@ -4,7 +4,7 @@ from enum import Enum
from PIL import Image, ImageTk
from core.api.grpc import core_pb2
from coretk.appdirs import LOCAL_ICONS_PATH
from coretk.appconfig import LOCAL_ICONS_PATH
class Images:

View file

@ -7,11 +7,12 @@ import webbrowser
from tkinter import filedialog, messagebox
from core.api.grpc import core_pb2
from coretk.appdirs import XML_PATH
from coretk.appconfig import XML_PATH
from coretk.dialogs.canvasbackground import CanvasBackgroundDialog
from coretk.dialogs.canvassizeandscale import SizeAndScaleDialog
from coretk.dialogs.hooks import HooksDialog
from coretk.dialogs.observerwidgets import ObserverWidgetsDialog
from coretk.dialogs.observers import ObserverDialog
from coretk.dialogs.preferences import PreferencesDialog
from coretk.dialogs.servers import ServersDialog
from coretk.dialogs.sessionoptions import SessionOptionsDialog
from coretk.dialogs.sessions import SessionsDialog
@ -83,6 +84,10 @@ class MenuAction:
self.prompt_save_running_session()
self.app.core.open_xml(file_path)
def gui_preferences(self):
dialog = PreferencesDialog(self.app, self.app)
dialog.show()
def canvas_size_and_scale(self):
dialog = SizeAndScaleDialog(self.app, self.app)
dialog.show()
@ -118,5 +123,5 @@ class MenuAction:
dialog.show()
def edit_observer_widgets(self):
dialog = ObserverWidgetsDialog(self.app, self.app)
dialog = ObserverDialog(self.app, self.app)
dialog.show()

View file

@ -1,6 +1,8 @@
import tkinter as tk
from functools import partial
import coretk.menuaction as action
from coretk.coreclient import OBSERVERS
class Menubar(tk.Menu):
@ -92,7 +94,9 @@ class Menubar(tk.Menu):
menu.add_separator()
menu.add_command(label="Find...", accelerator="Ctrl+F", state=tk.DISABLED)
menu.add_command(label="Clear marker", state=tk.DISABLED)
menu.add_command(label="Preferences...", state=tk.DISABLED)
menu.add_command(
label="Preferences...", command=self.menuaction.gui_preferences
)
self.add_cascade(label="Edit", menu=menu)
def draw_canvas_menu(self):
@ -364,23 +368,35 @@ class Menubar(tk.Menu):
:param tkinter.Menu widget_menu: widget_menu
:return: nothing
"""
var = tk.StringVar(value="none")
menu = tk.Menu(widget_menu)
menu.add_command(label="None", state=tk.DISABLED)
menu.add_command(label="processes", state=tk.DISABLED)
menu.add_command(label="ifconfig", state=tk.DISABLED)
menu.add_command(label="IPv4 routes", state=tk.DISABLED)
menu.add_command(label="IPv6 routes", state=tk.DISABLED)
menu.add_command(label="OSPFv2 neighbors", state=tk.DISABLED)
menu.add_command(label="OSPFv3 neighbors", state=tk.DISABLED)
menu.add_command(label="Listening sockets", state=tk.DISABLED)
menu.add_command(label="IPv4 MFC entries", state=tk.DISABLED)
menu.add_command(label="IPv6 MFC entries", state=tk.DISABLED)
menu.add_command(label="firewall rules", state=tk.DISABLED)
menu.add_command(label="IPsec policies", state=tk.DISABLED)
menu.add_command(label="docker logs", state=tk.DISABLED)
menu.add_command(label="OSPFv3 MDR level", state=tk.DISABLED)
menu.add_command(label="PIM neighbors", state=tk.DISABLED)
menu.add_command(label="Edit...", command=self.menuaction.edit_observer_widgets)
menu.var = var
menu.add_command(
label="Edit Observers", command=self.menuaction.edit_observer_widgets
)
menu.add_separator()
menu.add_radiobutton(
label="None",
variable=var,
value="none",
command=lambda: self.app.core.set_observer(None),
)
for name in sorted(OBSERVERS):
cmd = OBSERVERS[name]
menu.add_radiobutton(
label=name,
variable=var,
value=name,
command=partial(self.app.core.set_observer, cmd),
)
for name in sorted(self.app.core.custom_observers):
observer = self.app.core.custom_observers[name]
menu.add_radiobutton(
label=name,
variable=var,
value=name,
command=partial(self.app.core.set_observer, observer.cmd),
)
widget_menu.add_cascade(label="Observer Widgets", menu=menu)
def create_adjacency_menu(self, widget_menu):

View file

@ -26,7 +26,7 @@ class FrameScroll(tk.LabelFrame):
self.canvas.grid(row=0, sticky="nsew", padx=2, pady=2)
self.canvas.columnconfigure(0, weight=1)
self.canvas.rowconfigure(0, weight=1)
self.scrollbar = tk.Scrollbar(
self.scrollbar = ttk.Scrollbar(
self, orient="vertical", command=self.canvas.yview
)
self.scrollbar.grid(row=0, column=1, sticky="ns")
@ -70,11 +70,11 @@ class ConfigFrame(FrameScroll):
for group_name in sorted(group_mapping):
group = group_mapping[group_name]
frame = tk.Frame(self.frame)
frame = ttk.Frame(self.frame)
frame.columnconfigure(1, weight=1)
self.frame.add(frame, text=group_name)
for index, option in enumerate(sorted(group, key=lambda x: x.name)):
label = tk.Label(frame, text=option.label)
label = ttk.Label(frame, text=option.label)
label.grid(row=index, pady=pady, padx=padx, sticky="w")
value = tk.StringVar()
if option.type == core_pb2.ConfigOptionType.BOOL:
@ -96,15 +96,15 @@ class ConfigFrame(FrameScroll):
combobox.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type == core_pb2.ConfigOptionType.STRING:
value.set(option.value)
entry = tk.Entry(frame, textvariable=value)
entry = ttk.Entry(frame, textvariable=value)
entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type in INT_TYPES:
value.set(option.value)
entry = tk.Entry(frame, textvariable=value)
entry = ttk.Entry(frame, textvariable=value)
entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type == core_pb2.ConfigOptionType.FLOAT:
value.set(option.value)
entry = tk.Entry(frame, textvariable=value)
entry = ttk.Entry(frame, textvariable=value)
entry.grid(row=index, column=1, sticky="ew", pady=pady)
else:
logging.error("unhandled config option type: %s", option.type)
@ -131,7 +131,7 @@ class ListboxScroll(tk.LabelFrame):
super().__init__(master, cnf, **kw)
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.scrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
self.scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL)
self.scrollbar.grid(row=0, column=1, sticky="ns")
self.listbox = tk.Listbox(
self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set
@ -149,5 +149,5 @@ class CheckboxList(FrameScroll):
def add(self, name, checked):
var = tk.BooleanVar(value=checked)
func = partial(self.clicked, name, var)
checkbox = tk.Checkbutton(self.frame, text=name, variable=var, command=func)
checkbox = ttk.Checkbutton(self.frame, text=name, variable=var, command=func)
checkbox.grid(sticky="w")

View file

@ -184,9 +184,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("stop session: %s", request)
session = self.get_session(request.session_id, context)
session.data_collect()
session.set_state(EventTypes.DATACOLLECT_STATE)
session.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
session.clear()
session.set_state(EventTypes.SHUTDOWN_STATE)
session.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
return core_pb2.StopSessionResponse(result=True)
def CreateSession(self, request, context):