custom nodes dialog works for creating, editing, and saving to config in basic case

This commit is contained in:
bharnden 2019-11-07 11:33:40 -08:00
parent 613568ca28
commit 2873c32c23
7 changed files with 78 additions and 21 deletions

View file

@ -42,7 +42,10 @@ def check_directory():
for background in LOCAL_BACKGROUND_PATH.glob("*"): for background in LOCAL_BACKGROUND_PATH.glob("*"):
new_background = BACKGROUNDS_PATH.joinpath(background.name) new_background = BACKGROUNDS_PATH.joinpath(background.name)
shutil.copy(background, new_background) shutil.copy(background, new_background)
config = {"servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}]} config = {
"servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}],
"nodes": [],
}
save_config(config) save_config(config)

View file

@ -8,6 +8,7 @@ from collections import OrderedDict
from core.api.grpc import client, core_pb2 from core.api.grpc import client, core_pb2
from coretk.coretocanvas import CoreToCanvasMapping from coretk.coretocanvas import CoreToCanvasMapping
from coretk.dialogs.sessions import SessionsDialog from coretk.dialogs.sessions import SessionsDialog
from coretk.images import 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.wlannodeconfig import WlanNodeConfig from coretk.wlannodeconfig import WlanNodeConfig
@ -65,9 +66,10 @@ class CoreServer:
class CustomNode: class CustomNode:
def __init__(self, name, image, services): def __init__(self, name, image, image_file, services):
self.name = name self.name = name
self.image = image self.image = image
self.image_file = image_file
self.services = services self.services = services
@ -83,15 +85,11 @@ class CoreClient:
self.master = app.master self.master = app.master
self.interface_helper = None self.interface_helper = None
self.services = {} self.services = {}
self.custom_nodes = {}
# distributed server data # loaded configuration data
self.servers = {} self.servers = {}
for server_config in self.app.config["servers"]: self.custom_nodes = {}
server = CoreServer( self.read_config()
server_config["name"], server_config["address"], server_config["port"]
)
self.servers[server.name] = server
# data for managing the current session # data for managing the current session
self.nodes = {} self.nodes = {}
@ -106,6 +104,23 @@ class CoreClient:
self.mobilityconfig_management = MobilityNodeConfig() self.mobilityconfig_management = MobilityNodeConfig()
self.emane_config = None self.emane_config = None
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"]
)
self.servers[server.name] = server
# read custom nodes
for node in self.app.config["nodes"]:
image_file = node["image"]
image = Images.get_custom(image_file)
custom_node = CustomNode(
node["name"], image, image_file, set(node["services"])
)
self.custom_nodes[custom_node.name] = custom_node
def handle_events(self, event): def handle_events(self, event):
logging.info("event: %s", event) logging.info("event: %s", event)
if event.link_event is not None: if event.link_event is not None:

View file

@ -1,8 +1,11 @@
import logging
import tkinter as tk import tkinter as tk
from pathlib import Path
from coretk import appdirs
from coretk.coreclient import CustomNode from coretk.coreclient import CustomNode
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.nodeicon import IconDialog from coretk.dialogs.icondialog import IconDialog
from coretk.widgets import CheckboxList, ListboxScroll from coretk.widgets import CheckboxList, ListboxScroll
@ -86,6 +89,7 @@ class CustomNodesDialog(Dialog):
self.name = tk.StringVar() self.name = tk.StringVar()
self.image_button = None self.image_button = None
self.image = None self.image = None
self.image_file = None
self.services = set() self.services = set()
self.selected = None self.selected = None
self.selected_index = None self.selected_index = None
@ -145,17 +149,25 @@ class CustomNodesDialog(Dialog):
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.click_edit) button = tk.Button(frame, text="Save", command=self.click_save)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy) button = tk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def reset_values(self):
self.name.set("")
self.image = None
self.image_file = None
self.services = set()
self.image_button.config(image="")
def click_icon(self): def click_icon(self):
dialog = IconDialog(self, self.app, self.name.get(), self.image) dialog = IconDialog(self, self.app, self.name.get(), self.image)
dialog.show() dialog.show()
if dialog.image: if dialog.image:
self.image = dialog.image self.image = dialog.image
self.image_file = dialog.file_path.get()
self.image_button.config(image=self.image) self.image_button.config(image=self.image)
def click_services(self): def click_services(self):
@ -164,22 +176,44 @@ class CustomNodesDialog(Dialog):
if dialog.current_services is not None: if dialog.current_services is not None:
self.services = dialog.current_services self.services = dialog.current_services
def click_save(self):
self.app.config["nodes"].clear()
for name in sorted(self.app.core.custom_nodes):
custom_node = self.app.core.custom_nodes[name]
self.app.config["nodes"].append(
{
"name": custom_node.name,
"image": custom_node.image_file,
"services": list(custom_node.services),
}
)
logging.info("saving custom nodes: %s", self.app.config["nodes"])
appdirs.save_config(self.app.config)
def click_create(self): def click_create(self):
name = self.name.get() name = self.name.get()
if name not in self.app.core.custom_nodes: if name not in self.app.core.custom_nodes:
custom_node = CustomNode(name, self.image, self.services) custom_node = CustomNode(
name, self.image, Path(self.image_file).name, set(self.services)
)
self.app.core.custom_nodes[name] = custom_node self.app.core.custom_nodes[name] = custom_node
self.nodes_list.listbox.insert(tk.END, name) self.nodes_list.listbox.insert(tk.END, name)
self.reset_values() self.reset_values()
def reset_values(self):
self.name.set("")
self.image = None
self.services = set()
self.image_button.config(image="")
def click_edit(self): def click_edit(self):
pass name = self.name.get()
if self.selected:
previous_name = self.selected
self.selected = name
custom_node = self.app.core.custom_nodes.pop(previous_name)
custom_node.name = name
custom_node.image = self.image
custom_node.image_file = Path(self.image_file).name
custom_node.services = self.services
self.app.core.custom_nodes[name] = custom_node
self.nodes_list.listbox.delete(self.selected_index)
self.nodes_list.listbox.insert(self.selected_index, name)
self.nodes_list.listbox.selection_set(self.selected_index)
def click_delete(self): def click_delete(self):
if self.selected and self.selected in self.app.core.custom_nodes: if self.selected and self.selected in self.app.core.custom_nodes:
@ -198,6 +232,7 @@ class CustomNodesDialog(Dialog):
self.name.set(custom_node.name) self.name.set(custom_node.name)
self.services = custom_node.services self.services = custom_node.services
self.image = custom_node.image self.image = custom_node.image
self.image_file = custom_node.image_file
self.image_button.config(image=self.image) self.image_button.config(image=self.image)
self.edit_button.config(state=tk.NORMAL) self.edit_button.config(state=tk.NORMAL)
self.delete_button.config(state=tk.NORMAL) self.delete_button.config(state=tk.NORMAL)

View file

@ -2,7 +2,7 @@ import tkinter as tk
from tkinter import ttk from tkinter import ttk
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.nodeicon import IconDialog from coretk.dialogs.icondialog import IconDialog
from coretk.dialogs.nodeservice import NodeServicesDialog from coretk.dialogs.nodeservice import NodeServicesDialog
NETWORKNODETYPES = ["switch", "hub", "wlan", "rj45", "tunnel"] NETWORKNODETYPES = ["switch", "hub", "wlan", "rj45", "tunnel"]

View file

@ -5,7 +5,7 @@ wlan configuration
import tkinter as tk import tkinter as tk
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.nodeicon import IconDialog from coretk.dialogs.icondialog import IconDialog
class WlanConfigDialog(Dialog): class WlanConfigDialog(Dialog):

View file

@ -29,6 +29,10 @@ class Images:
def get(cls, image): def get(cls, image):
return cls.images[image.value] return cls.images[image.value]
@classmethod
def get_custom(cls, name):
return cls.images[name]
@classmethod @classmethod
def convert_type_and_model_to_image(cls, node_type, node_model): def convert_type_and_model_to_image(cls, node_type, node_model):
""" """