# GUI Feature Enhancement Plan **Overall Goal:** Modify the GUI (`gui/main_window.py`, `gui/prediction_handler.py`) to make the output path configurable, improve UI responsiveness during preview generation, and add a toggle to switch between detailed file preview and a simple input path list. **Detailed Plan:** 1. **Feature: Configurable Output Path** * **File:** `gui/main_window.py` * **Changes:** * **UI Addition:** * Below the `preset_combo` layout, add a new `QHBoxLayout`. * Inside this layout, add: * A `QLabel` with text "Output Directory:". * A `QLineEdit` (e.g., `self.output_path_edit`) to display/edit the path. Make it read-only initially if preferred, or editable. * A `QPushButton` (e.g., `self.browse_output_button`) with text "Browse...". * **Initialization (`__init__` or `setup_main_panel_ui`):** * Read the default `OUTPUT_BASE_DIR` from `core_config`. * Resolve this path relative to the project root (`project_root / output_base_dir_config`). * Set the initial text of `self.output_path_edit` to this resolved default path. * **Browse Button Logic:** * Connect the `clicked` signal of `self.browse_output_button` to a new method (e.g., `_browse_for_output_directory`). * Implement `_browse_for_output_directory`: * Use `QFileDialog.getExistingDirectory` to let the user select a folder. * If a directory is selected, update the text of `self.output_path_edit`. * **Processing Logic (`start_processing`):** * Instead of reading/resolving the path from `core_config`, get the path string directly from `self.output_path_edit.text()`. * Convert this string to a `Path` object. * **Add Validation:** Before passing the path to the handler, check if the directory exists. If not, attempt to create it using `output_dir.mkdir(parents=True, exist_ok=True)`. Handle potential `OSError` exceptions during creation and show an error message if it fails. Also, consider adding a basic writability check if possible. * Pass the validated `output_dir_str` to `self.processing_handler.run_processing`. 2. **Feature: Responsive UI (Address Prediction Bottleneck)** * **File:** `gui/prediction_handler.py` * **Changes:** * **Import:** Add `from concurrent.futures import ThreadPoolExecutor, as_completed`. * **Modify `run_prediction`:** * Inside the `try` block (after loading `config`), create a `ThreadPoolExecutor` (e.g., `with ThreadPoolExecutor(max_workers=...) as executor:`). Determine a reasonable `max_workers` count (e.g., `os.cpu_count() // 2` or a fixed number like 4 or 8). * Instead of iterating through `input_paths` sequentially, submit a task to the executor for each `input_path_str`. * The task submitted should be a helper method (e.g., `_predict_single_asset`) that takes `input_path_str` and the loaded `config` object as arguments. * `_predict_single_asset` will contain the logic currently inside the loop: instantiate `AssetProcessor`, call `get_detailed_file_predictions`, handle exceptions, and return the list of prediction dictionaries for that *single* asset (or an error dictionary). * Store the `Future` objects returned by `executor.submit`. * Use `as_completed(futures)` to process results as they become available. * Append the results from each completed future to the `all_file_results` list. * Emit `prediction_results_ready` once at the very end with the complete `all_file_results` list. * **File:** `gui/main_window.py` * **Changes:** * No changes needed in the `on_prediction_results_ready` slot itself, as the handler will still emit the full list at the end. 3. **Feature: Preview Toggle** * **File:** `gui/main_window.py` * **Changes:** * **UI Addition:** * Add a `QCheckBox` (e.g., `self.disable_preview_checkbox`) with text "Disable Detailed Preview". Place it logically, perhaps near the `overwrite_checkbox` or above the `preview_table`. Set its default state to unchecked. * **Modify `update_preview`:** * At the beginning of the method, check `self.disable_preview_checkbox.isChecked()`. * **If Checked (Simple View):** * Clear the `preview_table`. * Set simplified table headers (e.g., `self.preview_table.setColumnCount(1); self.preview_table.setHorizontalHeaderLabels(["Input Path"])`). Adjust column resize modes. * Iterate through `self.current_asset_paths`. For each path, add a row to the table containing just the path string. * Set status bar message (e.g., "Preview disabled. Showing input list."). * **Crucially:** `return` from the method here to prevent the `PredictionHandler` from being started. * **If Unchecked (Detailed View):** * Ensure the table headers and column count are set back to the detailed view configuration (Status, Original Path, Predicted Name, Details). * Continue with the rest of the existing `update_preview` logic to start the `PredictionHandler`. * **Connect Signal:** In `__init__` or `setup_main_panel_ui`, connect the `toggled` signal of `self.disable_preview_checkbox` to the `self.update_preview` slot. * **Initial State:** Ensure the first call to `update_preview` (if any) respects the initial unchecked state of the checkbox. **Mermaid Diagram:** ```mermaid graph TD subgraph MainWindow A[User Action: Add Asset / Change Preset / Toggle Preview] --> B{Update Preview Triggered}; B --> C{Is 'Disable Preview' Checked?}; C -- Yes --> D[Show Simple List View in Table]; C -- No --> E[Set Detailed Table Headers]; E --> F[Start PredictionHandler Thread]; F --> G[PredictionHandler Runs]; G --> H[Slot: Populate Table with Detailed Results]; I[User Clicks Start Processing] --> J{Get Output Path from UI LineEdit}; J --> K[Validate/Create Output Path]; K -- Path OK --> L[Start ProcessingHandler Thread]; K -- Path Error --> M[Show Error Message]; L --> N[ProcessingHandler Runs]; N --> O[Update UI (Progress, Status)]; P[User Clicks Browse...] --> Q[Show QFileDialog]; Q --> R[Update Output Path LineEdit]; end subgraph PredictionHandler [Background Thread] style PredictionHandler fill:#f9f,stroke:#333,stroke-width:2px F --> S{Use ThreadPoolExecutor}; S --> T[Run _predict_single_asset Concurrently]; T --> U[Collect Results]; U --> V[Emit prediction_results_ready (Full List)]; V --> H; end subgraph ProcessingHandler [Background Thread] style ProcessingHandler fill:#ccf,stroke:#333,stroke-width:2px L --> N; end