class GlobalEmaneDialog(Dialog): def __init__(self, master: tk.BaseWidget, app: "Application") -> None: super().__init__(app, "EMANE Configuration", master=master) self.config_frame: Optional[ConfigFrame] = None self.enabled: bool = not self.app.core.is_runtime() self.draw() def draw(self) -> None: self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) session = self.app.core.session self.config_frame = ConfigFrame(self.top, self.app, session.emane_config, self.enabled) self.config_frame.draw_config() self.config_frame.grid(sticky=tk.NSEW, pady=PADY) self.draw_buttons() def draw_buttons(self) -> None: frame = ttk.Frame(self.top) frame.grid(sticky=tk.EW) for i in range(2): frame.columnconfigure(i, weight=1) state = tk.NORMAL if self.enabled else tk.DISABLED button = ttk.Button(frame, text="Apply", command=self.click_apply, state=state) button.grid(row=0, column=0, sticky=tk.EW, padx=PADX) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky=tk.EW) def click_apply(self) -> None: self.config_frame.parse_config() self.destroy()
class GlobalEmaneDialog(Dialog): def __init__(self, master, app): super().__init__(master, app, "EMANE Configuration", modal=True) self.config_frame = None self.draw() def draw(self): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.app.core.emane_config) self.config_frame.draw_config() self.config_frame.grid(sticky="nsew", pady=PADY) self.draw_spacer() self.draw_buttons() def draw_buttons(self): frame = ttk.Frame(self.top) frame.grid(sticky="ew") for i in range(2): frame.columnconfigure(i, weight=1) button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, sticky="ew", padx=PADX) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky="ew") def click_apply(self): self.config_frame.parse_config() self.destroy()
class SessionOptionsDialog(Dialog): def __init__(self, app: "Application") -> None: super().__init__(app, "Session Options") self.config_frame: Optional[ConfigFrame] = None self.has_error: bool = False self.enabled: bool = not self.app.core.is_runtime() if not self.has_error: self.draw() def draw(self) -> None: self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) options = self.app.core.session.options self.config_frame = ConfigFrame(self.top, self.app, options, self.enabled) self.config_frame.draw_config() self.config_frame.grid(sticky=tk.NSEW, pady=PADY) frame = ttk.Frame(self.top) frame.grid(sticky=tk.EW) for i in range(2): frame.columnconfigure(i, weight=1) state = tk.NORMAL if self.enabled else tk.DISABLED button = ttk.Button(frame, text="Save", command=self.save, state=state) button.grid(row=0, column=0, padx=PADX, sticky=tk.EW) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky=tk.EW) def save(self) -> None: config = self.config_frame.parse_config() for key, value in config.items(): self.app.core.session.options[key].value = value self.destroy()
class EmaneModelDialog(Dialog): def __init__( self, master: tk.BaseWidget, app: "Application", node: Node, model: str, iface_id: int = None, ) -> None: super().__init__(app, f"{node.name} {model} Configuration", master=master) self.node: Node = node self.model: str = f"emane_{model}" self.iface_id: int = iface_id self.config_frame: Optional[ConfigFrame] = None self.enabled: bool = not self.app.core.is_runtime() self.has_error: bool = False try: config = self.node.emane_model_configs.get( (self.model, self.iface_id)) if not config: config = self.app.core.get_emane_model_config( self.node.id, self.model, self.iface_id) self.config: Dict[str, ConfigOption] = config self.draw() except grpc.RpcError as e: self.app.show_grpc_exception("Get EMANE Config Error", e) self.has_error: bool = True self.destroy() def draw(self) -> None: self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.config, self.enabled) self.config_frame.draw_config() self.config_frame.grid(sticky=tk.NSEW, pady=PADY) self.draw_buttons() def draw_buttons(self) -> None: frame = ttk.Frame(self.top) frame.grid(sticky=tk.EW) for i in range(2): frame.columnconfigure(i, weight=1) state = tk.NORMAL if self.enabled else tk.DISABLED button = ttk.Button(frame, text="Apply", command=self.click_apply, state=state) button.grid(row=0, column=0, sticky=tk.EW, padx=PADX) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky=tk.EW) def click_apply(self) -> None: self.config_frame.parse_config() key = (self.model, self.iface_id) self.node.emane_model_configs[key] = self.config self.destroy()
class WlanConfigDialog(Dialog): def __init__(self, master, app, canvas_node): super().__init__(master, app, f"{canvas_node.core_node.name} Wlan Configuration", modal=True) self.canvas_node = canvas_node self.node = canvas_node.core_node self.config_frame = None try: self.config = self.app.core.get_wlan_config(self.node.id) except grpc.RpcError as e: show_grpc_error(e) self.destroy() self.draw() def draw(self): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.config) self.config_frame.draw_config() self.config_frame.grid(sticky="nsew", pady=PADY) self.draw_apply_buttons() def draw_apply_buttons(self): """ create node configuration options :return: nothing """ frame = ttk.Frame(self.top) frame.grid(sticky="ew") for i in range(2): frame.columnconfigure(i, weight=1) button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, padx=PADX, sticky="ew") button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky="ew") def click_apply(self): """ retrieve user's wlan configuration and store the new configuration values :return: nothing """ config = self.config_frame.parse_config() self.app.core.wlan_configs[self.node.id] = self.config if self.app.core.is_runtime(): session_id = self.app.core.session_id self.app.core.client.set_wlan_config(session_id, self.node.id, config) self.destroy()
class EmaneModelDialog(Dialog): def __init__( self, master: Any, app: "Application", node: core_pb2.Node, model: str, interface: int = None, ): super().__init__(master, app, f"{node.name} {model} Configuration", modal=True) self.node = node self.model = f"emane_{model}" self.interface = interface self.config_frame = None self.has_error = False try: self.config = self.app.core.get_emane_model_config( self.node.id, self.model, self.interface) self.draw() except grpc.RpcError as e: show_grpc_error(e, self.app, self.app) self.has_error = True self.destroy() def draw(self): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.config) self.config_frame.draw_config() self.config_frame.grid(sticky="nsew", pady=PADY) self.draw_spacer() self.draw_buttons() def draw_buttons(self): frame = ttk.Frame(self.top) frame.grid(sticky="ew") for i in range(2): frame.columnconfigure(i, weight=1) button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, sticky="ew", padx=PADX) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky="ew") def click_apply(self): self.config_frame.parse_config() self.app.core.set_emane_model_config(self.node.id, self.model, self.config, self.interface) self.destroy()
class SessionOptionsDialog(Dialog): def __init__(self, app: "Application") -> None: super().__init__(app, "Session Options") self.config_frame: Optional[ConfigFrame] = None self.has_error: bool = False self.config: Dict[str, ConfigOption] = self.get_config() self.enabled: bool = not self.app.core.is_runtime() if not self.has_error: self.draw() def get_config(self) -> Dict[str, ConfigOption]: try: session_id = self.app.core.session.id response = self.app.core.client.get_session_options(session_id) return ConfigOption.from_dict(response.config) except grpc.RpcError as e: self.app.show_grpc_exception("Get Session Options Error", e) self.has_error = True self.destroy() def draw(self) -> None: self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.config, self.enabled) self.config_frame.draw_config() self.config_frame.grid(sticky=tk.NSEW, pady=PADY) frame = ttk.Frame(self.top) frame.grid(sticky=tk.EW) for i in range(2): frame.columnconfigure(i, weight=1) state = tk.NORMAL if self.enabled else tk.DISABLED button = ttk.Button(frame, text="Save", command=self.save, state=state) button.grid(row=0, column=0, padx=PADX, sticky=tk.EW) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky=tk.EW) def save(self) -> None: config = self.config_frame.parse_config() try: session_id = self.app.core.session.id response = self.app.core.client.set_session_options( session_id, config) logging.info("saved session config: %s", response) except grpc.RpcError as e: self.app.show_grpc_exception("Set Session Options Error", e) self.destroy()
class SessionOptionsDialog(Dialog): def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Session Options", modal=True) self.config_frame = None self.has_error = False self.config = self.get_config() if not self.has_error: self.draw() def get_config(self): try: session_id = self.app.core.session_id response = self.app.core.client.get_session_options(session_id) return response.config except grpc.RpcError as e: self.has_error = True show_grpc_error(e, self.app, self.app) self.destroy() def draw(self): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, config=self.config) self.config_frame.draw_config() self.config_frame.grid(sticky="nsew", pady=PADY) frame = ttk.Frame(self.top) frame.grid(sticky="ew") for i in range(2): frame.columnconfigure(i, weight=1) button = ttk.Button(frame, text="Save", command=self.save) button.grid(row=0, column=0, padx=PADX, sticky="ew") button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, padx=PADX, sticky="ew") def save(self): config = self.config_frame.parse_config() try: session_id = self.app.core.session_id response = self.app.core.client.set_session_options( session_id, config) logging.info("saved session config: %s", response) except grpc.RpcError as e: show_grpc_error(e, self.top, self.app) self.destroy()
class MobilityConfigDialog(Dialog): def __init__(self, master: "Application", app: "Application", canvas_node: "CanvasNode"): super().__init__( master, app, f"{canvas_node.core_node.name} Mobility Configuration", modal=True, ) self.canvas_node = canvas_node self.node = canvas_node.core_node self.config_frame = None self.has_error = False try: self.config = self.app.core.get_mobility_config(self.node.id) self.draw() except grpc.RpcError as e: self.has_error = True show_grpc_error(e, self.app, self.app) self.destroy() def draw(self): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.config) self.config_frame.draw_config() self.config_frame.grid(sticky="nsew", pady=PADY) self.draw_apply_buttons() def draw_apply_buttons(self): frame = ttk.Frame(self.top) frame.grid(sticky="ew") for i in range(2): frame.columnconfigure(i, weight=1) button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, padx=PADX, sticky="ew") button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky="ew") def click_apply(self): self.config_frame.parse_config() self.app.core.mobility_configs[self.node.id] = self.config self.destroy()
class MobilityConfigDialog(Dialog): def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: super().__init__( app, f"{canvas_node.core_node.name} Mobility Configuration") self.canvas_node: "CanvasNode" = canvas_node self.node: Node = canvas_node.core_node self.config_frame: Optional[ConfigFrame] = None self.has_error: bool = False try: config = self.canvas_node.mobility_config if not config: config = self.app.core.get_mobility_config(self.node.id) self.config: Dict[str, ConfigOption] = config self.draw() except grpc.RpcError as e: self.app.show_grpc_exception("Get Mobility Config Error", e) self.has_error: bool = True self.destroy() def draw(self) -> None: self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.config) self.config_frame.draw_config() self.config_frame.grid(sticky="nsew", pady=PADY) self.draw_apply_buttons() def draw_apply_buttons(self) -> None: frame = ttk.Frame(self.top) frame.grid(sticky="ew") for i in range(2): frame.columnconfigure(i, weight=1) button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, padx=PADX, sticky="ew") button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky="ew") def click_apply(self) -> None: self.config_frame.parse_config() self.canvas_node.mobility_config = self.config self.destroy()
class ConfigServiceConfigDialog(Dialog): def __init__( self, master: tk.BaseWidget, app: "Application", service_name: str, node: Node ) -> None: title = f"{service_name} Config Service" super().__init__(app, title, master=master) self.core: "CoreClient" = app.core self.node: Node = node self.service_name: str = service_name self.radiovar: tk.IntVar = tk.IntVar() self.radiovar.set(2) self.directories: List[str] = [] self.templates: List[str] = [] self.dependencies: List[str] = [] self.executables: List[str] = [] self.startup_commands: List[str] = [] self.validation_commands: List[str] = [] self.shutdown_commands: List[str] = [] self.default_startup: List[str] = [] self.default_validate: List[str] = [] self.default_shutdown: List[str] = [] self.validation_mode: Optional[ServiceValidationMode] = None self.validation_time: Optional[int] = None self.validation_period: tk.StringVar = tk.StringVar() self.modes: List[str] = [] self.mode_configs: Dict[str, Dict[str, str]] = {} self.notebook: Optional[ttk.Notebook] = None self.templates_combobox: Optional[ttk.Combobox] = None self.modes_combobox: Optional[ttk.Combobox] = None self.startup_commands_listbox: Optional[tk.Listbox] = None self.shutdown_commands_listbox: Optional[tk.Listbox] = None self.validate_commands_listbox: Optional[tk.Listbox] = None self.validation_time_entry: Optional[ttk.Entry] = None self.validation_mode_entry: Optional[ttk.Entry] = None self.template_text: Optional[CodeText] = None self.validation_period_entry: Optional[ttk.Entry] = None self.original_service_files: Dict[str, str] = {} self.temp_service_files: Dict[str, str] = {} self.modified_files: Set[str] = set() self.config_frame: Optional[ConfigFrame] = None self.default_config: Dict[str, str] = {} self.config: Dict[str, ConfigOption] = {} self.has_error: bool = False self.load() if not self.has_error: self.draw() def load(self) -> None: try: self.core.start_session(definition=True) service = self.core.config_services[self.service_name] self.dependencies = service.dependencies[:] self.executables = service.executables[:] self.directories = service.directories[:] self.templates = service.files[:] self.startup_commands = service.startup[:] self.validation_commands = service.validate[:] self.shutdown_commands = service.shutdown[:] self.validation_mode = service.validation_mode self.validation_time = service.validation_timer self.validation_period.set(service.validation_period) defaults = self.core.client.get_config_service_defaults(self.service_name) self.original_service_files = defaults.templates self.temp_service_files = dict(self.original_service_files) self.modes = sorted(defaults.modes) self.mode_configs = defaults.modes self.config = ConfigOption.from_dict(defaults.config) self.default_config = {x.name: x.value for x in self.config.values()} service_config = self.node.config_service_configs.get(self.service_name) if service_config: for key, value in service_config.config.items(): self.config[key].value = value logger.info("default config: %s", self.default_config) for file, data in service_config.templates.items(): self.modified_files.add(file) self.temp_service_files[file] = data except grpc.RpcError as e: self.app.show_grpc_exception("Get Config Service Error", e) self.has_error = True def draw(self) -> None: self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) # draw notebook self.notebook = ttk.Notebook(self.top) self.notebook.grid(sticky=tk.NSEW, pady=PADY) self.draw_tab_files() if self.config: self.draw_tab_config() self.draw_tab_startstop() self.draw_tab_validation() self.draw_buttons() def draw_tab_files(self) -> None: tab = ttk.Frame(self.notebook, padding=FRAME_PAD) tab.grid(sticky=tk.NSEW) tab.columnconfigure(0, weight=1) self.notebook.add(tab, text="Directories/Files") label = ttk.Label( tab, text="Directories and templates that will be used for this service." ) label.grid(pady=PADY) frame = ttk.Frame(tab) frame.grid(sticky=tk.EW, pady=PADY) frame.columnconfigure(1, weight=1) label = ttk.Label(frame, text="Directories") label.grid(row=0, column=0, sticky=tk.W, padx=PADX) directories_combobox = ttk.Combobox( frame, values=self.directories, state="readonly" ) directories_combobox.grid(row=0, column=1, sticky=tk.EW, pady=PADY) if self.directories: directories_combobox.current(0) label = ttk.Label(frame, text="Templates") label.grid(row=1, column=0, sticky=tk.W, padx=PADX) self.templates_combobox = ttk.Combobox( frame, values=self.templates, state="readonly" ) self.templates_combobox.bind( "<<ComboboxSelected>>", self.handle_template_changed ) self.templates_combobox.grid(row=1, column=1, sticky=tk.EW, pady=PADY) self.template_text = CodeText(tab) self.template_text.grid(sticky=tk.NSEW) tab.rowconfigure(self.template_text.grid_info()["row"], weight=1) if self.templates: self.templates_combobox.current(0) self.template_text.text.delete(1.0, "end") self.template_text.text.insert( "end", self.temp_service_files[self.templates[0]] ) self.template_text.text.bind("<FocusOut>", self.update_template_file_data) def draw_tab_config(self) -> None: tab = ttk.Frame(self.notebook, padding=FRAME_PAD) tab.grid(sticky=tk.NSEW) tab.columnconfigure(0, weight=1) self.notebook.add(tab, text="Configuration") if self.modes: frame = ttk.Frame(tab) frame.grid(sticky=tk.EW, pady=PADY) frame.columnconfigure(1, weight=1) label = ttk.Label(frame, text="Modes") label.grid(row=0, column=0, padx=PADX) self.modes_combobox = ttk.Combobox( frame, values=self.modes, state="readonly" ) self.modes_combobox.bind("<<ComboboxSelected>>", self.handle_mode_changed) self.modes_combobox.grid(row=0, column=1, sticky=tk.EW, pady=PADY) logger.info("config service config: %s", self.config) self.config_frame = ConfigFrame(tab, self.app, self.config) self.config_frame.draw_config() self.config_frame.grid(sticky=tk.NSEW, pady=PADY) tab.rowconfigure(self.config_frame.grid_info()["row"], weight=1) def draw_tab_startstop(self) -> None: tab = ttk.Frame(self.notebook, padding=FRAME_PAD) tab.grid(sticky=tk.NSEW) tab.columnconfigure(0, weight=1) for i in range(3): tab.rowconfigure(i, weight=1) self.notebook.add(tab, text="Startup/Shutdown") commands = [] # tab 3 for i in range(3): label_frame = None if i == 0: label_frame = ttk.LabelFrame( tab, text="Startup Commands", padding=FRAME_PAD ) commands = self.startup_commands elif i == 1: label_frame = ttk.LabelFrame( tab, text="Shutdown Commands", padding=FRAME_PAD ) commands = self.shutdown_commands elif i == 2: label_frame = ttk.LabelFrame( tab, text="Validation Commands", padding=FRAME_PAD ) commands = self.validation_commands label_frame.columnconfigure(0, weight=1) label_frame.rowconfigure(0, weight=1) label_frame.grid(row=i, column=0, sticky=tk.NSEW, pady=PADY) listbox_scroll = ListboxScroll(label_frame) for command in commands: listbox_scroll.listbox.insert("end", command) listbox_scroll.listbox.config(height=4) listbox_scroll.grid(sticky=tk.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 def draw_tab_validation(self) -> None: tab = ttk.Frame(self.notebook, padding=FRAME_PAD) tab.grid(sticky=tk.EW) tab.columnconfigure(0, weight=1) self.notebook.add(tab, text="Validation", sticky=tk.NSEW) frame = ttk.Frame(tab) frame.grid(sticky=tk.EW, pady=PADY) frame.columnconfigure(1, weight=1) label = ttk.Label(frame, text="Validation Time") label.grid(row=0, column=0, sticky=tk.W, padx=PADX) self.validation_time_entry = ttk.Entry(frame) self.validation_time_entry.insert("end", self.validation_time) self.validation_time_entry.config(state=tk.DISABLED) self.validation_time_entry.grid(row=0, column=1, sticky=tk.EW, pady=PADY) label = ttk.Label(frame, text="Validation Mode") label.grid(row=1, column=0, sticky=tk.W, padx=PADX) if self.validation_mode == ServiceValidationMode.BLOCKING: mode = "BLOCKING" elif self.validation_mode == ServiceValidationMode.NON_BLOCKING: mode = "NON_BLOCKING" else: mode = "TIMER" self.validation_mode_entry = ttk.Entry( frame, textvariable=tk.StringVar(value=mode) ) self.validation_mode_entry.insert("end", mode) self.validation_mode_entry.config(state=tk.DISABLED) self.validation_mode_entry.grid(row=1, column=1, sticky=tk.EW, pady=PADY) label = ttk.Label(frame, text="Validation Period") label.grid(row=2, column=0, sticky=tk.W, padx=PADX) self.validation_period_entry = ttk.Entry( frame, state=tk.DISABLED, textvariable=self.validation_period ) self.validation_period_entry.grid(row=2, column=1, sticky=tk.EW, pady=PADY) label_frame = ttk.LabelFrame(tab, text="Executables", padding=FRAME_PAD) label_frame.grid(sticky=tk.NSEW, pady=PADY) label_frame.columnconfigure(0, weight=1) label_frame.rowconfigure(0, weight=1) listbox_scroll = ListboxScroll(label_frame) listbox_scroll.grid(sticky=tk.NSEW) tab.rowconfigure(listbox_scroll.grid_info()["row"], weight=1) for executable in self.executables: listbox_scroll.listbox.insert("end", executable) label_frame = ttk.LabelFrame(tab, text="Dependencies", padding=FRAME_PAD) label_frame.grid(sticky=tk.NSEW, pady=PADY) label_frame.columnconfigure(0, weight=1) label_frame.rowconfigure(0, weight=1) listbox_scroll = ListboxScroll(label_frame) listbox_scroll.grid(sticky=tk.NSEW) tab.rowconfigure(listbox_scroll.grid_info()["row"], weight=1) for dependency in self.dependencies: listbox_scroll.listbox.insert("end", dependency) def draw_buttons(self) -> None: frame = ttk.Frame(self.top) frame.grid(sticky=tk.EW) for i in range(4): frame.columnconfigure(i, weight=1) button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, sticky=tk.EW, padx=PADX) button = ttk.Button(frame, text="Defaults", command=self.click_defaults) button.grid(row=0, column=1, sticky=tk.EW, padx=PADX) button = ttk.Button(frame, text="Copy...", command=self.click_copy) button.grid(row=0, column=2, sticky=tk.EW, padx=PADX) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=3, sticky=tk.EW) def click_apply(self) -> None: current_listbox = self.master.current.listbox if not self.is_custom(): self.node.config_service_configs.pop(self.service_name, None) current_listbox.itemconfig(current_listbox.curselection()[0], bg="") self.destroy() return service_config = self.node.config_service_configs.setdefault( self.service_name, ConfigServiceData() ) if self.config_frame: self.config_frame.parse_config() service_config.config = {x.name: x.value for x in self.config.values()} for file in self.modified_files: service_config.templates[file] = self.temp_service_files[file] all_current = current_listbox.get(0, tk.END) current_listbox.itemconfig(all_current.index(self.service_name), bg="green") self.destroy() def handle_template_changed(self, event: tk.Event) -> None: template = self.templates_combobox.get() self.template_text.text.delete(1.0, "end") self.template_text.text.insert("end", self.temp_service_files[template]) def handle_mode_changed(self, event: tk.Event) -> None: mode = self.modes_combobox.get() config = self.mode_configs[mode] logger.info("mode config: %s", config) self.config_frame.set_values(config) def update_template_file_data(self, event: tk.Event) -> None: scrolledtext = event.widget template = self.templates_combobox.get() self.temp_service_files[template] = scrolledtext.get(1.0, "end") if self.temp_service_files[template] != self.original_service_files[template]: self.modified_files.add(template) else: self.modified_files.discard(template) def is_custom(self) -> bool: has_custom_templates = len(self.modified_files) > 0 has_custom_config = False if self.config_frame: current = self.config_frame.parse_config() has_custom_config = self.default_config != current return has_custom_templates or has_custom_config def click_defaults(self) -> None: self.node.config_service_configs.pop(self.service_name, None) logger.info( "cleared config service config: %s", self.node.config_service_configs ) self.temp_service_files = dict(self.original_service_files) filename = self.templates_combobox.get() self.template_text.text.delete(1.0, "end") self.template_text.text.insert("end", self.temp_service_files[filename]) if self.config_frame: logger.info("resetting defaults: %s", self.default_config) self.config_frame.set_values(self.default_config) def click_copy(self) -> None: pass def append_commands( self, commands: List[str], listbox: tk.Listbox, to_add: List[str] ) -> None: for cmd in to_add: commands.append(cmd) listbox.insert(tk.END, cmd)
class WlanConfigDialog(Dialog): def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: super().__init__(app, f"{canvas_node.core_node.name} WLAN Configuration") self.canvas: "CanvasGraph" = app.canvas self.canvas_node: "CanvasNode" = canvas_node self.node: Node = canvas_node.core_node self.config_frame: Optional[ConfigFrame] = None self.range_entry: Optional[ttk.Entry] = None self.has_error: bool = False self.ranges: Dict[int, int] = {} self.positive_int: int = self.app.master.register( self.validate_and_update) try: config = self.node.wlan_config if not config: config = self.app.core.get_wlan_config(self.node.id) self.config: Dict[str, ConfigOption] = config self.init_draw_range() self.draw() except grpc.RpcError as e: self.app.show_grpc_exception("WLAN Config Error", e) self.has_error: bool = True self.destroy() def init_draw_range(self) -> None: if self.canvas_node.id in self.canvas.wireless_network: for cid in self.canvas.wireless_network[self.canvas_node.id]: x, y = self.canvas.coords(cid) range_id = self.canvas.create_oval(x, y, x, y, width=RANGE_WIDTH, outline=RANGE_COLOR, tags="range") self.ranges[cid] = range_id def draw(self) -> None: self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.config_frame = ConfigFrame(self.top, self.app, self.config) self.config_frame.draw_config() self.config_frame.grid(sticky=tk.NSEW, pady=PADY) self.draw_apply_buttons() self.top.bind("<Destroy>", self.remove_ranges) def draw_apply_buttons(self) -> None: """ create node configuration options """ frame = ttk.Frame(self.top) frame.grid(sticky=tk.EW) for i in range(2): frame.columnconfigure(i, weight=1) self.range_entry = self.config_frame.winfo_children( )[0].frame.winfo_children()[-1] self.range_entry.config(validatecommand=(self.positive_int, "%P")) button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, padx=PADX, sticky=tk.EW) button = ttk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky=tk.EW) def click_apply(self) -> None: """ retrieve user's wlan configuration and store the new configuration values """ config = self.config_frame.parse_config() self.node.wlan_config = self.config if self.app.core.is_runtime(): session_id = self.app.core.session.id self.app.core.client.set_wlan_config(session_id, self.node.id, config) self.remove_ranges() self.destroy() def remove_ranges(self, event=None) -> None: for cid in self.canvas.find_withtag("range"): self.canvas.delete(cid) self.ranges.clear() def validate_and_update(self, s: str) -> bool: """ custom validation to also redraw the mdr ranges when the range value changes """ if len(s) == 0: return True try: int_value = int(s) / 2 if int_value >= 0: net_range = int_value * self.canvas.ratio if self.canvas_node.id in self.canvas.wireless_network: for cid in self.canvas.wireless_network[ self.canvas_node.id]: x, y = self.canvas.coords(cid) self.canvas.coords( self.ranges[cid], x - net_range, y - net_range, x + net_range, y + net_range, ) return True return False except ValueError: return False