custom nodes dialog works for creating, editing, and saving to config in basic case
This commit is contained in:
parent
613568ca28
commit
2873c32c23
7 changed files with 78 additions and 21 deletions
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Add table
Reference in a new issue