""" 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