# GUI Preview Table Restructure Plan ## Objective Restructure the Graphical User Interface (GUI) preview table to group files by source asset and display "Ignored" and "Extra" files in a new "Additional Files" column, aligned with the mapped files of the same asset. ## Analysis Based on the review of `gui/prediction_handler.py` and `gui/preview_table_model.py`: * The `PredictionHandler` provides a flat list of file prediction dictionaries. * The `PreviewTableModel` currently stores and displays this flat list directly. * The `PreviewSortFilterProxyModel` sorts this flat list. * The data transformation to achieve the desired grouped layout must occur within the `PreviewTableModel`. ## Proposed Plan 1. **Modify `gui/preview_table_model.py`:** * **Add New Column:** * Define a new constant: `COL_ADDITIONAL_FILES = 5`. * Add "Additional Files" to the `_headers_detailed` list. * **Introduce New Internal Data Structure:** * Create a new internal list, `self._table_rows`, to store dictionaries representing the final rows to be displayed in the table. * **Update `set_data(self, data: list)`:** * Process the incoming flat `data` list (received from `PredictionHandler`). * Group file dictionaries by their `source_asset`. * Within each asset group, separate files into two lists: * `main_files`: Files with status "Mapped", "Model", or "Error". * `additional_files`: Files with status "Ignored", "Extra", "Unrecognised", or "Unmatched Extra". * Determine the maximum number of rows needed for this asset block: `max(len(main_files), len(additional_files))`. * Build the row dictionaries for `self._table_rows` for this asset block: * For `i` from 0 to `max_rows - 1`: * Get the `i`-th file from `main_files` (or `None` if `i` is out of bounds). * Get the `i`-th file from `additional_files` (or `None` if `i` is out of bounds). * Create a row dictionary containing: * `source_asset`: The asset name. * `predicted_asset`: From the `main_file` (if exists). * `details`: From the `main_file` (if exists). * `original_path`: From the `main_file` (if exists). * `additional_file_path`: Path from the `additional_file` (if exists). * `additional_file_details`: The original dictionary of the `additional_file` (if exists, for tooltips). * `is_main_row`: Boolean flag (True if this row corresponds to a file in `main_files`, False otherwise). * Append these row dictionaries to `self._table_rows`. * After processing all assets, call `self.beginResetModel()` and `self.endResetModel()`. * **Update `rowCount`:** Return `len(self._table_rows)` when in detailed mode. * **Update `columnCount`:** Return `len(self._headers_detailed)`. * **Update `data(self, index, role)`:** * Retrieve the row dictionary: `row_data = self._table_rows[index.row()]`. * For `Qt.ItemDataRole.DisplayRole`: * If `index.column()` is `COL_ADDITIONAL_FILES`, return `row_data.get('additional_file_path', '')`. * For other columns (`COL_STATUS`, `COL_PREDICTED_ASSET`, `COL_ORIGINAL_PATH`, `COL_DETAILS`), return data from the `main_file` part of `row_data` if `row_data['is_main_row']` is True, otherwise return an empty string or appropriate placeholder. * For `Qt.ItemDataRole.ToolTipRole`: * If `index.column()` is `COL_ADDITIONAL_FILES` and `row_data.get('additional_file_details')` exists, generate a tooltip using the status and details from `additional_file_details`. * For other columns, use the existing tooltip logic based on the `main_file` data. * For `Qt.ItemDataRole.ForegroundRole`: * Apply existing color-coding based on the status of the `main_file` if `row_data['is_main_row']` is True. * For the `COL_ADDITIONAL_FILES` cell and for rows where `row_data['is_main_row']` is False, use neutral styling (default text color). * **Update `headerData`:** Return the correct header for `COL_ADDITIONAL_FILES`. 2. **Modify `gui/preview_table_model.py` (`PreviewSortFilterProxyModel`):** * **Update `lessThan(self, left, right)`:** * Retrieve the row dictionaries for `left` and `right` indices from the source model (`model._table_rows[left.row()]`, etc.). * **Level 1: Source Asset:** Compare `source_asset` from the row dictionaries. * **Level 2: Row Type:** If assets are the same, compare `is_main_row` (True sorts before False). * **Level 3 (Main Rows):** If both are main rows (`is_main_row` is True), compare `original_path`. * **Level 4 (Additional-Only Rows):** If both are additional-only rows (`is_main_row` is False), compare `additional_file_path`. ## Clarifications & Decisions * **Error Handling:** "Error" files will remain in the main columns, similar to "Mapped" files, with their current "Error" status. * **Sorting within Asset:** The proposed sorting logic within an asset block is acceptable (mapped rows by original path, additional-only rows by additional file path). * **Styling of Additional Column:** Use neutral text and background styling for the "Additional Files" column, relying on tooltips for specific file details. ## Mermaid Diagram (Updated Data Flow) ```mermaid graph LR A[PredictionHandler] -- prediction_results_ready(flat_list) --> B(PreviewTableModel); subgraph PreviewTableModel C[set_data] -- Processes flat_list --> D{Internal Grouping & Transformation}; D -- Creates --> E[_table_rows (Structured List)]; F[data()] -- Reads from --> E; end B -- Provides data via data() --> G(QTableView via Proxy); style B fill:#f9f,stroke:#333,stroke-width:2px style C fill:#ccf,stroke:#333,stroke-width:1px style D fill:#lightgrey,stroke:#333,stroke-width:1px style E fill:#ccf,stroke:#333,stroke-width:1px style F fill:#ccf,stroke:#333,stroke-width:1px