208 lines
7.9 KiB
Python
208 lines
7.9 KiB
Python
# FlightMonitor/gui/panels/data_logging_panel.py
|
|
"""
|
|
Defines the GUI panel for controlling raw data logging functionality.
|
|
This panel is designed to be shared across different monitoring modes.
|
|
"""
|
|
import tkinter as tk
|
|
from tkinter import ttk, filedialog, font as tkFont
|
|
from typing import Optional, Any
|
|
from datetime import datetime, timezone
|
|
|
|
from flightmonitor.utils.logger import get_logger
|
|
|
|
module_logger = get_logger(__name__)
|
|
|
|
|
|
class DataLoggingPanel:
|
|
"""
|
|
Manages the GUI elements for enabling and configuring raw data logging.
|
|
"""
|
|
|
|
def __init__(self, parent_frame: ttk.Frame, controller: Any):
|
|
"""
|
|
Initializes the DataLoggingPanel.
|
|
|
|
Args:
|
|
parent_frame: The parent ttk.Frame where this panel will be placed.
|
|
controller: The application controller instance.
|
|
"""
|
|
self.parent_frame = parent_frame
|
|
self.controller = controller
|
|
|
|
# --- Tkinter Variables ---
|
|
self.enable_logging_var = tk.BooleanVar(value=False)
|
|
self.log_directory_var = tk.StringVar(value="")
|
|
self.last_query_result_var = tk.StringVar(value="Last query result: N/A")
|
|
|
|
# --- Widget References ---
|
|
self.log_dir_entry: Optional[ttk.Entry] = None
|
|
self.browse_button: Optional[ttk.Button] = None
|
|
self.open_folder_button: Optional[ttk.Button] = (
|
|
None # MODIFICATO: Aggiunto riferimento
|
|
)
|
|
self.summary_table: Optional[ttk.Treeview] = None
|
|
|
|
self._build_ui()
|
|
module_logger.debug("DataLoggingPanel initialized.")
|
|
|
|
def _build_ui(self):
|
|
"""Builds all the widgets for the panel."""
|
|
container = ttk.LabelFrame(
|
|
self.parent_frame, text="Data Logging Session", padding=10
|
|
)
|
|
container.pack(fill=tk.X, expand=True, padx=2, pady=5)
|
|
|
|
self.enable_checkbox = ttk.Checkbutton(
|
|
container,
|
|
text="Enable Raw Data Logging",
|
|
variable=self.enable_logging_var,
|
|
command=self._on_toggle_logging,
|
|
)
|
|
self.enable_checkbox.pack(anchor=tk.W, pady=(0, 5))
|
|
|
|
dir_frame = ttk.Frame(container)
|
|
dir_frame.pack(fill=tk.X, expand=True)
|
|
dir_frame.columnconfigure(1, weight=1)
|
|
|
|
ttk.Label(dir_frame, text="Save to:").grid(
|
|
row=0, column=0, sticky=tk.W, padx=(0, 5)
|
|
)
|
|
self.log_dir_entry = ttk.Entry(
|
|
dir_frame, textvariable=self.log_directory_var, state=tk.DISABLED
|
|
)
|
|
self.log_dir_entry.grid(row=0, column=1, sticky=tk.EW)
|
|
|
|
# MODIFICATO: Aggiunto il nuovo pulsante "Open Folder"
|
|
self.browse_button = ttk.Button(
|
|
dir_frame,
|
|
text="Browse...",
|
|
command=self._on_browse_directory,
|
|
state=tk.DISABLED,
|
|
)
|
|
self.browse_button.grid(row=0, column=2, sticky=tk.E, padx=(5, 2))
|
|
|
|
self.open_folder_button = ttk.Button(
|
|
dir_frame,
|
|
text="Open Folder",
|
|
command=self._on_open_folder,
|
|
state=tk.DISABLED,
|
|
)
|
|
self.open_folder_button.grid(row=0, column=3, sticky=tk.E, padx=(2, 0))
|
|
# --- FINE MODIFICA ---
|
|
|
|
last_result_font = tkFont.Font(family="Helvetica", size=9, slant="italic")
|
|
last_result_label = ttk.Label(
|
|
container,
|
|
textvariable=self.last_query_result_var,
|
|
font=last_result_font,
|
|
foreground="navy",
|
|
)
|
|
last_result_label.pack(anchor=tk.W, pady=(8, 2))
|
|
|
|
table_frame = ttk.Frame(container)
|
|
table_frame.pack(fill=tk.BOTH, expand=True, pady=(2, 0))
|
|
|
|
self.summary_table = ttk.Treeview(
|
|
table_frame, columns=("timestamp", "count"), show="headings", height=4
|
|
)
|
|
self.summary_table.heading("timestamp", text="Fetch Timestamp (UTC)")
|
|
self.summary_table.heading("count", text="Aircraft Count")
|
|
self.summary_table.column("timestamp", width=160, anchor=tk.W)
|
|
self.summary_table.column("count", width=100, anchor=tk.CENTER)
|
|
|
|
scrollbar = ttk.Scrollbar(
|
|
table_frame, orient="vertical", command=self.summary_table.yview
|
|
)
|
|
self.summary_table.configure(yscrollcommand=scrollbar.set)
|
|
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
self.summary_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
|
|
def _on_toggle_logging(self):
|
|
is_enabled = self.enable_logging_var.get()
|
|
new_state = tk.NORMAL if is_enabled else tk.DISABLED
|
|
if self.log_dir_entry:
|
|
self.log_dir_entry.config(state=new_state)
|
|
if self.browse_button:
|
|
self.browse_button.config(state=new_state)
|
|
# MODIFICATO: Abilita/disabilita anche il nuovo pulsante
|
|
if self.open_folder_button:
|
|
self.open_folder_button.config(state=new_state)
|
|
module_logger.info(
|
|
f"Raw data logging has been {'enabled' if is_enabled else 'disabled'} by user."
|
|
)
|
|
|
|
def _on_browse_directory(self):
|
|
directory = filedialog.askdirectory(
|
|
title="Select Directory to Save Raw Data", parent=self.parent_frame
|
|
)
|
|
if directory:
|
|
self.log_directory_var.set(directory)
|
|
module_logger.info(f"User selected new log directory: {directory}")
|
|
|
|
# MODIFICATO: Aggiunto il metodo callback per "Open Folder"
|
|
def _on_open_folder(self):
|
|
"""Callback for the 'Open Folder' button."""
|
|
directory_path = self.get_log_directory()
|
|
if self.controller and hasattr(self.controller, "open_log_directory"):
|
|
self.controller.open_log_directory(directory_path)
|
|
else:
|
|
module_logger.error(
|
|
"Controller or 'open_log_directory' method not available."
|
|
)
|
|
|
|
def is_logging_enabled(self) -> bool:
|
|
return self.enable_logging_var.get()
|
|
|
|
def get_log_directory(self) -> str:
|
|
return self.log_directory_var.get()
|
|
|
|
def add_summary_entry(self, timestamp: float, count: int):
|
|
if not self.summary_table or not self.summary_table.winfo_exists():
|
|
return
|
|
|
|
try:
|
|
dt_object = datetime.fromtimestamp(timestamp, timezone.utc)
|
|
time_str = dt_object.strftime("%Y-%m-%d %H:%M:%S")
|
|
self.summary_table.insert("", 0, values=(time_str, count))
|
|
except (ValueError, TypeError) as e:
|
|
module_logger.error(f"Failed to add summary entry to table: {e}")
|
|
except tk.TclError:
|
|
module_logger.warning(
|
|
"TclError adding summary to table, widget likely destroyed."
|
|
)
|
|
|
|
def update_last_query_result(self, timestamp: float, count: int):
|
|
try:
|
|
dt_object = datetime.fromtimestamp(timestamp, timezone.utc)
|
|
time_str = dt_object.strftime("%H:%M:%S")
|
|
result_text = f"Last query result: {count} aircraft at {time_str} UTC"
|
|
self.last_query_result_var.set(result_text)
|
|
except (ValueError, TypeError):
|
|
self.last_query_result_var.set("Last query result: Invalid timestamp")
|
|
except tk.TclError:
|
|
module_logger.warning(
|
|
"TclError updating last query label, widget likely destroyed."
|
|
)
|
|
|
|
def clear_summary_table(self):
|
|
if not self.summary_table or not self.summary_table.winfo_exists():
|
|
return
|
|
self.last_query_result_var.set("Last query result: N/A")
|
|
try:
|
|
for item in self.summary_table.get_children():
|
|
self.summary_table.delete(item)
|
|
module_logger.info("Data logging summary table cleared.")
|
|
except tk.TclError:
|
|
module_logger.warning(
|
|
"TclError clearing summary table, widget likely destroyed."
|
|
)
|
|
|
|
def update_settings(self, enabled: bool, directory: str):
|
|
self.enable_logging_var.set(enabled)
|
|
self.log_directory_var.set(directory)
|
|
self._on_toggle_logging()
|
|
module_logger.debug(
|
|
f"DataLoggingPanel settings updated: enabled={enabled}, dir='{directory}'"
|
|
)
|