merged latest from coretk and updated code to use ttk widgets

This commit is contained in:
Blake Harnden 2019-11-13 08:38:08 -08:00
commit 02243684d9
7 changed files with 411 additions and 131 deletions

View file

@ -11,6 +11,7 @@ from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
from coretk.images import NODE_WIDTH, Images from coretk.images import NODE_WIDTH, Images
from coretk.interface import Interface, InterfaceManager from coretk.interface import Interface, InterfaceManager
from coretk.mobilitynodeconfig import MobilityNodeConfig from coretk.mobilitynodeconfig import MobilityNodeConfig
from coretk.servicenodeconfig import ServiceNodeConfig
from coretk.wlannodeconfig import WlanNodeConfig from coretk.wlannodeconfig import WlanNodeConfig
NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"} NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"}
@ -124,6 +125,7 @@ class CoreClient:
self.mobilityconfig_management = MobilityNodeConfig() self.mobilityconfig_management = MobilityNodeConfig()
self.emaneconfig_management = EmaneModelNodeConfig(app) self.emaneconfig_management = EmaneModelNodeConfig(app)
self.emane_config = None self.emane_config = None
self.serviceconfig_manager = ServiceNodeConfig(app)
def set_observer(self, value): def set_observer(self, value):
self.observer = value self.observer = value
@ -359,6 +361,13 @@ class CoreClient:
) )
logging.debug("Start session %s, result: %s", self.session_id, response.result) logging.debug("Start session %s, result: %s", self.session_id, response.result)
response = self.client.get_service_defaults(self.session_id)
for default in response.defaults:
print(default.node_type)
print(default.services)
response = self.client.get_node_service(self.session_id, 5, "FTP")
print(response)
def stop_session(self): def stop_session(self):
response = self.client.stop_session(session_id=self.session_id) response = self.client.stop_session(session_id=self.session_id)
logging.debug("coregrpc.py Stop session, result: %s", response.result) logging.debug("coregrpc.py Stop session, result: %s", response.result)
@ -488,6 +497,12 @@ class CoreClient:
if node_type == core_pb2.NodeType.EMANE: if node_type == core_pb2.NodeType.EMANE:
self.emaneconfig_management.set_default_config(nid) self.emaneconfig_management.set_default_config(nid)
# set default service configurations
if node_type == core_pb2.NodeType.DEFAULT:
self.serviceconfig_manager.node_default_services_configuration(
node_id=nid, node_model=node_model
)
self.nodes[canvas_id] = create_node self.nodes[canvas_id] = create_node
self.core_mapping.map_core_id_to_canvas_id(nid, canvas_id) self.core_mapping.map_core_id_to_canvas_id(nid, canvas_id)
logging.debug( logging.debug(

View file

@ -4,7 +4,7 @@ from tkinter import ttk
from coretk.coreclient import DEFAULT_NODES from coretk.coreclient import DEFAULT_NODES
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog from coretk.dialogs.icondialog import IconDialog
from coretk.dialogs.nodeservice import NodeServicesDialog from coretk.dialogs.nodeservice import NodeService
class NodeConfigDialog(Dialog): class NodeConfigDialog(Dialog):
@ -85,7 +85,7 @@ class NodeConfigDialog(Dialog):
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def click_services(self): def click_services(self):
dialog = NodeServicesDialog(self, self.app, self.canvas_node) dialog = NodeService(self, self.app, self.canvas_node)
dialog.show() dialog.show()
def click_icon(self): def click_icon(self):

View file

@ -5,154 +5,100 @@ import tkinter as tk
from tkinter import messagebox, ttk from tkinter import messagebox, ttk
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.serviceconfiguration import ServiceConfiguration
from coretk.widgets import CheckboxList, ListboxScroll
class NodeServicesDialog(Dialog): class NodeService(Dialog):
def __init__(self, master, app, canvas_node): def __init__(self, master, app, canvas_node, services=None):
super().__init__(master, app, "Node Services", modal=True) super().__init__(master, app, "Node Services", modal=True)
self.canvas_node = canvas_node self.canvas_node = canvas_node
self.core_groups = [] self.groups = None
self.service_to_config = None self.services = None
self.config_frame = None self.current = None
self.services_list = None if services is None:
services = set()
self.current_services = services
self.draw() self.draw()
def draw(self): def draw(self):
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
self.config_frame = ttk.Frame(self)
self.config_frame.columnconfigure(0, weight=1)
self.config_frame.columnconfigure(1, weight=1)
self.config_frame.columnconfigure(2, weight=1)
self.config_frame.rowconfigure(0, weight=1)
self.config_frame.grid(row=0, column=0, sticky="nsew")
self.draw_group()
self.draw_services()
self.draw_current_services()
self.draw_buttons()
def draw_group(self):
"""
draw the group tab
:return: nothing
"""
frame = ttk.Frame(self.config_frame)
frame.columnconfigure(0, weight=1)
frame.rowconfigure(1, weight=1)
frame.grid(row=0, column=0, padx=3, pady=3, sticky="nsew")
label = ttk.Label(frame, text="Group")
label.grid(row=0, column=0, sticky="ew")
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=1, column=1, sticky="ns")
listbox = tk.Listbox(
frame,
selectmode=tk.SINGLE,
yscrollcommand=scrollbar.set,
relief=tk.FLAT,
highlightthickness=0.5,
bd=0,
)
listbox.grid(row=1, column=0, sticky="nsew")
listbox.bind("<<ListboxSelect>>", self.handle_group_change)
for group in sorted(self.app.core.services):
listbox.insert(tk.END, group)
scrollbar.config(command=listbox.yview)
def draw_services(self):
frame = ttk.Frame(self.config_frame)
frame.columnconfigure(0, weight=1)
frame.rowconfigure(1, weight=1)
frame.grid(row=0, column=1, padx=3, pady=3, sticky="nsew")
label = ttk.Label(frame, text="Group services")
label.grid(row=0, column=0, sticky="ew")
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=1, column=1, sticky="ns")
self.services_list = tk.Listbox(
frame,
selectmode=tk.SINGLE,
yscrollcommand=scrollbar.set,
relief=tk.FLAT,
highlightthickness=0.5,
bd=0,
)
self.services_list.grid(row=1, column=0, sticky="nsew")
self.services_list.bind("<<ListboxSelect>>", self.handle_service_change)
scrollbar.config(command=self.services_list.yview)
def draw_current_services(self):
frame = ttk.Frame(self.config_frame)
frame.columnconfigure(0, weight=1)
frame.rowconfigure(1, weight=1)
frame.grid(row=0, column=2, padx=3, pady=3, sticky="nsew")
label = ttk.Label(frame, text="Current services")
label.grid(row=0, column=0, sticky="ew")
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=1, column=1, sticky="ns")
listbox = tk.Listbox(
frame,
selectmode=tk.MULTIPLE,
yscrollcommand=scrollbar.set,
relief=tk.FLAT,
highlightthickness=0.5,
bd=0,
)
listbox.grid(row=1, column=0, sticky="nsew")
scrollbar.config(command=listbox.yview)
def draw_buttons(self):
frame = ttk.Frame(self) frame = ttk.Frame(self)
frame.columnconfigure(0, weight=1) frame.grid(stick="nsew")
frame.columnconfigure(1, weight=1) frame.rowconfigure(0, weight=1)
frame.columnconfigure(2, weight=1) for i in range(3):
frame.grid(row=1, column=0, sticky="ew") frame.columnconfigure(i, weight=1)
self.groups = ListboxScroll(frame, text="Groups")
self.groups.grid(row=0, column=0, sticky="nsew")
for group in sorted(self.app.core.services):
self.groups.listbox.insert(tk.END, group)
self.groups.listbox.bind("<<ListboxSelect>>", self.handle_group_change)
self.groups.listbox.selection_set(0)
self.services = CheckboxList(
frame, text="Services", clicked=self.service_clicked
)
self.services.grid(row=0, column=1, sticky="nsew")
self.current = ListboxScroll(frame, text="Selected")
self.current.grid(row=0, column=2, sticky="nsew")
for service in sorted(self.current_services):
self.current.listbox.insert(tk.END, service)
frame = ttk.Frame(self)
frame.grid(stick="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Configure", command=self.click_configure) button = ttk.Button(frame, text="Configure", command=self.click_configure)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = ttk.Button(frame, text="Save", command=self.click_save)
button = ttk.Button(frame, text="Apply")
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
button = ttk.Button(frame, text="Cancel", command=self.click_cancel)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=2, sticky="ew") button.grid(row=0, column=2, sticky="ew")
# trigger group change
self.groups.listbox.event_generate("<<ListboxSelect>>")
def handle_group_change(self, event): def handle_group_change(self, event):
listbox = event.widget selection = self.groups.listbox.curselection()
cur_selection = listbox.curselection() if selection:
if cur_selection: index = selection[0]
s = listbox.get(listbox.curselection()) group = self.groups.listbox.get(index)
self.display_group_services(s) self.services.clear()
for service in sorted(self.app.core.services[group], key=lambda x: x.name):
checked = service.name in self.current_services
self.services.add(service.name, checked)
def display_group_services(self, group_name): def service_clicked(self, name, var):
self.services_list.delete(0, tk.END) if var.get() and name not in self.current_services:
for service in sorted(self.app.core.services[group_name], key=lambda x: x.name): self.current_services.add(name)
self.services_list.insert(tk.END, service.name) elif not var.get() and name in self.current_services:
self.current_services.remove(name)
def handle_service_change(self, event): self.current.listbox.delete(0, tk.END)
print("select group service") for name in sorted(self.current_services):
listbox = event.widget self.current.listbox.insert(tk.END, name)
cur_selection = listbox.curselection()
if cur_selection:
s = listbox.get(listbox.curselection())
self.service_to_config = s
else:
self.service_to_config = None
def click_configure(self): def click_configure(self):
if self.service_to_config is None: current_selection = self.current.listbox.curselection()
messagebox.showinfo("CORE info", "Choose a service to configure.") if len(current_selection):
dialog = ServiceConfiguration(
master=self,
app=self.app,
service_name=self.current.listbox.get(current_selection[0]),
canvas_node=self.canvas_node,
)
dialog.show()
else: else:
print(self.service_to_config) messagebox.showinfo(
"Node service configuration", "Select a service to configure"
)
def click_save(self):
print("not implemented")
print(self.current_services)
def click_cancel(self):
self.current_services = None
self.destroy()

View file

@ -0,0 +1,281 @@
"Service configuration dialog"
import logging
import tkinter as tk
from tkinter import ttk
from coretk.dialogs.dialog import Dialog
from coretk.images import ImageEnum, Images
from coretk.widgets import ListboxScroll
class ServiceConfiguration(Dialog):
def __init__(self, master, app, service_name, canvas_node):
super().__init__(master, app, f"{service_name} service", modal=True)
self.app = app
self.service_name = service_name
self.metadata = tk.StringVar()
self.filename = tk.StringVar()
self.radiovar = tk.IntVar()
self.radiovar.set(2)
self.startup_index = tk.IntVar()
self.start_time = tk.IntVar()
self.documentnew_img = Images.get(ImageEnum.DOCUMENTNEW, 16)
self.editdelete_img = Images.get(ImageEnum.EDITDELETE, 16)
self.tab_parent = None
self.filenames = ["test1", "test2", "test3"]
self.metadata_entry = None
self.filename_combobox = None
self.startup_commands_listbox = None
self.shutdown_commands_listbox = None
self.validate_commands_listbox = None
self.draw()
def draw(self):
# self.columnconfigure(1, weight=1)
frame = ttk.Frame(self)
frame1 = ttk.Frame(frame)
label = ttk.Label(frame1, text=self.service_name)
label.grid(row=0, column=0, sticky="ew")
frame1.grid(row=0, column=0)
frame2 = ttk.Frame(frame)
# frame2.columnconfigure(0, weight=1)
# frame2.columnconfigure(1, weight=4)
label = ttk.Label(frame2, text="Meta-data")
label.grid(row=0, column=0)
self.metadata_entry = ttk.Entry(frame2, textvariable=self.metadata)
self.metadata_entry.grid(row=0, column=1)
frame2.grid(row=1, column=0)
frame.grid(row=0, column=0)
frame = ttk.Frame(self)
self.tab_parent = ttk.Notebook(frame)
tab1 = ttk.Frame(self.tab_parent)
tab2 = ttk.Frame(self.tab_parent)
tab3 = ttk.Frame(self.tab_parent)
tab4 = ttk.Frame(self.tab_parent)
tab1.columnconfigure(0, weight=1)
tab2.columnconfigure(0, weight=1)
tab3.columnconfigure(0, weight=1)
tab4.columnconfigure(0, weight=1)
self.tab_parent.add(tab1, text="Files", sticky="nsew")
self.tab_parent.add(tab2, text="Directories", sticky="nsew")
self.tab_parent.add(tab3, text="Startup/shutdown", sticky="nsew")
self.tab_parent.add(tab4, text="Configuration", sticky="nsew")
self.tab_parent.grid(row=0, column=0, sticky="nsew")
frame.grid(row=1, column=0, sticky="nsew")
# tab 1
label = ttk.Label(
tab1, text="Config files and scripts that are generated for this service."
)
label.grid(row=0, column=0, sticky="nsew")
frame = ttk.Frame(tab1)
label = ttk.Label(frame, text="File name: ")
label.grid(row=0, column=0)
self.filename_combobox = ttk.Combobox(frame, values=self.filenames)
self.filename_combobox.grid(row=0, column=1)
self.filename_combobox.current(0)
button = ttk.Button(frame, image=self.documentnew_img)
button.bind("<Button-1>", self.add_filename)
button.grid(row=0, column=2)
button = ttk.Button(frame, image=self.editdelete_img)
button.bind("<Button-1>", self.delete_filename)
button.grid(row=0, column=3)
frame.grid(row=1, column=0, sticky="nsew")
frame = ttk.Frame(tab1)
button = ttk.Radiobutton(
frame,
variable=self.radiovar,
text="Copy this source file:",
value=1,
state="disabled",
)
button.grid(row=0, column=0)
entry = ttk.Entry(frame, state=tk.DISABLED)
entry.grid(row=0, column=1)
image = Images.get(ImageEnum.FILEOPEN, 16)
button = ttk.Button(frame, image=image)
button.image = image
button.grid(row=0, column=2)
frame.grid(row=2, column=0, sticky="nsew")
frame = ttk.Frame(tab1)
button = ttk.Radiobutton(
frame,
variable=self.radiovar,
text="Use text below for file contents:",
value=2,
)
button.grid(row=0, column=0)
image = Images.get(ImageEnum.FILEOPEN, 16)
button = ttk.Button(frame, image=image)
button.image = image
button.grid(row=0, column=1)
image = Images.get(ImageEnum.DOCUMENTSAVE, 16)
button = ttk.Button(frame, image=image)
button.image = image
button.grid(row=0, column=2)
frame.grid(row=3, column=0, sticky="nsew")
# tab 2
label = ttk.Label(
tab2,
text="Directories required by this service that are unique for each node.",
)
label.grid(row=0, column=0, sticky="nsew")
# tab 3
for i in range(3):
label_frame = None
if i == 0:
label_frame = ttk.LabelFrame(tab3, text="Startup commands")
elif i == 1:
label_frame = ttk.LabelFrame(tab3, text="Shutdown commands")
elif i == 2:
label_frame = ttk.LabelFrame(tab3, text="Validation commands")
label_frame.columnconfigure(0, weight=1)
frame = ttk.Frame(label_frame)
frame.columnconfigure(0, weight=1)
entry = ttk.Entry(frame, textvariable=tk.StringVar())
entry.grid(row=0, column=0, stick="nsew")
button = ttk.Button(frame, image=self.documentnew_img)
button.bind("<Button-1>", self.add_command)
button.grid(row=0, column=1, sticky="nsew")
button = ttk.Button(frame, image=self.editdelete_img)
button.grid(row=0, column=2, sticky="nsew")
button.bind("<Button-1>", self.delete_command)
frame.grid(row=0, column=0, sticky="nsew")
listbox_scroll = ListboxScroll(label_frame)
listbox_scroll.listbox.bind("<<ListboxSelect>>", self.update_entry)
listbox_scroll.listbox.config(height=4)
listbox_scroll.grid(row=1, column=0, sticky="nsew")
if i == 0:
self.startup_commands_listbox = listbox_scroll.listbox
elif i == 1:
self.shutdown_commands_listbox = listbox_scroll.listbox
elif i == 2:
self.validate_commands_listbox = listbox_scroll.listbox
label_frame.grid(row=i, column=0, sticky="nsew")
# tab 4
for i in range(2):
if i == 0:
label_frame = ttk.LabelFrame(tab4, text="Executables")
elif i == 1:
label_frame = ttk.LabelFrame(tab4, text="Dependencies")
label_frame.columnconfigure(0, weight=1)
listbox_scroll = ListboxScroll(label_frame)
listbox_scroll.listbox.config(height=4, state="disabled")
listbox_scroll.grid(row=0, column=0, sticky="nsew")
label_frame.grid(row=i, column=0, sticky="nsew")
for i in range(3):
frame = ttk.Frame(tab4)
frame.columnconfigure(0, weight=1)
if i == 0:
label = ttk.Label(frame, text="Validation time:")
elif i == 1:
label = ttk.Label(frame, text="Validation mode:")
elif i == 2:
label = ttk.Label(frame, text="Validation period:")
label.grid(row=i, column=0)
entry = ttk.Entry(frame, state="disabled", textvariable=tk.StringVar())
entry.grid(row=i, column=1)
frame.grid(row=2 + i, column=0, sticky="nsew")
button = ttk.Button(
self, text="onle store values that have changed from their defaults"
)
button.grid(row=2, column=0)
frame = ttk.Frame(self)
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="nsew")
button = ttk.Button(
frame, text="Dafults", command=self.click_defaults, state="disabled"
)
button.grid(row=0, column=1, sticky="nsew")
button = ttk.Button(
frame, text="Copy...", command=self.click_copy, state="disabled"
)
button.grid(row=0, column=2, sticky="nsew")
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=3, sticky="nsew")
frame.grid(row=3, column=0)
def add_filename(self, event):
frame_contains_button = event.widget.master
combobox = frame_contains_button.grid_slaves(row=0, column=1)[0]
filename = combobox.get()
if filename not in combobox["values"]:
combobox["values"] += (filename,)
def delete_filename(self, event):
frame_comntains_button = event.widget.master
combobox = frame_comntains_button.grid_slaves(row=0, column=1)[0]
filename = combobox.get()
if filename in combobox["values"]:
combobox["values"] = tuple([x for x in combobox["values"] if x != filename])
combobox.set("")
def add_command(self, event):
frame_contains_button = event.widget.master
listbox = frame_contains_button.master.grid_slaves(row=1, column=0)[0].listbox
command_to_add = frame_contains_button.grid_slaves(row=0, column=0)[0].get()
if command_to_add == "":
return
for cmd in listbox.get(0, tk.END):
if cmd == command_to_add:
return
listbox.insert(tk.END, command_to_add)
def update_entry(self, event):
listbox = event.widget
current_selection = listbox.curselection()
if len(current_selection) > 0:
cmd = listbox.get(current_selection[0])
entry = listbox.master.master.grid_slaves(row=0, column=0)[0].grid_slaves(
row=0, column=0
)[0]
entry.delete(0, "end")
entry.insert(0, cmd)
def delete_command(self, event):
button = event.widget
frame_contains_button = button.master
listbox = frame_contains_button.master.grid_slaves(row=1, column=0)[0].listbox
current_selection = listbox.curselection()
if len(current_selection) > 0:
listbox.delete(current_selection[0])
entry = frame_contains_button.grid_slaves(row=0, column=0)[0]
entry.delete(0, tk.END)
def click_apply(self):
metadata = self.metadata_entry.get()
filenames = list(self.filename_combobox["values"])
startup_commands = self.startup_commands_listbox.get(0, "end")
shutdown_commands = self.shutdown_commands_listbox.get(0, "end")
validate_commands = self.validate_commands_listbox.get(0, "end")
logging.info(
"%s, %s, %s, %s, %s",
metadata,
filenames,
startup_commands,
shutdown_commands,
validate_commands,
)
def click_defaults(self):
logging.info("not implemented")
def click_copy(self):
logging.info("not implemented")
def click_cancel(self):
logging.info("not implemented")

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -117,6 +117,7 @@ class ImageEnum(Enum):
OBSERVE = "observe" OBSERVE = "observe"
RUN = "run" RUN = "run"
DOCUMENTNEW = "document-new" DOCUMENTNEW = "document-new"
DOCUMENTSAVE = "document-save"
FILEOPEN = "fileopen" FILEOPEN = "fileopen"
EDITDELETE = "edit-delete" EDITDELETE = "edit-delete"
ANTENNA = "antenna" ANTENNA = "antenna"

View file

@ -0,0 +1,37 @@
"""
service node configuration
"""
import logging
class ServiceNodeConfig:
def __init__(self, app):
self.app = app
self.configurations = {}
self.default_services = {}
def node_default_services_configuration(self, node_id, node_model):
"""
set the default configurations for the default services of a node
:param coretk.graph.CanvasNode canvas_node: canvas node object
:return: nothing
"""
session_id = self.app.core.session_id
client = self.app.core.client
if len(self.default_services) == 0:
response = client.get_service_defaults(session_id)
logging.info("session default services: %s", response)
for default in response.defaults:
self.default_services[default.node_type] = default.services
self.configurations[node_id] = {}
for default in self.default_services[node_model]:
response = client.get_node_service(session_id, node_id, default)
logging.info(
"servicenodeconfig.py get node service (%s), result: %s",
node_id,
response,
)
self.configurations[node_id][default] = response.service