fix save/new/load scenario
minor fix in gui
This commit is contained in:
parent
08aa827cd7
commit
3b447d7fdb
4
script.txt
Normal file
4
script.txt
Normal file
@ -0,0 +1,4 @@
|
||||
$tgtinit 0 20.00 45.00 500.00 270.00 10000.00 /s /t
|
||||
$tgtinit 1 30.00 45.00 500.00 270.00 10000.00 /s /t
|
||||
$tgtinit 2 60.00 20.00 500.00 270.00 10000.00 /s /t
|
||||
$tgtinit 3 25.00 -10.00 130.00 20.00 20000.00 /s /t
|
||||
4
scripts.txt
Normal file
4
scripts.txt
Normal file
@ -0,0 +1,4 @@
|
||||
$tgtinit 0 20.00 45.00 500.00 270.00 10000.00 /s /t
|
||||
$tgtinit 1 30.00 45.00 500.00 270.00 10000.00 /s /t
|
||||
$tgtinit 2 60.00 20.00 500.00 270.00 10000.00 /s /t
|
||||
$tgtinit 3 25.00 -10.00 130.00 20.00 20000.00 /s /t
|
||||
@ -5,10 +5,27 @@
|
||||
"geometry": "1200x900+291+141",
|
||||
"last_selected_scenario": "scenario1",
|
||||
"connection": {
|
||||
"type": "tftp",
|
||||
"tftp": {
|
||||
"ip": "127.0.0.1",
|
||||
"port": 50071
|
||||
"target": {
|
||||
"type": "tftp",
|
||||
"tftp": {
|
||||
"ip": "127.0.0.1",
|
||||
"port": 50069
|
||||
},
|
||||
"serial": {
|
||||
"port": "COM1",
|
||||
"baudrate": 9600
|
||||
}
|
||||
},
|
||||
"lru": {
|
||||
"type": "serial",
|
||||
"tftp": {
|
||||
"ip": "127.0.0.1",
|
||||
"port": 69
|
||||
},
|
||||
"serial": {
|
||||
"port": "COM2",
|
||||
"baudrate": 38400
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -57,6 +74,46 @@
|
||||
"traceable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"scenario2": {
|
||||
"name": "scenario2",
|
||||
"targets": [
|
||||
{
|
||||
"target_id": 0,
|
||||
"range_nm": 20.0,
|
||||
"azimuth_deg": 45.0,
|
||||
"velocity_fps": 843.905,
|
||||
"heading_deg": 270.0,
|
||||
"altitude_ft": 10000.0,
|
||||
"active": true,
|
||||
"traceable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"scenario3": {
|
||||
"name": "scenario3",
|
||||
"targets": [
|
||||
{
|
||||
"target_id": 0,
|
||||
"range_nm": 20.0,
|
||||
"azimuth_deg": 45.0,
|
||||
"velocity_fps": 843.905,
|
||||
"heading_deg": 270.0,
|
||||
"altitude_ft": 10000.0,
|
||||
"active": true,
|
||||
"traceable": true
|
||||
},
|
||||
{
|
||||
"target_id": 1,
|
||||
"range_nm": 20.0,
|
||||
"azimuth_deg": 45.0,
|
||||
"velocity_fps": 843.905,
|
||||
"heading_deg": 270.0,
|
||||
"altitude_ft": 10000.0,
|
||||
"active": true,
|
||||
"traceable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,4 +126,4 @@ def build_aclatch() -> str:
|
||||
|
||||
def build_acunlatch() -> str:
|
||||
"""Builds the command to release the A/C data latch."""
|
||||
return "aclatch /r"
|
||||
return "aclatch /r"
|
||||
|
||||
@ -20,7 +20,8 @@ from target_simulator.utils.logger import get_logger
|
||||
class TFTPCommunicator(CommunicatorInterface):
|
||||
"""A class to manage and abstract TFTP communication."""
|
||||
|
||||
REMOTE_FILENAME = "ris_scenario.txt" # The filename to upload on the TFTP server
|
||||
REMOTE_FILENAME = "MON:script.txt" # The filename to upload on the TFTP server
|
||||
LOCAL_FILENAME = "scripts.txt"
|
||||
|
||||
def __init__(self):
|
||||
self.logger = get_logger(__name__)
|
||||
@ -76,20 +77,28 @@ class TFTPCommunicator(CommunicatorInterface):
|
||||
|
||||
# 1. Build the script content in memory
|
||||
script_lines = []
|
||||
# Per il manuale, gli script devono iniziare con una linea specifica
|
||||
script_lines.append(";++++")
|
||||
for target in scenario.get_all_targets():
|
||||
script_lines.append(command_builder.build_tgtinit(target))
|
||||
command = command_builder.build_tgtinit(target)
|
||||
script_lines.append(f"${command}")
|
||||
|
||||
script_content = "\n".join(script_lines)
|
||||
|
||||
# 2. Use io.StringIO to treat the string as a file
|
||||
# 2. Save the script to a local file for verification
|
||||
try:
|
||||
with open(self.LOCAL_FILENAME, "w") as f:
|
||||
f.write(script_content)
|
||||
self.logger.info(f"Scenario script saved locally to '{self.LOCAL_FILENAME}'")
|
||||
except IOError as e:
|
||||
self.logger.error(f"Failed to save script locally: {e}")
|
||||
# We might not want to abort the whole process for this
|
||||
|
||||
# 3. Use io.StringIO to treat the string as a file for upload
|
||||
in_memory_script = io.StringIO(script_content)
|
||||
|
||||
# 3. Upload the in-memory file
|
||||
# 4. Upload the in-memory file
|
||||
try:
|
||||
client = TFTPClient(self.config['ip'], self.config['port'])
|
||||
success = client.upload(self.REMOTE_FILENAME, in_memory_script)
|
||||
success = client.upload(self.REMOTE_FILENAME, in_memory_script, mode="netascii")
|
||||
if success:
|
||||
self.logger.info(f"Successfully uploaded scenario as '{self.REMOTE_FILENAME}'.")
|
||||
return True
|
||||
|
||||
207
target_simulator/gui/connection_settings_window.py
Normal file
207
target_simulator/gui/connection_settings_window.py
Normal file
@ -0,0 +1,207 @@
|
||||
# target_simulator/gui/connection_settings_window.py
|
||||
"""
|
||||
Toplevel window for configuring Target and LRU connections.
|
||||
"""
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
|
||||
class ConnectionSettingsWindow(tk.Toplevel):
|
||||
"""A dialog for configuring connection settings."""
|
||||
def __init__(self, master, config_manager, connection_config):
|
||||
super().__init__(master)
|
||||
self.master_view = master
|
||||
self.config_manager = config_manager
|
||||
self.connection_config = connection_config
|
||||
|
||||
self.title("Connection Settings")
|
||||
self.transient(master)
|
||||
self.grab_set()
|
||||
self.resizable(False, False)
|
||||
|
||||
self._create_widgets()
|
||||
self._load_settings()
|
||||
self.protocol("WM_DELETE_WINDOW", self._on_cancel)
|
||||
|
||||
# Center the window on the main view
|
||||
self.update_idletasks()
|
||||
main_x = master.winfo_rootx()
|
||||
main_y = master.winfo_rooty()
|
||||
main_w = master.winfo_width()
|
||||
main_h = master.winfo_height()
|
||||
win_w = self.winfo_width()
|
||||
win_h = self.winfo_height()
|
||||
x = main_x + (main_w // 2) - (win_w // 2)
|
||||
y = main_y + (main_h // 2) - (win_h // 2)
|
||||
self.geometry(f"{win_w}x{win_h}+{x}+{y}")
|
||||
|
||||
def _load_settings(self):
|
||||
# --- Load Target Settings ---
|
||||
target_cfg = self.connection_config.get('target', {})
|
||||
self.target_vars['conn_type'].set("Serial" if target_cfg.get('type', 'TFTP').lower() == "serial" else "TFTP")
|
||||
self.target_vars['tftp_ip'].set(target_cfg.get('tftp', {}).get('ip', '127.0.0.1'))
|
||||
self.target_vars['tftp_port'].set(target_cfg.get('tftp', {}).get('port', 69))
|
||||
self.target_vars['serial_port'].set(target_cfg.get('serial', {}).get('port', 'COM1'))
|
||||
self.target_vars['serial_baud'].set(target_cfg.get('serial', {}).get('baudrate', 9600))
|
||||
self._switch_view(self.target_vars)
|
||||
|
||||
# --- Load LRU Settings ---
|
||||
lru_cfg = self.connection_config.get('lru', {})
|
||||
self.lru_vars['conn_type'].set("Serial" if lru_cfg.get('type', 'TFTP').lower() == "serial" else "TFTP")
|
||||
self.lru_vars['tftp_ip'].set(lru_cfg.get('tftp', {}).get('ip', '127.0.0.1'))
|
||||
self.lru_vars['tftp_port'].set(lru_cfg.get('tftp', {}).get('port', 69))
|
||||
self.lru_vars['serial_port'].set(lru_cfg.get('serial', {}).get('port', 'COM1'))
|
||||
self.lru_vars['serial_baud'].set(lru_cfg.get('serial', {}).get('baudrate', 9600))
|
||||
self._switch_view(self.lru_vars)
|
||||
|
||||
def _create_widgets(self):
|
||||
main_frame = ttk.Frame(self, padding="10")
|
||||
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# --- Target Connection Frame ---
|
||||
target_frame = ttk.LabelFrame(main_frame, text="Target Connection")
|
||||
target_frame.pack(fill=tk.X, expand=True, pady=5, padx=5)
|
||||
self.target_vars = self._create_connection_panel(target_frame, "Target")
|
||||
|
||||
# --- LRU Connection Frame ---
|
||||
lru_frame = ttk.LabelFrame(main_frame, text="LRU Connection")
|
||||
lru_frame.pack(fill=tk.X, expand=True, pady=5, padx=5)
|
||||
self.lru_vars = self._create_connection_panel(lru_frame, "LRU")
|
||||
|
||||
# --- Buttons ---
|
||||
button_frame = ttk.Frame(main_frame)
|
||||
button_frame.pack(pady=10, fill=tk.X, side=tk.BOTTOM)
|
||||
|
||||
ttk.Button(button_frame, text="Save", command=self._on_save).pack(side=tk.RIGHT, padx=5)
|
||||
ttk.Button(button_frame, text="Cancel", command=self._on_cancel).pack(side=tk.RIGHT, padx=5)
|
||||
|
||||
def _create_connection_panel(self, parent_frame, name):
|
||||
vars = {}
|
||||
|
||||
# --- Connection Type Selection ---
|
||||
conn_type_frame = ttk.Frame(parent_frame)
|
||||
conn_type_frame.pack(fill=tk.X, padx=5, pady=(5,10))
|
||||
|
||||
vars['conn_type'] = tk.StringVar()
|
||||
|
||||
ttk.Label(conn_type_frame, text="Type:").pack(side=tk.LEFT)
|
||||
ttk.Radiobutton(conn_type_frame, text="TFTP", variable=vars['conn_type'], value="TFTP", command=lambda: self._switch_view(vars)).pack(side=tk.LEFT, padx=5)
|
||||
ttk.Radiobutton(conn_type_frame, text="Serial", variable=vars['conn_type'], value="Serial", command=lambda: self._switch_view(vars)).pack(side=tk.LEFT, padx=5)
|
||||
|
||||
# --- Configuration Frames (TFTP and Serial) ---
|
||||
vars['tftp_frame'] = ttk.Frame(parent_frame, padding=5)
|
||||
vars['serial_frame'] = ttk.Frame(parent_frame, padding=5)
|
||||
|
||||
# --- TFTP Widgets ---
|
||||
tftp_grid = vars['tftp_frame']
|
||||
ttk.Label(tftp_grid, text="IP Address:").grid(row=0, column=0, sticky=tk.W, pady=2)
|
||||
vars['tftp_ip'] = tk.StringVar()
|
||||
ttk.Entry(tftp_grid, textvariable=vars['tftp_ip']).grid(row=0, column=1, sticky=tk.EW, padx=5)
|
||||
|
||||
ttk.Label(tftp_grid, text="Port:").grid(row=1, column=0, sticky=tk.W, pady=2)
|
||||
vars['tftp_port'] = tk.IntVar()
|
||||
ttk.Spinbox(tftp_grid, from_=1, to=65535, textvariable=vars['tftp_port'], width=7).grid(row=1, column=1, sticky=tk.W, padx=5)
|
||||
tftp_grid.columnconfigure(1, weight=1)
|
||||
|
||||
# --- Serial Widgets ---
|
||||
serial_grid = vars['serial_frame']
|
||||
ttk.Label(serial_grid, text="COM Port:").grid(row=0, column=0, sticky=tk.W, pady=2)
|
||||
vars['serial_port'] = tk.StringVar()
|
||||
# In a real app, you might want to auto-detect available ports
|
||||
ttk.Combobox(serial_grid, textvariable=vars['serial_port'], values=[f"COM{i}" for i in range(1, 17)]).grid(row=0, column=1, sticky=tk.EW, padx=5)
|
||||
|
||||
ttk.Label(serial_grid, text="Baud Rate:").grid(row=1, column=0, sticky=tk.W, pady=2)
|
||||
vars['serial_baud'] = tk.IntVar()
|
||||
baud_rates = [9600, 19200, 38400, 57600, 115200]
|
||||
ttk.Combobox(serial_grid, textvariable=vars['serial_baud'], values=baud_rates, width=7).grid(row=1, column=1, sticky=tk.W, padx=5)
|
||||
serial_grid.columnconfigure(1, weight=1)
|
||||
|
||||
# --- Test Button ---
|
||||
test_button = ttk.Button(parent_frame, text="Test Connection", command=lambda: self._test_connection(name, vars))
|
||||
test_button.pack(pady=5, padx=5, anchor=tk.E)
|
||||
|
||||
# Initial view setup is now done in _load_settings
|
||||
# self._switch_view(vars)
|
||||
|
||||
return vars
|
||||
|
||||
def _switch_view(self, vars):
|
||||
conn_type = vars['conn_type'].get()
|
||||
if conn_type == "TFTP":
|
||||
vars['serial_frame'].pack_forget()
|
||||
vars['tftp_frame'].pack(fill=tk.X, expand=True, padx=5, pady=5)
|
||||
else: # Serial
|
||||
vars['tftp_frame'].pack_forget()
|
||||
vars['serial_frame'].pack(fill=tk.X, expand=True, padx=5, pady=5)
|
||||
|
||||
def _test_connection(self, name, vars):
|
||||
conn_type = vars['conn_type'].get()
|
||||
result = False
|
||||
error = None
|
||||
if conn_type == "TFTP":
|
||||
ip = vars['tftp_ip'].get()
|
||||
port = vars['tftp_port'].get()
|
||||
try:
|
||||
port = int(port)
|
||||
from core.tftp_communicator import TFTPCommunicator
|
||||
comm = TFTPCommunicator()
|
||||
result = comm.connect({'ip': ip, 'port': port})
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
else: # Serial
|
||||
serial_port = vars['serial_port'].get()
|
||||
baudrate = vars['serial_baud'].get()
|
||||
try:
|
||||
baudrate = int(baudrate)
|
||||
from core.serial_communicator import SerialCommunicator
|
||||
comm = SerialCommunicator()
|
||||
result = comm.connect({'port': serial_port, 'baudrate': baudrate})
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
if result:
|
||||
messagebox.showinfo("Connection Test", f"{name} connection successful!", parent=self)
|
||||
else:
|
||||
msg = f"{name} connection failed."
|
||||
if error:
|
||||
msg += f"\nError: {error}"
|
||||
messagebox.showerror("Connection Test", msg, parent=self)
|
||||
|
||||
def _on_save(self):
|
||||
# Save Target and LRU connection configs in a consistent structure
|
||||
new_config = {
|
||||
'target': {
|
||||
'type': self.target_vars['conn_type'].get().lower(),
|
||||
'tftp': {
|
||||
'ip': self.target_vars['tftp_ip'].get(),
|
||||
'port': self.target_vars['tftp_port'].get()
|
||||
},
|
||||
'serial': {
|
||||
'port': self.target_vars['serial_port'].get(),
|
||||
'baudrate': self.target_vars['serial_baud'].get()
|
||||
}
|
||||
},
|
||||
'lru': {
|
||||
'type': self.lru_vars['conn_type'].get().lower(),
|
||||
'tftp': {
|
||||
'ip': self.lru_vars['tftp_ip'].get(),
|
||||
'port': self.lru_vars['tftp_port'].get()
|
||||
},
|
||||
'serial': {
|
||||
'port': self.lru_vars['serial_port'].get(),
|
||||
'baudrate': self.lru_vars['serial_baud'].get()
|
||||
}
|
||||
}
|
||||
}
|
||||
self.master_view.update_connection_settings(new_config)
|
||||
print("Settings saved and applied.")
|
||||
self.destroy()
|
||||
|
||||
def _on_cancel(self):
|
||||
self.destroy()
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Example usage for testing
|
||||
root = tk.Tk()
|
||||
root.withdraw() # Hide the root window
|
||||
app = ConnectionSettingsWindow(root)
|
||||
root.wait_window(app)
|
||||
root.destroy()
|
||||
@ -9,6 +9,7 @@ from typing import Optional, Dict, Any
|
||||
|
||||
from .ppi_display import PPIDisplay
|
||||
from .settings_window import SettingsWindow
|
||||
from .connection_settings_window import ConnectionSettingsWindow
|
||||
from .radar_config_window import RadarConfigWindow
|
||||
from .scenario_controls_frame import ScenarioControlsFrame
|
||||
from .target_list_frame import TargetListFrame
|
||||
@ -23,6 +24,44 @@ from target_simulator.utils.logger import get_logger, shutdown_logging_system
|
||||
from target_simulator.utils.config_manager import ConfigManager
|
||||
|
||||
class MainView(tk.Tk):
|
||||
def _on_new_scenario(self, scenario_name):
|
||||
"""
|
||||
Handles creation of a new scenario:
|
||||
- If scenario name exists, notify user and load it.
|
||||
- If not, create new scenario, update combobox, select, and clear targets.
|
||||
"""
|
||||
scenario_names = self.config_manager.get_scenario_names()
|
||||
if scenario_name in scenario_names:
|
||||
messagebox.showinfo(
|
||||
"Duplicate Scenario",
|
||||
f"Scenario '{scenario_name}' already exists. Loading saved data.",
|
||||
parent=self
|
||||
)
|
||||
self._on_load_scenario(scenario_name)
|
||||
# Select in comboboxes
|
||||
self.scenario_controls.update_scenario_list(scenario_names, scenario_name)
|
||||
if hasattr(self, 'sim_scenario_combobox'):
|
||||
self.sim_scenario_combobox['values'] = scenario_names
|
||||
self.sim_scenario_combobox.set(scenario_name)
|
||||
return
|
||||
# Create new scenario
|
||||
self.scenario = Scenario(name=scenario_name)
|
||||
self.current_scenario_name = scenario_name
|
||||
# Clear targets in UI
|
||||
self.target_list.update_target_list([])
|
||||
# Update comboboxes
|
||||
scenario_names.append(scenario_name)
|
||||
self.scenario_controls.update_scenario_list(scenario_names, scenario_name)
|
||||
if hasattr(self, 'sim_scenario_combobox'):
|
||||
self.sim_scenario_combobox['values'] = scenario_names
|
||||
self.sim_scenario_combobox.set(scenario_name)
|
||||
self._update_window_title()
|
||||
self.logger.info(f"Created new scenario '{scenario_name}'. Ready for target input.")
|
||||
messagebox.showinfo(
|
||||
"New Scenario",
|
||||
f"Scenario '{scenario_name}' created. Add targets to begin.",
|
||||
parent=self
|
||||
)
|
||||
"""The main application window."""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@ -33,82 +72,154 @@ class MainView(tk.Tk):
|
||||
self.max_range = settings.get('max_range', 100)
|
||||
self.connection_config = self.config_manager.get_connection_settings()
|
||||
self.title("Radar Target Simulator")
|
||||
self.geometry(settings.get('geometry', '1200x900'))
|
||||
self.minsize(900, 700)
|
||||
self.communicator = None
|
||||
self.geometry(settings.get('geometry', '1200x1024'))
|
||||
self.minsize(1024, 1024)
|
||||
self.target_communicator = None
|
||||
self.lru_communicator = None
|
||||
self.current_scenario_name = None
|
||||
self._create_main_layout()
|
||||
self._create_menubar()
|
||||
self._create_statusbar()
|
||||
self._initialize_communicator() # Attempt to connect with saved settings
|
||||
self._load_scenarios_into_ui()
|
||||
|
||||
def _create_main_layout(self):
|
||||
v_pane = ttk.PanedWindow(self, orient=tk.VERTICAL)
|
||||
v_pane.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
self.h_pane = ttk.PanedWindow(v_pane, orient=tk.HORIZONTAL)
|
||||
v_pane.add(self.h_pane, weight=4)
|
||||
left_frame = ttk.Frame(self.h_pane)
|
||||
self.h_pane.add(left_frame, weight=1)
|
||||
|
||||
# --- Right Pane (PPI) ---
|
||||
self.ppi_widget = PPIDisplay(self.h_pane, max_range_nm=self.max_range, scan_limit_deg=self.scan_limit)
|
||||
self.h_pane.add(self.ppi_widget, weight=2)
|
||||
|
||||
# --- Connessione Frame ---
|
||||
conn_frame = ttk.LabelFrame(left_frame, text="Connection")
|
||||
conn_frame.pack(fill=tk.X, padx=5, pady=(5, 0))
|
||||
self.conn_type_var = tk.StringVar(value=self.connection_config.get("type", "N/A"))
|
||||
self.conn_params_var = tk.StringVar(value=self._get_connection_params_str())
|
||||
# Connection status indicator (semaphore)
|
||||
self.conn_status_canvas = tk.Canvas(conn_frame, width=18, height=18, highlightthickness=0, bd=0)
|
||||
self.conn_status_canvas.grid(row=0, column=0, padx=(5,2), pady=2)
|
||||
self._draw_conn_status_indicator(connected=False)
|
||||
# Ripristino i widget e bottoni accanto al semaforo
|
||||
ttk.Label(conn_frame, text="Type:").grid(row=0, column=1, sticky=tk.W, padx=2, pady=2)
|
||||
ttk.Entry(conn_frame, textvariable=self.conn_type_var, state="readonly", width=10).grid(row=0, column=2, sticky=tk.W, padx=2, pady=2)
|
||||
ttk.Entry(conn_frame, textvariable=self.conn_params_var, state="readonly", width=22).grid(row=0, column=3, sticky=tk.W, padx=2, pady=2)
|
||||
self.connect_btn = ttk.Button(conn_frame, text="Connect", command=self._on_connect)
|
||||
self.connect_btn.grid(row=0, column=4, sticky=tk.W, padx=2, pady=2)
|
||||
self.disconnect_btn = ttk.Button(conn_frame, text="Disconnect", command=self._on_disconnect)
|
||||
self.disconnect_btn.grid(row=0, column=5, sticky=tk.W, padx=2, pady=2)
|
||||
self.connect_btn.state(["!disabled"])
|
||||
self.disconnect_btn.state(["disabled"])
|
||||
# Add Connect button next to PPI controls
|
||||
# Find the controls_frame inside PPIDisplay and add the button
|
||||
controls_frame = self.ppi_widget.children.get('!frame')
|
||||
if controls_frame:
|
||||
connect_btn = ttk.Button(controls_frame, text="Connect", command=self._on_connect_button)
|
||||
connect_btn.pack(side=tk.RIGHT, padx=10)
|
||||
|
||||
# --- Scenario Controls Frame ---
|
||||
self.scenario_controls = ScenarioControlsFrame(left_frame, load_scenario_command=self._on_load_scenario, save_as_command=self._on_save_scenario_as, update_command=self._on_update_scenario, delete_command=self._on_delete_scenario)
|
||||
self.scenario_controls.pack(fill=tk.X, expand=False, padx=5, pady=(5, 5))
|
||||
|
||||
self.target_list = TargetListFrame(left_frame, targets_changed_callback=self._on_targets_changed)
|
||||
self.target_list.pack(fill=tk.BOTH, expand=True, padx=5)
|
||||
|
||||
# --- Logs Frame ---
|
||||
# --- Bottom Pane (Logs) ---
|
||||
log_frame_container = ttk.LabelFrame(v_pane, text="Logs")
|
||||
v_pane.add(log_frame_container, weight=1)
|
||||
self.log_text_widget = scrolledtext.ScrolledText(log_frame_container, state=tk.DISABLED, wrap=tk.WORD, font=("Consolas", 9))
|
||||
self.log_text_widget.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
# --- Left Pane ---
|
||||
left_pane_container = ttk.Frame(self.h_pane)
|
||||
self.h_pane.add(left_pane_container, weight=1)
|
||||
|
||||
# --- Notebook for left pane ---
|
||||
left_notebook = ttk.Notebook(left_pane_container)
|
||||
left_notebook.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# --- TAB 2: SCENARIO CONFIG ---
|
||||
if not hasattr(self, 'scenario_tab'):
|
||||
self.scenario_tab = ttk.Frame(left_notebook)
|
||||
left_notebook.add(self.scenario_tab, text="Scenario Config")
|
||||
self.scenario_controls = ScenarioControlsFrame(self.scenario_tab,
|
||||
main_view=self,
|
||||
load_scenario_command=self._on_load_scenario,
|
||||
save_as_command=self._on_save_scenario_as,
|
||||
delete_command=self._on_delete_scenario,
|
||||
new_scenario_command=self._on_new_scenario)
|
||||
self.scenario_controls.pack(fill=tk.X, expand=False, padx=5, pady=(5, 5))
|
||||
self.target_list = TargetListFrame(self.scenario_tab, targets_changed_callback=self._on_targets_changed)
|
||||
self.target_list.pack(fill=tk.BOTH, expand=True, padx=5)
|
||||
|
||||
# --- TAB 3: SIMULATION ---
|
||||
if not hasattr(self, 'simulation_tab'):
|
||||
self.simulation_tab = ttk.Frame(left_notebook)
|
||||
left_notebook.add(self.simulation_tab, text="Simulation")
|
||||
sim_controls_frame = ttk.LabelFrame(self.simulation_tab, text="Simulation Controls")
|
||||
sim_controls_frame.pack(fill=tk.X, padx=5, pady=5, anchor='n')
|
||||
ttk.Label(sim_controls_frame, text="Scenario:").pack(side=tk.LEFT, padx=(5, 5), pady=5)
|
||||
self.sim_scenario_combobox = ttk.Combobox(
|
||||
sim_controls_frame,
|
||||
textvariable=self.scenario_controls.current_scenario,
|
||||
state="readonly"
|
||||
)
|
||||
self.sim_scenario_combobox.pack(side=tk.LEFT, expand=True, fill=tk.X, pady=5)
|
||||
self.sim_scenario_combobox.bind("<<ComboboxSelected>>", lambda event: self._on_load_scenario(self.sim_scenario_combobox.get()))
|
||||
send_button = ttk.Button(sim_controls_frame, text="Send to Radar", command=self._on_send_scenario)
|
||||
send_button.pack(side=tk.LEFT, padx=5, pady=5)
|
||||
|
||||
# --- TAB 4: LRU SIMULATION ---
|
||||
if not hasattr(self, 'lru_tab'):
|
||||
self.lru_tab = ttk.Frame(left_notebook)
|
||||
left_notebook.add(self.lru_tab, text="LRU Simulation")
|
||||
cooling_frame = ttk.LabelFrame(self.lru_tab, text="Cooling Unit Status")
|
||||
cooling_frame.pack(fill=tk.X, padx=5, pady=5, anchor='n')
|
||||
ttk.Label(cooling_frame, text="Status:").pack(side=tk.LEFT, padx=5, pady=5)
|
||||
self.cooling_status_var = tk.StringVar(value="OK")
|
||||
cooling_combo = ttk.Combobox(
|
||||
cooling_frame,
|
||||
textvariable=self.cooling_status_var,
|
||||
values=["OK", "OVERHEATING", "FAULT"],
|
||||
state="readonly"
|
||||
)
|
||||
cooling_combo.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5, pady=5)
|
||||
power_frame = ttk.LabelFrame(self.lru_tab, text="Power Supply Unit Status")
|
||||
power_frame.pack(fill=tk.X, padx=5, pady=5, anchor='n')
|
||||
ttk.Label(power_frame, text="Status:").pack(side=tk.LEFT, padx=5, pady=5)
|
||||
self.power_status_var = tk.StringVar(value="OK")
|
||||
power_combo = ttk.Combobox(
|
||||
power_frame,
|
||||
textvariable=self.power_status_var,
|
||||
values=["OK", "LOW_VOLTAGE", "FAULT"],
|
||||
state="readonly"
|
||||
)
|
||||
power_combo.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5, pady=5)
|
||||
lru_action_frame = ttk.Frame(self.lru_tab)
|
||||
lru_action_frame.pack(fill=tk.X, padx=5, pady=10, anchor='n')
|
||||
self.lru_message_var = tk.StringVar()
|
||||
ttk.Entry(lru_action_frame, textvariable=self.lru_message_var, state="readonly").pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 5))
|
||||
send_lru_button = ttk.Button(lru_action_frame, text="Send LRU Status", command=self._on_send_lru_status)
|
||||
send_lru_button.pack(side=tk.LEFT)
|
||||
|
||||
# Carica gli scenari solo dopo aver creato scenario_controls
|
||||
self._load_scenarios_into_ui()
|
||||
|
||||
# Rimuovi la voce di menu per la configurazione
|
||||
|
||||
def _on_targets_changed(self, targets):
|
||||
# Called by TargetListFrame when targets are changed
|
||||
self.ppi_widget.update_targets(targets)
|
||||
|
||||
def _draw_conn_status_indicator(self, connected: bool):
|
||||
self.conn_status_canvas.delete("all")
|
||||
color = "#2ecc40" if connected else "#e74c3c" # green or red
|
||||
self.conn_status_canvas.create_oval(2, 2, 16, 16, fill=color, outline="black")
|
||||
def _create_statusbar(self):
|
||||
status_bar = ttk.Frame(self, relief=tk.SUNKEN)
|
||||
status_bar.pack(side=tk.BOTTOM, fill=tk.X)
|
||||
|
||||
ttk.Label(status_bar, text="Target:").pack(side=tk.LEFT, padx=(5, 2))
|
||||
self.target_status_canvas = tk.Canvas(status_bar, width=16, height=16, highlightthickness=0)
|
||||
self.target_status_canvas.pack(side=tk.LEFT, padx=(0, 10))
|
||||
self._draw_status_indicator(self.target_status_canvas, "#e74c3c") # Default to red
|
||||
|
||||
ttk.Label(status_bar, text="LRU:").pack(side=tk.LEFT, padx=(5, 2))
|
||||
self.lru_status_canvas = tk.Canvas(status_bar, width=16, height=16, highlightthickness=0)
|
||||
self.lru_status_canvas.pack(side=tk.LEFT, padx=(0, 10))
|
||||
self._draw_status_indicator(self.lru_status_canvas, "#e74c3c") # Default to red
|
||||
|
||||
self.status_var = tk.StringVar(value="Ready")
|
||||
ttk.Label(status_bar, textvariable=self.status_var, anchor=tk.W).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
|
||||
def _on_connect_button(self):
|
||||
try:
|
||||
self.logger.info("Connection requested by user.")
|
||||
self._initialize_communicator()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error during connection: {e}")
|
||||
self._log_message(f"Error during connection: {e}")
|
||||
|
||||
def _log_message(self, message):
|
||||
self.log_text_widget.configure(state=tk.NORMAL)
|
||||
self.log_text_widget.insert(tk.END, message + "\n")
|
||||
self.log_text_widget.configure(state=tk.DISABLED)
|
||||
self.log_text_widget.see(tk.END)
|
||||
def _draw_status_indicator(self, canvas, color):
|
||||
canvas.delete("all")
|
||||
canvas.create_oval(2, 2, 14, 14, fill=color, outline="black")
|
||||
|
||||
def _draw_conn_status_indicator(self, connected: bool):
|
||||
self.conn_status_canvas.delete("all")
|
||||
color = "#2ecc40" if connected else "#e74c3c" # green or red
|
||||
self.conn_status_canvas.create_oval(2, 2, 16, 16, fill=color, outline="black")
|
||||
|
||||
def _get_connection_params_str(self):
|
||||
typ = self.connection_config.get("type", "N/A")
|
||||
if typ == "serial":
|
||||
params = self.connection_config.get("serial", {})
|
||||
return f"Port: {params.get('port', '')}, Baud: {params.get('baudrate', '')}, Parity: {params.get('parity', '')}"
|
||||
elif typ == "tftp":
|
||||
params = self.connection_config.get("tftp", {})
|
||||
return f"IP: {params.get('ip', '')}, Port: {params.get('port', '')}"
|
||||
return ""
|
||||
|
||||
def _create_menubar(self):
|
||||
menubar = tk.Menu(self)
|
||||
@ -118,35 +229,89 @@ class MainView(tk.Tk):
|
||||
menubar.add_cascade(label="Settings", menu=settings_menu)
|
||||
settings_menu.add_command(label="Connection...", command=self._open_settings)
|
||||
settings_menu.add_command(label="Radar Config...", command=self._open_radar_config)
|
||||
|
||||
def _create_statusbar(self):
|
||||
self.status_var = tk.StringVar(value="Status: Disconnected")
|
||||
status_bar = ttk.Label(self, textvariable=self.status_var, anchor=tk.W, relief=tk.SUNKEN)
|
||||
status_bar.pack(side=tk.BOTTOM, fill=tk.X)
|
||||
|
||||
def _initialize_communicator(self):
|
||||
"""Creates and connects the appropriate communicator based on config."""
|
||||
if self.communicator and self.communicator.is_open:
|
||||
self.communicator.disconnect()
|
||||
|
||||
comm_type = self.connection_config.get("type")
|
||||
self.logger.info(f"Initializing communicator of type: {comm_type}")
|
||||
|
||||
if comm_type == "serial":
|
||||
self.communicator = SerialCommunicator()
|
||||
config_data = self.connection_config.get("serial", {})
|
||||
elif comm_type == "tftp":
|
||||
self.communicator = TFTPCommunicator()
|
||||
config_data = self.connection_config.get("tftp", {})
|
||||
else:
|
||||
self.communicator = None
|
||||
self.status_var.set("Status: No communication type configured.")
|
||||
return
|
||||
"""Creates and connects the appropriate communicators based on config."""
|
||||
# Disconnect if already connected
|
||||
if self.target_communicator and self.target_communicator.is_open:
|
||||
self.target_communicator.disconnect()
|
||||
if self.lru_communicator and self.lru_communicator.is_open:
|
||||
self.lru_communicator.disconnect()
|
||||
|
||||
|
||||
# --- Initialize Target Communicator ---
|
||||
# --- Initialize Target Communicator ---
|
||||
target_cfg = self.connection_config.get("target", {})
|
||||
target_comm_type = target_cfg.get("type")
|
||||
self.logger.info(f"Initializing Target communicator of type: {target_comm_type}")
|
||||
self.target_communicator = None
|
||||
config_data = None
|
||||
if target_comm_type == "serial":
|
||||
config_data = target_cfg.get("serial", {})
|
||||
port = config_data.get("port")
|
||||
baudrate = config_data.get("baudrate")
|
||||
if isinstance(port, str) and port and isinstance(baudrate, int):
|
||||
self.target_communicator = SerialCommunicator()
|
||||
if self.target_communicator.connect(config_data):
|
||||
self._draw_status_indicator(self.target_status_canvas, "#2ecc40") # green
|
||||
self.status_var.set("Target: Connected")
|
||||
else:
|
||||
self._draw_status_indicator(self.target_status_canvas, "#e74c3c") # red
|
||||
self.status_var.set("Target: Disconnected")
|
||||
else:
|
||||
self.logger.error(f"Skipped Target serial connection: invalid config {config_data}")
|
||||
self._draw_status_indicator(self.target_status_canvas, "#e74c3c")
|
||||
self.status_var.set("Target: Invalid config")
|
||||
elif target_comm_type == "tftp":
|
||||
config_data = target_cfg.get("tftp", {})
|
||||
ip = config_data.get("ip")
|
||||
port = config_data.get("port")
|
||||
if isinstance(ip, str) and ip and isinstance(port, int):
|
||||
self.target_communicator = TFTPCommunicator()
|
||||
if self.target_communicator.connect(config_data):
|
||||
self._draw_status_indicator(self.target_status_canvas, "#2ecc40") # green
|
||||
self.status_var.set("Target: Connected")
|
||||
else:
|
||||
self._draw_status_indicator(self.target_status_canvas, "#e74c3c") # red
|
||||
self.status_var.set("Target: Disconnected")
|
||||
else:
|
||||
self.logger.error(f"Skipped Target TFTP connection: invalid config {config_data}")
|
||||
self._draw_status_indicator(self.target_status_canvas, "#e74c3c")
|
||||
self.status_var.set("Target: Invalid config")
|
||||
|
||||
# --- Initialize LRU Communicator ---
|
||||
lru_cfg = self.connection_config.get("lru", {})
|
||||
lru_comm_type = lru_cfg.get("type")
|
||||
self.logger.info(f"Initializing LRU communicator of type: {lru_comm_type}")
|
||||
self.lru_communicator = None
|
||||
lru_config_data = None
|
||||
if lru_comm_type == "serial":
|
||||
lru_config_data = lru_cfg.get("serial", {})
|
||||
port = lru_config_data.get("port")
|
||||
baudrate = lru_config_data.get("baudrate")
|
||||
if isinstance(port, str) and port and isinstance(baudrate, int):
|
||||
self.lru_communicator = SerialCommunicator()
|
||||
if self.lru_communicator.connect(lru_config_data):
|
||||
self._draw_status_indicator(self.lru_status_canvas, "#2ecc40") # green
|
||||
else:
|
||||
self._draw_status_indicator(self.lru_status_canvas, "#e74c3c") # red
|
||||
else:
|
||||
self.logger.error(f"Skipped LRU serial connection: invalid config {lru_config_data}")
|
||||
self._draw_status_indicator(self.lru_status_canvas, "#e74c3c")
|
||||
elif lru_comm_type == "tftp":
|
||||
lru_config_data = lru_cfg.get("tftp", {})
|
||||
ip = lru_config_data.get("ip")
|
||||
port = lru_config_data.get("port")
|
||||
if isinstance(ip, str) and ip and isinstance(port, int):
|
||||
self.lru_communicator = TFTPCommunicator()
|
||||
if self.lru_communicator.connect(lru_config_data):
|
||||
self._draw_status_indicator(self.lru_status_canvas, "#2ecc40") # green
|
||||
else:
|
||||
self._draw_status_indicator(self.lru_status_canvas, "#e74c3c") # red
|
||||
else:
|
||||
self.logger.error(f"Skipped LRU TFTP connection: invalid config {lru_config_data}")
|
||||
self._draw_status_indicator(self.lru_status_canvas, "#e74c3c")
|
||||
|
||||
if self.communicator.connect(config_data):
|
||||
self.status_var.set(f"Status: Connected via {comm_type.upper()}")
|
||||
else:
|
||||
self.status_var.set(f"Status: Disconnected (Failed to auto-connect)")
|
||||
|
||||
def update_connection_settings(self, new_config: Dict[str, Any]):
|
||||
"""Callback from SettingsWindow to apply and save new connection settings."""
|
||||
@ -154,52 +319,40 @@ class MainView(tk.Tk):
|
||||
self.connection_config = new_config
|
||||
self.config_manager.save_connection_settings(new_config)
|
||||
self._initialize_communicator() # Re-initialize with new settings
|
||||
# Aggiorna la visualizzazione dei parametri e tipo connessione
|
||||
self.conn_type_var.set(self.connection_config.get("type", "N/A"))
|
||||
self.conn_params_var.set(self._get_connection_params_str())
|
||||
|
||||
def _open_settings(self):
|
||||
self.logger.info("Opening connection settings window.")
|
||||
SettingsWindow(self, self.config_manager, self.connection_config)
|
||||
|
||||
def _on_connect(self):
|
||||
if not self.communicator:
|
||||
self.logger.warning("Cannot connect: communicator not initialized. Please configure settings.")
|
||||
messagebox.showwarning("Not Configured", "Please configure the connection in the Settings menu first.")
|
||||
return
|
||||
if self.communicator.is_open:
|
||||
self.logger.info("Already connected.")
|
||||
# Always update indicator and buttons if already connected
|
||||
self.connect_btn.state(["disabled"])
|
||||
self.disconnect_btn.state(["!disabled"])
|
||||
self._draw_conn_status_indicator(connected=True)
|
||||
return
|
||||
self._initialize_communicator() # Re-attempt connection
|
||||
# Update button states and indicator
|
||||
if self.communicator and self.communicator.is_open:
|
||||
self.connect_btn.state(["disabled"])
|
||||
self.disconnect_btn.state(["!disabled"])
|
||||
self._draw_conn_status_indicator(connected=True)
|
||||
|
||||
def _on_disconnect(self):
|
||||
if self.communicator and self.communicator.is_open:
|
||||
self.communicator.disconnect()
|
||||
self.status_var.set("Status: Disconnected")
|
||||
self.logger.info("User manually disconnected.")
|
||||
self.connect_btn.state(["!disabled"])
|
||||
self.disconnect_btn.state(["disabled"])
|
||||
self._draw_conn_status_indicator(connected=False)
|
||||
else:
|
||||
self.logger.info("Already disconnected.")
|
||||
ConnectionSettingsWindow(self, self.config_manager, self.connection_config)
|
||||
|
||||
def _on_send_scenario(self):
|
||||
if self.communicator and self.communicator.is_open:
|
||||
if self.target_communicator and self.target_communicator.is_open:
|
||||
if self.scenario and self.scenario.get_all_targets():
|
||||
self.communicator.send_scenario(self.scenario)
|
||||
self.target_communicator.send_scenario(self.scenario)
|
||||
else:
|
||||
messagebox.showinfo("Empty Scenario", "Cannot send an empty scenario.", parent=self)
|
||||
else:
|
||||
messagebox.showerror("Not Connected", "Please connect before sending a scenario.", parent=self)
|
||||
messagebox.showerror("Not Connected", "Target communicator is not connected. Please check settings.", parent=self)
|
||||
|
||||
def _on_send_lru_status(self):
|
||||
cooling_status = self.cooling_status_var.get()
|
||||
power_status = self.power_status_var.get()
|
||||
|
||||
# Assume a simple CSV-like format for the message
|
||||
message = f"LRU_STATUS,COOLING={cooling_status},POWER={power_status}"
|
||||
self.lru_message_var.set(message)
|
||||
self.logger.info(f"Formatted LRU status message: {message}")
|
||||
|
||||
if self.lru_communicator and self.lru_communicator.is_open:
|
||||
if hasattr(self.lru_communicator, 'send_raw_message'):
|
||||
self.lru_communicator.send_raw_message(message)
|
||||
self.logger.info("Sent LRU status message to radar.")
|
||||
messagebox.showinfo("LRU Status Sent", f"Message sent:\n{message}", parent=self)
|
||||
else:
|
||||
self.logger.warning("Communicator does not have a 'send_raw_message' method.")
|
||||
messagebox.showwarning("Not Supported", "The current communicator does not support sending raw messages.", parent=self)
|
||||
else:
|
||||
self.logger.warning("Attempted to send LRU status while disconnected.")
|
||||
messagebox.showerror("Not Connected", "LRU communicator is not connected. Please check settings.", parent=self)
|
||||
|
||||
# --- Other methods remain largely the same ---
|
||||
|
||||
@ -219,6 +372,9 @@ class MainView(tk.Tk):
|
||||
def _load_scenarios_into_ui(self):
|
||||
scenario_names = self.config_manager.get_scenario_names()
|
||||
self.scenario_controls.update_scenario_list(scenario_names, self.current_scenario_name)
|
||||
# Also update the values for the simulation tab combobox
|
||||
if hasattr(self, 'sim_scenario_combobox'):
|
||||
self.sim_scenario_combobox['values'] = scenario_names
|
||||
|
||||
# Rimosso: la logica di aggiunta target è ora nel TargetListFrame
|
||||
|
||||
@ -245,12 +401,19 @@ class MainView(tk.Tk):
|
||||
self._update_window_title()
|
||||
messagebox.showinfo("Success", f"Scenario '{scenario_name}' saved successfully.", parent=self)
|
||||
|
||||
def _on_update_scenario(self, scenario_name: str):
|
||||
self.logger.info(f"Updating scenario: {scenario_name}")
|
||||
def _on_save_scenario(self, scenario_name: str):
|
||||
"""
|
||||
Save the current scenario and its targets (from the target list) under the selected name.
|
||||
"""
|
||||
self.logger.info(f"Saving scenario: {scenario_name}")
|
||||
# Update scenario's targets from the target list
|
||||
self.scenario.targets = {t.target_id: t for t in self.target_list.get_targets()}
|
||||
scenario_data = self.scenario.to_dict()
|
||||
self.config_manager.save_scenario(scenario_name, scenario_data)
|
||||
self._load_scenarios_into_ui() # Refresh list to be safe
|
||||
messagebox.showinfo("Success", f"Scenario '{scenario_name}' updated successfully.", parent=self)
|
||||
self.current_scenario_name = scenario_name
|
||||
self._load_scenarios_into_ui() # Refresh list
|
||||
self._update_window_title()
|
||||
messagebox.showinfo("Success", f"Scenario '{scenario_name}' saved successfully.", parent=self)
|
||||
|
||||
def _on_delete_scenario(self, scenario_name: str):
|
||||
self.logger.info(f"Deleting scenario: {scenario_name}")
|
||||
@ -288,7 +451,10 @@ class MainView(tk.Tk):
|
||||
self.config_manager.save_general_settings(settings_to_save)
|
||||
self.config_manager.save_connection_settings(self.connection_config)
|
||||
|
||||
if self.communicator and self.communicator.is_open:
|
||||
self.communicator.disconnect()
|
||||
if self.target_communicator and self.target_communicator.is_open:
|
||||
self.target_communicator.disconnect()
|
||||
if self.lru_communicator and self.lru_communicator.is_open:
|
||||
self.lru_communicator.disconnect()
|
||||
|
||||
shutdown_logging_system()
|
||||
self.destroy()
|
||||
self.destroy()
|
||||
|
||||
@ -13,17 +13,19 @@ class ScenarioControlsFrame(ttk.LabelFrame):
|
||||
|
||||
|
||||
def __init__(self, master, *,
|
||||
main_view,
|
||||
load_scenario_command: Callable[[str], None],
|
||||
save_as_command: Callable[[str], None],
|
||||
update_command: Callable[[str], None],
|
||||
delete_command: Callable[[str], None],
|
||||
new_scenario_command: Callable[[str], None],
|
||||
send_scenario_command: Callable[[], None] = None):
|
||||
super().__init__(master, text="Scenario Controls")
|
||||
|
||||
self.main_view = main_view
|
||||
self._load_scenario_command = load_scenario_command
|
||||
self._save_as_command = save_as_command
|
||||
self._update_command = update_command
|
||||
self._delete_command = delete_command
|
||||
self._new_scenario_command = new_scenario_command
|
||||
self._send_scenario_command = send_scenario_command
|
||||
|
||||
self.current_scenario = tk.StringVar()
|
||||
@ -48,27 +50,52 @@ class ScenarioControlsFrame(ttk.LabelFrame):
|
||||
send_btn = ttk.Button(top_frame, text="Send Scenario", command=self._send_scenario_command)
|
||||
send_btn.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
self.new_button = ttk.Button(
|
||||
top_frame, text="New...", command=self._on_new
|
||||
)
|
||||
self.new_button.pack(side=tk.LEFT, padx=(10, 5))
|
||||
|
||||
self.save_button = ttk.Button(
|
||||
top_frame, text="Save", command=self._on_save
|
||||
)
|
||||
self.save_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
self.save_as_button = ttk.Button(
|
||||
top_frame, text="Save As...", command=self._on_save_as
|
||||
)
|
||||
self.save_as_button.pack(side=tk.LEFT, padx=(10, 5))
|
||||
self.save_as_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
self.update_button = ttk.Button(
|
||||
top_frame, text="Update", command=self._on_update
|
||||
)
|
||||
self.update_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
self.delete_button = ttk.Button(
|
||||
top_frame, text="Delete", command=self._on_delete
|
||||
)
|
||||
self.delete_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
def _on_save(self):
|
||||
"""Handle the 'Save' button click: overwrite the selected scenario."""
|
||||
scenario_name = self.current_scenario.get()
|
||||
if not scenario_name:
|
||||
messagebox.showwarning("No Scenario Selected", "Please select a scenario to save.", parent=self)
|
||||
return
|
||||
# Call the new save method in MainView
|
||||
self.main_view._on_save_scenario(scenario_name)
|
||||
|
||||
def _on_scenario_select(self, event):
|
||||
"""Callback for when a scenario is selected from the combobox."""
|
||||
scenario_name = self.current_scenario.get()
|
||||
if scenario_name:
|
||||
self._load_scenario_command(scenario_name)
|
||||
|
||||
def _on_new(self):
|
||||
"""Handle the 'New' button click."""
|
||||
scenario_name = simpledialog.askstring(
|
||||
"New Scenario",
|
||||
"Enter a name for the new scenario:",
|
||||
parent=self
|
||||
)
|
||||
if scenario_name:
|
||||
self._new_scenario_command(scenario_name)
|
||||
|
||||
def _on_save_as(self):
|
||||
"""Handle the 'Save As' button click."""
|
||||
scenario_name = simpledialog.askstring(
|
||||
@ -79,13 +106,6 @@ class ScenarioControlsFrame(ttk.LabelFrame):
|
||||
if scenario_name:
|
||||
self._save_as_command(scenario_name)
|
||||
|
||||
def _on_update(self):
|
||||
"""Handle the 'Update' button click."""
|
||||
scenario_name = self.current_scenario.get()
|
||||
if not scenario_name:
|
||||
messagebox.showwarning("No Scenario Selected", "Please select a scenario to update.", parent=self)
|
||||
return
|
||||
self._update_command(scenario_name)
|
||||
|
||||
def _on_delete(self):
|
||||
"""Handle the 'Delete' button click."""
|
||||
|
||||
@ -51,10 +51,8 @@ class TargetListFrame(ttk.LabelFrame):
|
||||
|
||||
# --- Buttons ---
|
||||
|
||||
button_frame = ttk.Frame(self, relief=tk.RAISED, borderwidth=1)
|
||||
button_frame.grid(row=2, column=0, columnspan=2, pady=10, padx=10, sticky="ew")
|
||||
self.rowconfigure(2, weight=0)
|
||||
self.columnconfigure(0, weight=1)
|
||||
button_frame = ttk.Frame(self)
|
||||
button_frame.grid(row=1, column=0, columnspan=2, pady=5)
|
||||
|
||||
self.add_button = ttk.Button(button_frame, text="Add", command=self._on_add_click)
|
||||
self.add_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
@ -12,20 +12,11 @@ from typing import Dict, Any, Optional, List
|
||||
class ConfigManager:
|
||||
def save_connection_settings(self, config: Dict[str, Any]):
|
||||
"""
|
||||
Updates only the selected connection type settings, preserving the other type.
|
||||
Save both target and lru connection configs in the settings file.
|
||||
"""
|
||||
if "general" not in self._settings:
|
||||
self._settings["general"] = {}
|
||||
conn = self._settings["general"].get("connection", {})
|
||||
# Aggiorna solo la sezione del tipo selezionato
|
||||
typ = config.get("type")
|
||||
if typ == "serial":
|
||||
conn["type"] = "serial"
|
||||
conn["serial"] = config.get("serial", {})
|
||||
elif typ == "tftp":
|
||||
conn["type"] = "tftp"
|
||||
conn["tftp"] = config.get("tftp", {})
|
||||
self._settings["general"]["connection"] = conn
|
||||
self._settings["general"]["connection"] = config
|
||||
self._save_settings()
|
||||
def get_connection_settings(self) -> Dict[str, Any]:
|
||||
"""
|
||||
|
||||
Loading…
Reference in New Issue
Block a user