sistemati alcuni messaggi

This commit is contained in:
VALLONGOL 2025-11-26 13:50:07 +01:00
parent 5fa6477dca
commit 99253d02a1
3 changed files with 91 additions and 27 deletions

View File

@ -30,11 +30,13 @@ class ActionHandlers:
self.app._set_phase("Scanning...") self.app._set_phase("Scanning...")
self.app._current_mode = 'scan' self.app._current_mode = 'scan'
# Disable action buttons during operation
self.app._disable_action_buttons()
# Reset UI # Reset UI
self._reset_progress_ui() self._reset_progress_ui()
self.app._set_results_columns(("name", "path")) self.app._set_results_columns(("name", "path"))
self._clear_results() self._clear_results()
self.app.export_btn.config(state='disabled')
self.app.update_idletasks() self.app.update_idletasks()
# Get paths and filters # Get paths and filters
@ -74,11 +76,13 @@ class ActionHandlers:
self.app._set_phase("Counting...") self.app._set_phase("Counting...")
self.app._current_mode = 'countings' self.app._current_mode = 'countings'
# Disable action buttons during operation
self.app._disable_action_buttons()
# Reset UI # Reset UI
self._reset_progress_ui() self._reset_progress_ui()
self.app._set_results_columns(("name", "path", "code", "comment", "blank", "total", "language")) self.app._set_results_columns(("name", "path", "code", "comment", "blank", "total", "language"))
self._clear_results() self._clear_results()
self.app.export_btn.config(state='disabled')
self.app.update_idletasks() self.app.update_idletasks()
paths, allowed_exts, ignore_patterns, pr = self.app._resolve_profile_and_filters() paths, allowed_exts, ignore_patterns, pr = self.app._resolve_profile_and_filters()
@ -94,8 +98,8 @@ class ActionHandlers:
files = results or [] files = results or []
if not files: if not files:
messagebox.showinfo("Countings", "No files found to analyze.") messagebox.showinfo("Countings", "No files found to analyze.")
self.app.cancel_btn.config(state='disabled')
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
from ..core.countings_impl import analyze_file_counts from ..core.countings_impl import analyze_file_counts
@ -131,11 +135,13 @@ class ActionHandlers:
self.app._set_phase("Computing metrics...") self.app._set_phase("Computing metrics...")
self.app._current_mode = 'metrics' self.app._current_mode = 'metrics'
# Disable action buttons during operation
self.app._disable_action_buttons()
# Reset UI # Reset UI
self._reset_progress_ui() self._reset_progress_ui()
self.app._set_results_columns(("name", "path", "avg_cc", "max_cc", "func_count", "mi", "language")) self.app._set_results_columns(("name", "path", "avg_cc", "max_cc", "func_count", "mi", "language"))
self._clear_results() self._clear_results()
self.app.export_btn.config(state='disabled')
self.app.update_idletasks() self.app.update_idletasks()
paths, allowed_exts, ignore_patterns, pr = self.app._resolve_profile_and_filters() paths, allowed_exts, ignore_patterns, pr = self.app._resolve_profile_and_filters()
@ -151,8 +157,8 @@ class ActionHandlers:
files = results or [] files = results or []
if not files: if not files:
messagebox.showinfo("Metrics", "No files found to analyze.") messagebox.showinfo("Metrics", "No files found to analyze.")
self.app.cancel_btn.config(state='disabled')
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
try: try:
@ -160,6 +166,7 @@ class ActionHandlers:
except Exception: except Exception:
messagebox.showerror("Metrics", "Metrics analyzer not available") messagebox.showerror("Metrics", "Metrics analyzer not available")
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
self.app._total_files = len(files) self.app._total_files = len(files)
@ -194,7 +201,9 @@ class ActionHandlers:
self.app._set_results_columns(("fileA", "fileB", "added", "deleted", "modified", "unmodified", "Δ code_lines", "Δ comment_lines", "Δ blank_lines", "Δ func_count", "Δ avg_cc", "Δ mi")) self.app._set_results_columns(("fileA", "fileB", "added", "deleted", "modified", "unmodified", "Δ code_lines", "Δ comment_lines", "Δ blank_lines", "Δ func_count", "Δ avg_cc", "Δ mi"))
self._clear_results() self._clear_results()
self.app._current_mode = 'differ' self.app._current_mode = 'differ'
self.app.export_btn.config(state='disabled')
# Disable action buttons during operation
self.app._disable_action_buttons()
try: try:
self.app._lbl_files.config(text="Files: 0/0") self.app._lbl_files.config(text="Files: 0/0")
@ -215,22 +224,35 @@ class ActionHandlers:
self.app.update_idletasks() self.app.update_idletasks()
bm = BaselineManager(project) bm = BaselineManager(project)
baselines = bm.list_baselines() all_baselines = bm.list_baselines()
profile_name = pr.get('name') if pr else None profile_name = pr.get('name') if pr else None
max_keep = app_settings.get_max_keep() max_keep = app_settings.get_max_keep()
# Filter baselines by current profile
baselines = []
for baseline_id in all_baselines:
try:
meta = bm.load_metadata(baseline_id)
baseline_profile = meta.profile if hasattr(meta, 'profile') else None
# Match baselines with same profile (or both None)
if baseline_profile == profile_name:
baselines.append(baseline_id)
except Exception:
# Skip baselines that can't be loaded
pass
# Callback handlers # Callback handlers
def _on_create_done(baseline_id): def _on_create_done(baseline_id):
try: try:
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._current_task_id = None self.app._current_task_id = None
self.app.cancel_btn.config(state='disabled') self.app._enable_action_buttons()
messagebox.showinfo("Differing", f"Baseline created: {baseline_id}") messagebox.showinfo("Differing", f"Baseline created: {baseline_id}")
except Exception: except Exception:
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._current_task_id = None self.app._current_task_id = None
self.app.cancel_btn.config(state='disabled') self.app._enable_action_buttons()
def _on_diff_done(result): def _on_diff_done(result):
try: try:
@ -250,16 +272,18 @@ class ActionHandlers:
self.app.cancel_btn.config(state='normal') self.app.cancel_btn.config(state='normal')
except Exception: except Exception:
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app.cancel_btn.config(state='disabled')
self.app._current_task_id = None self.app._current_task_id = None
self.app._enable_action_buttons()
except Exception as e: except Exception as e:
messagebox.showerror('Differ Error', str(e)) messagebox.showerror('Differ Error', str(e))
self.app._enable_action_buttons()
# No baseline exists - create one # No baseline exists - create one
if not baselines: if not baselines:
create = messagebox.askyesno("Differing", "No baseline found for this project. Create baseline now?") create = messagebox.askyesno("Differing", "No baseline found for this project. Create baseline now?")
if not create: if not create:
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
self.app._set_phase("Creating baseline...") self.app._set_phase("Creating baseline...")
@ -277,6 +301,7 @@ class ActionHandlers:
chosen = self._select_baseline_dialog(baselines) chosen = self._select_baseline_dialog(baselines)
if not chosen: if not chosen:
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
try: try:
@ -285,6 +310,7 @@ class ActionHandlers:
except Exception as e: except Exception as e:
messagebox.showerror("Differing", f"Failed to load baseline metadata: {e}") messagebox.showerror("Differing", f"Failed to load baseline metadata: {e}")
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
# Setup baseline and current roots for diff viewer # Setup baseline and current roots for diff viewer
@ -301,6 +327,7 @@ class ActionHandlers:
except Exception: except Exception:
messagebox.showerror('Differing', 'Failed to scan current project files') messagebox.showerror('Differing', 'Failed to scan current project files')
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
self.app._set_phase("Building pairs...") self.app._set_phase("Building pairs...")
@ -311,11 +338,13 @@ class ActionHandlers:
except Exception: except Exception:
messagebox.showerror('Differing', 'Failed to build file pairs') messagebox.showerror('Differing', 'Failed to build file pairs')
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
if not pairs: if not pairs:
messagebox.showinfo("Differing", "No files to compare") messagebox.showinfo("Differing", "No files to compare")
self.app._set_phase('Idle') self.app._set_phase('Idle')
self.app._enable_action_buttons()
return return
# Process pairs in parallel # Process pairs in parallel

View File

@ -166,6 +166,9 @@ class App(tk.Tk):
# Worker manager (background task runner) # Worker manager (background task runner)
self.worker = WorkerManager() self.worker = WorkerManager()
# Track task names for logging
self._task_names = {}
# Initialize handlers (refactored to separate modules) # Initialize handlers (refactored to separate modules)
self.action_handlers = ActionHandlers(self) self.action_handlers = ActionHandlers(self)
self.progress_handlers = ProgressHandlers(self) self.progress_handlers = ProgressHandlers(self)
@ -182,6 +185,34 @@ class App(tk.Tk):
# poll the worker UI queue and dispatch callbacks in the main thread (50ms for better responsiveness) # poll the worker UI queue and dispatch callbacks in the main thread (50ms for better responsiveness)
self.after(50, self._poll_worker_ui_queue) self.after(50, self._poll_worker_ui_queue)
def _disable_action_buttons(self):
"""Disable all action buttons except Cancel when an operation is running."""
try:
self.scan_btn.config(state='disabled')
self.count_btn.config(state='disabled')
self.metrics_btn.config(state='disabled')
self.differ_btn.config(state='disabled')
self.export_btn.config(state='disabled')
self.cancel_btn.config(state='normal')
except Exception:
pass
def _enable_action_buttons(self):
"""Re-enable all action buttons when operation is complete."""
try:
self.scan_btn.config(state='normal')
self.count_btn.config(state='normal')
self.metrics_btn.config(state='normal')
self.differ_btn.config(state='normal')
# Export button state depends on whether we have results
if self.results_tree.get_children():
self.export_btn.config(state='normal')
else:
self.export_btn.config(state='disabled')
self.cancel_btn.config(state='disabled')
except Exception:
pass
def _set_results_columns(self, cols): def _set_results_columns(self, cols):
"""Reconfigure the shared results tree to use given columns. """Reconfigure the shared results tree to use given columns.
Cols is an iterable of (col_id, ...) where col_id are string keys. Cols is an iterable of (col_id, ...) where col_id are string keys.
@ -290,12 +321,8 @@ class App(tk.Tk):
except Exception: except Exception:
pass pass
self._current_task_id = None self._current_task_id = None
# reset phase to idle when finished
try:
self._set_phase("Idle") self._set_phase("Idle")
except Exception: self._enable_action_buttons()
pass
self.cancel_btn.config(state='disabled')
def _on_action_export(self): def _on_action_export(self):
"""Delegate export action to ExportHandler.""" """Delegate export action to ExportHandler."""
@ -352,14 +379,13 @@ class App(tk.Tk):
self.results_tree.insert('', 'end', values=(f.name, str(f))) self.results_tree.insert('', 'end', values=(f.name, str(f)))
except Exception: except Exception:
pass pass
self.export_btn.config(state='normal' if files else 'disabled')
self.cancel_btn.config(state='disabled')
self._current_task_id = None self._current_task_id = None
self._set_phase("Idle") self._set_phase("Idle")
self._enable_action_buttons()
except Exception as e: except Exception as e:
messagebox.showerror('Scan Error', str(e)) messagebox.showerror('Scan Error', str(e))
self.cancel_btn.config(state='disabled')
self._set_phase("Idle") self._set_phase("Idle")
self._enable_action_buttons()
def _on_count_progress(self, res): def _on_count_progress(self, res):
"""Delegate count progress to ProgressHandlers.""" """Delegate count progress to ProgressHandlers."""
@ -400,6 +426,8 @@ class App(tk.Tk):
typ, task_id, payload = msg typ, task_id, payload = msg
if typ == "started": if typ == "started":
name = payload.get("func") if isinstance(payload, dict) else str(payload) name = payload.get("func") if isinstance(payload, dict) else str(payload)
# Store task name for later use
self._task_names[task_id] = name
self.log(f"Task {task_id[:8]} started: {name}", level="INFO") self.log(f"Task {task_id[:8]} started: {name}", level="INFO")
elif typ == "progress": elif typ == "progress":
# payload is expected to be a partial result or status dictionary # payload is expected to be a partial result or status dictionary
@ -407,13 +435,22 @@ class App(tk.Tk):
# so we skip logging them to avoid clutter # so we skip logging them to avoid clutter
pass # Skip progress logging pass # Skip progress logging
elif typ == "done": elif typ == "done":
# payload may contain final results # Retrieve task name from stored mapping
self.log(f"Task {task_id[:8]} done. Result: {payload}", level="INFO") name = self._task_names.get(task_id, "unknown")
self.log(f"Task {task_id[:8]} {name} done.", level="INFO")
# Clean up task name from memory
self._task_names.pop(task_id, None)
elif typ == "error": elif typ == "error":
# payload is typically a traceback string or exception info # payload is typically a traceback string or exception info
self.log(f"Task {task_id[:8]} error: {payload}", level="ERROR") name = self._task_names.get(task_id, "unknown")
self.log(f"Task {task_id[:8]} {name} error: {payload}", level="ERROR")
# Clean up task name from memory
self._task_names.pop(task_id, None)
elif typ == "cancelled": elif typ == "cancelled":
self.log(f"Task {task_id[:8]} cancelled", level="WARNING") name = self._task_names.get(task_id, "unknown")
self.log(f"Task {task_id[:8]} {name} cancelled", level="WARNING")
# Clean up task name from memory
self._task_names.pop(task_id, None)
def on_closing(self): def on_closing(self):
"""Cleanup when closing the application.""" """Cleanup when closing the application."""

View File

@ -55,13 +55,12 @@ class ProgressHandlers:
# Flush remaining batch buffer # Flush remaining batch buffer
self._flush_count_batch() self._flush_count_batch()
self.app.export_btn.config(state='normal')
self.app.cancel_btn.config(state='disabled')
self.app._current_task_id = None self.app._current_task_id = None
try: try:
self.app._set_phase("Idle") self.app._set_phase("Idle")
except Exception: except Exception:
pass pass
self.app._enable_action_buttons()
def on_metrics_progress(self, res): def on_metrics_progress(self, res):
"""Handle progress for metrics analysis. """Handle progress for metrics analysis.
@ -98,13 +97,12 @@ class ProgressHandlers:
# Flush remaining batch buffer # Flush remaining batch buffer
self._flush_metrics_batch() self._flush_metrics_batch()
self.app.export_btn.config(state='normal')
self.app.cancel_btn.config(state='disabled')
self.app._current_task_id = None self.app._current_task_id = None
try: try:
self.app._set_phase("Idle") self.app._set_phase("Idle")
except Exception: except Exception:
pass pass
self.app._enable_action_buttons()
def _flush_count_batch(self): def _flush_count_batch(self):
"""Flush countings batch buffer to results tree.""" """Flush countings batch buffer to results tree."""