190 lines
6.4 KiB
Python
190 lines
6.4 KiB
Python
"""
|
|
Progress handlers for PyUCC GUI.
|
|
Handles progress callbacks with batch processing to avoid GUI blocking.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
class ProgressHandlers:
|
|
"""Handles progress callbacks for all analysis types with batch processing."""
|
|
|
|
BATCH_SIZE = 50 # Insert items in batches of 50 to reduce GUI blocking
|
|
UPDATE_FREQUENCY = 10 # Update progress UI every N files
|
|
|
|
def __init__(self, gui_app):
|
|
"""
|
|
Args:
|
|
gui_app: Reference to the main GUI application instance
|
|
"""
|
|
self.app = gui_app
|
|
self._count_batch_buffer = []
|
|
self._metrics_batch_buffer = []
|
|
|
|
def on_count_progress(self, res):
|
|
"""Handle progress for countings analysis.
|
|
|
|
Args:
|
|
res: Dictionary with file counting results
|
|
"""
|
|
try:
|
|
if not isinstance(res, dict):
|
|
return
|
|
|
|
file = res.get("file")
|
|
name = Path(file).name if file else ""
|
|
code = res.get("code_lines") or res.get("code") or 0
|
|
comment = res.get("comment_lines") or 0
|
|
blank = res.get("blank_lines") or 0
|
|
total = res.get("physical_lines") or 0
|
|
lang = res.get("language") or ""
|
|
|
|
# UCC extended metrics
|
|
cmt_whole = res.get("comment_whole") or 0
|
|
cmt_embed = res.get("comment_embedded") or 0
|
|
directive = res.get("compiler_directives") or 0
|
|
data_decl = res.get("data_declarations") or 0
|
|
exec_inst = res.get("exec_instructions") or 0
|
|
logical = res.get("logical_sloc") or 0
|
|
physical = res.get("physical_sloc") or 0
|
|
|
|
# Add to batch buffer with extended metrics
|
|
self._count_batch_buffer.append(
|
|
(
|
|
name,
|
|
file,
|
|
int(code),
|
|
int(comment),
|
|
int(blank),
|
|
int(total),
|
|
lang,
|
|
int(cmt_whole),
|
|
int(cmt_embed),
|
|
int(directive),
|
|
int(data_decl),
|
|
int(exec_inst),
|
|
int(logical),
|
|
int(physical),
|
|
)
|
|
)
|
|
|
|
# Insert batch when buffer is full
|
|
if len(self._count_batch_buffer) >= self.BATCH_SIZE:
|
|
self._flush_count_batch()
|
|
|
|
# Update progress less frequently
|
|
self._update_progress_counter()
|
|
except Exception:
|
|
pass
|
|
|
|
def on_count_done(self, results):
|
|
"""Handle completion of countings analysis."""
|
|
# Flush remaining batch buffer
|
|
self._flush_count_batch()
|
|
|
|
# Store results for report generation
|
|
self.app._results_cache = results if isinstance(results, list) else []
|
|
|
|
# Hide metrics toggle (not relevant for countings)
|
|
self.app.metrics_toggle_frame.grid_remove()
|
|
|
|
self.app._current_task_id = None
|
|
try:
|
|
self.app._set_phase("Idle")
|
|
except Exception:
|
|
pass
|
|
self.app._enable_action_buttons()
|
|
|
|
def on_metrics_progress(self, res):
|
|
"""Handle progress for metrics analysis.
|
|
|
|
Args:
|
|
res: Dictionary with file metrics results
|
|
"""
|
|
try:
|
|
if not isinstance(res, dict):
|
|
return
|
|
|
|
file = res.get("file")
|
|
name = Path(file).name if file else ""
|
|
avg_cc = res.get("avg_cc") or res.get("avg") or 0
|
|
func_count = res.get("func_count") or 0
|
|
mi = res.get("mi") or 0
|
|
|
|
# Calculate Total_CC (same as report)
|
|
total_cc = int(avg_cc * func_count) if func_count > 0 else 0
|
|
|
|
# Determine risk level (same logic as report)
|
|
if avg_cc <= 10:
|
|
risk = "Low"
|
|
elif avg_cc <= 20:
|
|
risk = "Medium"
|
|
elif avg_cc <= 50:
|
|
risk = "High"
|
|
else:
|
|
risk = "Very High"
|
|
|
|
# Add to batch buffer (matching new column structure)
|
|
self._metrics_batch_buffer.append(
|
|
(name, file, total_cc, f"{avg_cc:.2f}", risk, f"{mi:.2f}")
|
|
)
|
|
|
|
# Insert batch when buffer is full
|
|
if len(self._metrics_batch_buffer) >= self.BATCH_SIZE:
|
|
self._flush_metrics_batch()
|
|
|
|
# Update progress
|
|
self._update_progress_counter()
|
|
except Exception:
|
|
pass
|
|
|
|
def on_metrics_done(self, results):
|
|
"""Handle completion of metrics analysis."""
|
|
# Flush remaining batch buffer
|
|
self._flush_metrics_batch()
|
|
|
|
# Store results for report generation AND view switching
|
|
self.app._results_cache = results if isinstance(results, list) else []
|
|
self.app._metrics_results_cache = results if isinstance(results, list) else []
|
|
|
|
# Show metrics toggle
|
|
self.app.metrics_toggle_frame.grid()
|
|
|
|
self.app._current_task_id = None
|
|
try:
|
|
self.app._set_phase("Idle")
|
|
except Exception:
|
|
pass
|
|
self.app._enable_action_buttons()
|
|
|
|
def _flush_count_batch(self):
|
|
"""Flush countings batch buffer to results tree."""
|
|
if self._count_batch_buffer:
|
|
for row_values in self._count_batch_buffer:
|
|
self.app.results_tree.insert("", "end", values=row_values)
|
|
self._count_batch_buffer.clear()
|
|
|
|
def _flush_metrics_batch(self):
|
|
"""Flush metrics batch buffer to results tree."""
|
|
if self._metrics_batch_buffer:
|
|
for row_values in self._metrics_batch_buffer:
|
|
self.app.results_tree.insert("", "end", values=row_values)
|
|
self._metrics_batch_buffer.clear()
|
|
|
|
def _update_progress_counter(self):
|
|
"""Update progress counter and UI (with reduced frequency)."""
|
|
try:
|
|
self.app._processed_files = getattr(self.app, "_processed_files", 0) + 1
|
|
|
|
# Update UI only every N files or at completion
|
|
if (
|
|
self.app._processed_files % self.UPDATE_FREQUENCY == 0
|
|
or self.app._processed_files == self.app._total_files
|
|
):
|
|
self.app._lbl_files.config(
|
|
text=f"Files: {self.app._processed_files}/{self.app._total_files}"
|
|
)
|
|
self.app.progress["value"] = self.app._processed_files
|
|
except Exception:
|
|
pass
|