draft add flight analyzer tab
This commit is contained in:
parent
db0e26b5a1
commit
06b1fe79e1
@ -3,6 +3,7 @@
|
||||
"last_opened_rec_file": "C:/src/____GitProjects/radar_data_reader/_rec/_25-05-15-12-22-52_sata_345.rec",
|
||||
"last_out_output_dir": "C:/src/____GitProjects/radar_data_reader/_rec",
|
||||
"last_rec_output_dir": "C:\\src\\____GitProjects\\radar_data_reader\\_rec",
|
||||
"last_flight_folder": "//tsclient/F/__DATI_VOLI/Volo12 - Maggio 2025/_rec",
|
||||
"active_out_export_profile_name": "gsp_data",
|
||||
"export_profiles": [
|
||||
{
|
||||
|
||||
@ -16,6 +16,7 @@ from typing import List, Any, Dict, Tuple, Optional
|
||||
from tkinter import filedialog, messagebox
|
||||
import tkinter as tk
|
||||
import ctypes
|
||||
import threading
|
||||
|
||||
from ..utils.config_manager import ConfigManager
|
||||
from ..core.file_reader import run_worker_process
|
||||
@ -532,3 +533,71 @@ class AppController:
|
||||
self.worker_process.terminate()
|
||||
self._close_all_files()
|
||||
logger.shutdown_logging_system()
|
||||
|
||||
def select_and_analyze_flight_folder(self):
|
||||
"""
|
||||
Opens a dialog to select a folder and then starts the analysis
|
||||
in a separate thread to keep the GUI responsive.
|
||||
"""
|
||||
initial_dir = self.config_manager.get("last_flight_folder")
|
||||
if new_dir := filedialog.askdirectory(
|
||||
initialdir=initial_dir, title="Select Folder with Flight Recordings"
|
||||
):
|
||||
# --- Update GUI immediately to show something is happening ---
|
||||
self.view.analyzer_rec_folder_var.set(new_dir)
|
||||
self.view.analyzer_info_var.set("Scanning folder, please wait...")
|
||||
self.view.start_analysis_button.config(state=tk.DISABLED)
|
||||
# Force GUI update
|
||||
self.view.update_idletasks()
|
||||
|
||||
# --- Run the slow analysis in a background thread ---
|
||||
analysis_thread = threading.Thread(
|
||||
target=self._analyze_folder_worker,
|
||||
args=(new_dir,),
|
||||
daemon=True
|
||||
)
|
||||
analysis_thread.start()
|
||||
|
||||
def _analyze_folder_worker(self, dir_path_str: str):
|
||||
"""
|
||||
Worker thread function to perform the slow task of scanning folder contents.
|
||||
"""
|
||||
try:
|
||||
folder_path = Path(dir_path_str)
|
||||
self.config_manager.set("last_flight_folder", dir_path_str)
|
||||
self.config_manager.save_config()
|
||||
|
||||
rec_files = sorted([f for f in folder_path.glob("*.rec")])
|
||||
|
||||
if not rec_files:
|
||||
self.view.analyzer_info_var.set("No .rec files found in the selected folder.")
|
||||
# The button remains disabled, which is correct
|
||||
return
|
||||
|
||||
total_size_bytes = sum(f.stat().st_size for f in rec_files)
|
||||
total_size_mb = total_size_bytes / (1024 * 1024)
|
||||
file_count = len(rec_files)
|
||||
|
||||
info_text = (
|
||||
f"Found {file_count} .rec files, "
|
||||
f"Total size: {total_size_mb:.2f} MB. Ready for analysis."
|
||||
)
|
||||
self.view.analyzer_info_var.set(info_text)
|
||||
|
||||
# Generate default flight name
|
||||
first_file_name = rec_files[0].stem
|
||||
match = re.search(r"(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})", first_file_name)
|
||||
if match:
|
||||
yy, mo, dd, hh, mi, ss = match.groups()
|
||||
flight_name = f"{yy}{mo}{dd}_{hh}{mi}{ss}_Flight"
|
||||
self.view.analyzer_flight_name_var.set(flight_name)
|
||||
else:
|
||||
self.view.analyzer_flight_name_var.set(f"{folder_path.name}_Flight")
|
||||
|
||||
# Enable the analysis button on the main thread
|
||||
self.view.start_analysis_button.config(state=tk.NORMAL)
|
||||
|
||||
except Exception as e:
|
||||
log.error(f"Error in folder analysis worker: {e}", exc_info=True)
|
||||
self.view.analyzer_info_var.set(f"Error during folder analysis: {e}")
|
||||
self.view.start_analysis_button.config(state=tk.DISABLED)
|
||||
|
||||
@ -75,6 +75,10 @@ class MainWindow(tk.Frame):
|
||||
self.progress_text_var = tk.StringVar(value="N/A")
|
||||
self.batches_found_var = tk.StringVar(value="N/A")
|
||||
self.progress_bar_var = tk.DoubleVar(value=0)
|
||||
|
||||
self.analyzer_rec_folder_var = tk.StringVar()
|
||||
self.analyzer_flight_name_var = tk.StringVar()
|
||||
self.analyzer_info_var = tk.StringVar(value="Please select a folder and a flight name.")
|
||||
|
||||
def _create_widgets(self):
|
||||
menu_bar = tk.Menu(self.master)
|
||||
@ -98,12 +102,19 @@ class MainWindow(tk.Frame):
|
||||
|
||||
self.out_processor_tab = ttk.Frame(self.notebook, padding="10")
|
||||
self.rec_converter_tab = ttk.Frame(self.notebook, padding="10")
|
||||
# --- NUOVA RIGA ---
|
||||
self.flight_analyzer_tab = ttk.Frame(self.notebook, padding="10")
|
||||
|
||||
# --- ORDINE MODIFICATO ---
|
||||
# Mettiamo il nuovo wizard come prima tab perché è il punto di partenza del workflow
|
||||
self.notebook.add(self.flight_analyzer_tab, text="Flight Analyzer")
|
||||
self.notebook.add(self.out_processor_tab, text="OUT Processor")
|
||||
self.notebook.add(self.rec_converter_tab, text="REC to OUT Converter")
|
||||
|
||||
self._create_out_processor_tab(self.out_processor_tab)
|
||||
self._create_rec_converter_tab(self.rec_converter_tab)
|
||||
# --- NUOVA CHIAMATA ---
|
||||
self._create_flight_analyzer_tab(self.flight_analyzer_tab)
|
||||
|
||||
self._create_log_console_frame(main_frame)
|
||||
|
||||
@ -115,6 +126,79 @@ class MainWindow(tk.Frame):
|
||||
padding=2,
|
||||
)
|
||||
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
|
||||
|
||||
def _create_flight_analyzer_tab(self, parent):
|
||||
"""Creates the widgets for the new Flight Analyzer wizard tab."""
|
||||
parent.columnconfigure(0, weight=1)
|
||||
# La riga 2 conterrà la timeline, quindi le diamo peso per espandersi
|
||||
parent.rowconfigure(2, weight=1)
|
||||
|
||||
# --- Frame 1: Input e Setup del Volo ---
|
||||
setup_frame = ttk.LabelFrame(parent, text="Flight Setup")
|
||||
setup_frame.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
|
||||
setup_frame.columnconfigure(1, weight=1)
|
||||
|
||||
# Selezione cartella REC
|
||||
ttk.Label(setup_frame, text="Recordings Folder:").grid(
|
||||
row=0, column=0, padx=5, pady=5, sticky="w"
|
||||
)
|
||||
rec_folder_entry = ttk.Entry(
|
||||
setup_frame, textvariable=self.analyzer_rec_folder_var, state="readonly"
|
||||
)
|
||||
rec_folder_entry.grid(row=0, column=1, sticky="ew", padx=5)
|
||||
ttk.Button(
|
||||
setup_frame, text="Browse...", command=self.controller.select_and_analyze_flight_folder).grid(row=0, column=2, padx=5)
|
||||
|
||||
# Nome del Volo
|
||||
ttk.Label(setup_frame, text="Flight Name:").grid(
|
||||
row=1, column=0, padx=5, pady=5, sticky="w"
|
||||
)
|
||||
flight_name_entry = ttk.Entry(setup_frame, textvariable=self.analyzer_flight_name_var)
|
||||
flight_name_entry.grid(row=1, column=1, columnspan=2, sticky="ew", padx=5)
|
||||
|
||||
# --- Frame 2: Azioni e Informazioni ---
|
||||
action_frame = ttk.Frame(parent)
|
||||
action_frame.grid(row=1, column=0, sticky="ew", padx=5, pady=10)
|
||||
|
||||
self.start_analysis_button = ttk.Button(
|
||||
action_frame, text="Start Flight Analysis", command=lambda: print("TODO: Start Analysis"),
|
||||
state=tk.DISABLED
|
||||
)
|
||||
self.start_analysis_button.pack(side=tk.LEFT)
|
||||
|
||||
# Area per info preliminari
|
||||
info_label = ttk.Label(action_frame, textvariable=self.analyzer_info_var)
|
||||
info_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
|
||||
# --- Frame 3: Risultati e Timeline ---
|
||||
results_frame = ttk.LabelFrame(parent, text="Flight Summary & Segments")
|
||||
results_frame.grid(row=2, column=0, sticky="nsew", padx=5, pady=5)
|
||||
results_frame.columnconfigure(0, weight=1)
|
||||
results_frame.rowconfigure(0, weight=1)
|
||||
|
||||
# Tabella per la timeline
|
||||
self.flight_timeline_tree = ttk.Treeview(
|
||||
results_frame,
|
||||
columns=("mode", "start_batch", "end_batch", "duration"),
|
||||
show="headings"
|
||||
)
|
||||
self.flight_timeline_tree.heading("mode", text="Mode")
|
||||
self.flight_timeline_tree.heading("start_batch", text="Start Batch")
|
||||
self.flight_timeline_tree.heading("end_batch", text="End Batch")
|
||||
self.flight_timeline_tree.heading("duration", text="Duration (s)")
|
||||
self.flight_timeline_tree.grid(row=0, column=0, sticky="nsew")
|
||||
|
||||
# Scrollbar per la tabella
|
||||
tree_scrollbar = ttk.Scrollbar(results_frame, orient="vertical", command=self.flight_timeline_tree.yview)
|
||||
self.flight_timeline_tree.configure(yscrollcommand=tree_scrollbar.set)
|
||||
tree_scrollbar.grid(row=0, column=1, sticky="ns")
|
||||
|
||||
# Bottone per esportare i segmenti
|
||||
self.export_segment_button = ttk.Button(
|
||||
results_frame, text="Export Selected Segment(s)", state=tk.DISABLED, command=lambda: print("TODO: Export Segment") # TODO
|
||||
)
|
||||
self.export_segment_button.grid(row=1, column=0, columnspan=2, pady=5)
|
||||
|
||||
def _create_out_processor_tab(self, parent):
|
||||
parent.columnconfigure(1, weight=1)
|
||||
|
||||
@ -79,6 +79,7 @@ class ConfigManager:
|
||||
"last_opened_rec_file": "",
|
||||
"last_out_output_dir": "",
|
||||
"last_rec_output_dir": "",
|
||||
"last_flight_folder": "",
|
||||
"active_out_export_profile_name": "Default",
|
||||
"export_profiles": [default_export_profile.to_dict()],
|
||||
"cpp_converter_config": default_cpp_config,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user