{
    "sourceFile": "gui/preview_table_model.py",
    "activeCommit": 0,
    "commits": [
        {
            "activePatchIndex": 22,
            "patches": [
                {
                    "date": 1745323013820,
                    "content": "Index: \n===================================================================\n--- \n+++ \n"
                },
                {
                    "date": 1745324033031,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -54,10 +54,33 @@\n \r\n         # --- Handle Display Role ---\r\n         if role == Qt.ItemDataRole.DisplayRole:\r\n             if col == self.COL_STATUS:\r\n-                # TODO: Implement status text simplification here later\r\n-                return file_details.get('status', '[No Status]')\r\n+                raw_status = file_details.get('status', '[No Status]')\r\n+                details = file_details.get('details', '') # Get details for parsing\r\n+\r\n+                # Implement status text simplification\r\n+                if raw_status == \"Unmatched Extra\":\r\n+                    # Check details for regex match info\r\n+                    if details and details.startswith(\"[Unmatched Extra (Regex match:\"):\r\n+                        try:\r\n+                            pattern = details.split(\"match: '\")[1].split(\"'\")[0]\r\n+                            return f\"[Extra={pattern}]\"\r\n+                        except IndexError:\r\n+                            return \"Extra\" # Fallback if parsing fails\r\n+                    else:\r\n+                        return \"Extra\"\r\n+                elif raw_status == \"Ignored\" and details and \"Superseed by 16bit variant for\" in details:\r\n+                     try:\r\n+                         # Extract filename after \"for \"\r\n+                         filename = details.split(\"Superseed by 16bit variant for \")[1]\r\n+                         return f\"Superseeded by 16bit {filename}\"\r\n+                     except IndexError:\r\n+                         return raw_status # Fallback if parsing fails\r\n+                # Add other specific simplifications here if needed\r\n+                else:\r\n+                    return raw_status # Return original status if no simplification applies\r\n+\r\n             elif col == self.COL_PREDICTED_ASSET:\r\n                 return file_details.get('predicted_asset_name', 'N/A')\r\n             elif col == self.COL_ORIGINAL_PATH:\r\n                 return file_details.get('original_path', '[Missing Path]')\r\n"
                },
                {
                    "date": 1745324053209,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -152,11 +152,20 @@\n     \"\"\"\r\n     Custom proxy model for sorting the preview table.\r\n     Implements multi-level sorting and custom status order.\r\n     \"\"\"\r\n-    # Define the desired status order for sorting\r\n-    # Error > Mapped > Model > Ignored > Extra\r\n-    STATUS_ORDER = [\"Error\", \"Mapped\", \"Model\", \"Ignored\", \"Extra\", \"Unrecognised\", \"Unmatched Extra\", \"[No Status]\"] # Include others for completeness\r\n+    # Define the desired status priority for sorting\r\n+    # Lower numbers sort first. Mapped/Model have same priority.\r\n+    STATUS_PRIORITY = {\r\n+        \"Error\": 0,\r\n+        \"Mapped\": 1,\r\n+        \"Model\": 1,\r\n+        \"Ignored\": 2,\r\n+        \"Extra\": 3,\r\n+        \"Unrecognised\": 3, # Treat as Extra\r\n+        \"Unmatched Extra\": 3, # Treat as Extra\r\n+        \"[No Status]\": 99 # Lowest priority\r\n+    }\r\n \r\n     def __init__(self, parent=None):\r\n         super().__init__(parent)\r\n         # Set default sort column and order (Status column, Ascending)\r\n@@ -185,20 +194,20 @@\n             if not left_asset: return True # Empty asset comes first\r\n             if not right_asset: return False # Non-empty asset comes first\r\n             return left_asset < right_asset # Alphabetical sort for assets\r\n \r\n-        # --- Level 2: Sort by Status (Custom Order) ---\r\n+        # --- Level 2: Sort by Status (Custom Priority) ---\r\n         left_status = model.data(left.siblingAtColumn(model.COL_STATUS), model.ROLE_RAW_STATUS)\r\n         right_status = model.data(right.siblingAtColumn(model.COL_STATUS), model.ROLE_RAW_STATUS)\r\n \r\n-        # Get the index of the status in the defined order\r\n-        left_status_index = self.STATUS_ORDER.index(left_status) if left_status in self.STATUS_ORDER else len(self.STATUS_ORDER)\r\n-        right_status_index = self.STATUS_ORDER.index(right_status) if right_status in self.STATUS_ORDER else len(self.STATUS_ORDER)\r\n+        # Get the priority from the dictionary (default to low priority if status not found)\r\n+        left_prio = self.STATUS_PRIORITY.get(left_status, 99)\r\n+        right_prio = self.STATUS_PRIORITY.get(right_status, 99)\r\n \r\n-        if left_status_index != right_status_index:\r\n-            return left_status_index < right_status_index # Sort based on custom order index\r\n+        if left_prio != right_prio:\r\n+            return left_prio < right_prio # Sort based on priority\r\n \r\n-        # --- Level 3: Sort by Original Path (Alphabetical) ---\r\n+        # --- Level 3: Sort by Original Path (Alphabetical, only if assets and status priorities are equal) ---\r\n         left_path = model.data(left.siblingAtColumn(model.COL_ORIGINAL_PATH), Qt.ItemDataRole.DisplayRole)\r\n         right_path = model.data(right.siblingAtColumn(model.COL_ORIGINAL_PATH), Qt.ItemDataRole.DisplayRole)\r\n \r\n         # Handle None/empty strings\r\n"
                },
                {
                    "date": 1745332248186,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -3,48 +3,76 @@\n \r\n class PreviewTableModel(QAbstractTableModel):\r\n     \"\"\"\r\n     Custom table model for the GUI preview table.\r\n-    Holds detailed file prediction results.\r\n+    Holds detailed file prediction results or a simple list of source assets.\r\n     \"\"\"\r\n-    # Define column roles for clarity\r\n+    # Define column roles for clarity (Detailed Mode)\r\n     COL_STATUS = 0\r\n     COL_PREDICTED_ASSET = 1\r\n     COL_ORIGINAL_PATH = 2\r\n-    COL_PREDICTED_OUTPUT = 3\r\n+    COL_PREDICTED_OUTPUT = 3 # Kept for internal data access, but hidden in view\r\n     COL_DETAILS = 4\r\n \r\n     # Define internal data roles for sorting/filtering\r\n     ROLE_RAW_STATUS = Qt.ItemDataRole.UserRole + 1\r\n     ROLE_SOURCE_ASSET = Qt.ItemDataRole.UserRole + 2\r\n \r\n+    # Column for Simple Mode\r\n+    COL_SIMPLE_PATH = 0\r\n+\r\n     def __init__(self, data=None, parent=None):\r\n         super().__init__(parent)\r\n         # Data format: List of dictionaries, each representing a file's details\r\n         # Example: {'original_path': '...', 'predicted_asset_name': '...', 'predicted_output_name': '...', 'status': '...', 'details': '...', 'source_asset': '...'}\r\n-        self._data = data or []\r\n-        # Initial columns - will be adjusted later\r\n-        self._headers = [\"Status\", \"Predicted Asset\", \"Original Path\", \"Predicted Output\", \"Details\"]\r\n+        self._data = []\r\n+        self._simple_data = [] # List of unique source asset paths for simple mode\r\n+        self._simple_mode = False # Flag to toggle between detailed and simple view\r\n+        self._headers_detailed = [\"Status\", \"Predicted Asset\", \"Original Path\", \"Predicted Output\", \"Details\"]\r\n+        self._headers_simple = [\"Input Path\"]\r\n+        self.set_data(data or []) # Initialize data and simple_data\r\n \r\n+    def set_simple_mode(self, enabled: bool):\r\n+        \"\"\"Toggles the model between detailed and simple view modes.\"\"\"\r\n+        if self._simple_mode != enabled:\r\n+            self.beginResetModel()\r\n+            self._simple_mode = enabled\r\n+            self.endResetModel()\r\n+\r\n     def rowCount(self, parent=QModelIndex()):\r\n         \"\"\"Returns the number of rows in the model.\"\"\"\r\n         if parent.isValid():\r\n             return 0\r\n-        return len(self._data)\r\n+        return len(self._simple_data) if self._simple_mode else len(self._data)\r\n \r\n     def columnCount(self, parent=QModelIndex()):\r\n         \"\"\"Returns the number of columns in the model.\"\"\"\r\n         if parent.isValid():\r\n             return 0\r\n-        return len(self._headers)\r\n+        return len(self._headers_simple) if self._simple_mode else len(self._headers_detailed)\r\n \r\n     def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):\r\n         \"\"\"Returns the data for a given index and role.\"\"\"\r\n         if not index.isValid():\r\n             return None\r\n \r\n         row = index.row()\r\n         col = index.column()\r\n+\r\n+        # --- Simple Mode ---\r\n+        if self._simple_mode:\r\n+            if row >= len(self._simple_data): return None # Bounds check\r\n+            source_asset_path = self._simple_data[row]\r\n+            if role == Qt.ItemDataRole.DisplayRole:\r\n+                if col == self.COL_SIMPLE_PATH:\r\n+                    return source_asset_path\r\n+            elif role == Qt.ItemDataRole.ToolTipRole:\r\n+                 if col == self.COL_SIMPLE_PATH:\r\n+                     return f\"Input Asset: {source_asset_path}\"\r\n+            return None\r\n+\r\n+        # --- Detailed Mode ---\r\n+        if row >= len(self._data): return None # Bounds check\r\n         file_details = self._data[row]\r\n \r\n         # --- Handle Custom Internal Roles ---\r\n         if role == self.ROLE_RAW_STATUS:\r\n@@ -132,16 +160,24 @@\n \r\n     def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole):\r\n         \"\"\"Returns the header data for a given section, orientation, and role.\"\"\"\r\n         if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:\r\n-            if 0 <= section < len(self._headers):\r\n-                return self._headers[section]\r\n+            headers = self._headers_simple if self._simple_mode else self._headers_detailed\r\n+            if 0 <= section < len(headers):\r\n+                return headers[section]\r\n         return None\r\n \r\n     def set_data(self, data: list):\r\n-        \"\"\"Sets the model's data and emits signals to update views.\"\"\"\r\n+        \"\"\"Sets the model's data, extracts simple data, and emits signals.\"\"\"\r\n         self.beginResetModel()\r\n-        self._data = data\r\n+        self._data = data or []\r\n+        # Extract unique source asset paths for simple mode\r\n+        unique_sources = set()\r\n+        for item in self._data:\r\n+            source = item.get('source_asset')\r\n+            if source:\r\n+                unique_sources.add(source)\r\n+        self._simple_data = sorted(list(unique_sources))\r\n         self.endResetModel()\r\n \r\n     def clear_data(self):\r\n         \"\"\"Clears the model's data.\"\"\"\r\n"
                },
                {
                    "date": 1745332438063,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,7 +1,10 @@\n+import logging # Import logging\r\n from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex, QSortFilterProxyModel\r\n from PySide6.QtGui import QColor\r\n \r\n+log = logging.getLogger(__name__) # Get logger\r\n+\r\n class PreviewTableModel(QAbstractTableModel):\r\n     \"\"\"\r\n     Custom table model for the GUI preview table.\r\n     Holds detailed file prediction results or a simple list of source assets.\r\n@@ -21,8 +24,9 @@\n     COL_SIMPLE_PATH = 0\r\n \r\n     def __init__(self, data=None, parent=None):\r\n         super().__init__(parent)\r\n+        log.debug(\"PreviewTableModel initialized.\")\r\n         # Data format: List of dictionaries, each representing a file's details\r\n         # Example: {'original_path': '...', 'predicted_asset_name': '...', 'predicted_output_name': '...', 'status': '...', 'details': '...', 'source_asset': '...'}\r\n         self._data = []\r\n         self._simple_data = [] # List of unique source asset paths for simple mode\r\n@@ -32,24 +36,33 @@\n         self.set_data(data or []) # Initialize data and simple_data\r\n \r\n     def set_simple_mode(self, enabled: bool):\r\n         \"\"\"Toggles the model between detailed and simple view modes.\"\"\"\r\n+        log.debug(f\"PreviewTableModel.set_simple_mode called with enabled={enabled}. Current mode: {self._simple_mode}\")\r\n         if self._simple_mode != enabled:\r\n             self.beginResetModel()\r\n             self._simple_mode = enabled\r\n+            log.debug(f\"PreviewTableModel mode changed to: {self._simple_mode}\")\r\n             self.endResetModel()\r\n+        else:\r\n+            log.debug(\"PreviewTableModel mode is already as requested. No change.\")\r\n \r\n+\r\n     def rowCount(self, parent=QModelIndex()):\r\n         \"\"\"Returns the number of rows in the model.\"\"\"\r\n         if parent.isValid():\r\n             return 0\r\n-        return len(self._simple_data) if self._simple_mode else len(self._data)\r\n+        row_count = len(self._simple_data) if self._simple_mode else len(self._data)\r\n+        # log.debug(f\"PreviewTableModel.rowCount called. Mode: {self._simple_mode}, Row Count: {row_count}\")\r\n+        return row_count\r\n \r\n     def columnCount(self, parent=QModelIndex()):\r\n         \"\"\"Returns the number of columns in the model.\"\"\"\r\n         if parent.isValid():\r\n             return 0\r\n-        return len(self._headers_simple) if self._simple_mode else len(self._headers_detailed)\r\n+        col_count = len(self._headers_simple) if self._simple_mode else len(self._headers_detailed)\r\n+        # log.debug(f\"PreviewTableModel.columnCount called. Mode: {self._simple_mode}, Column Count: {col_count}\")\r\n+        return col_count\r\n \r\n     def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):\r\n         \"\"\"Returns the data for a given index and role.\"\"\"\r\n         if not index.isValid():\r\n@@ -59,9 +72,11 @@\n         col = index.column()\r\n \r\n         # --- Simple Mode ---\r\n         if self._simple_mode:\r\n-            if row >= len(self._simple_data): return None # Bounds check\r\n+            if row >= len(self._simple_data):\r\n+                # log.warning(f\"data called with out of bounds row in simple mode: {row}/{len(self._simple_data)}\")\r\n+                return None # Bounds check\r\n             source_asset_path = self._simple_data[row]\r\n             if role == Qt.ItemDataRole.DisplayRole:\r\n                 if col == self.COL_SIMPLE_PATH:\r\n                     return source_asset_path\r\n@@ -70,9 +85,11 @@\n                      return f\"Input Asset: {source_asset_path}\"\r\n             return None\r\n \r\n         # --- Detailed Mode ---\r\n-        if row >= len(self._data): return None # Bounds check\r\n+        if row >= len(self._data):\r\n+            # log.warning(f\"data called with out of bounds row in detailed mode: {row}/{len(self._data)}\")\r\n+            return None # Bounds check\r\n         file_details = self._data[row]\r\n \r\n         # --- Handle Custom Internal Roles ---\r\n         if role == self.ROLE_RAW_STATUS:\r\n@@ -167,21 +184,31 @@\n         return None\r\n \r\n     def set_data(self, data: list):\r\n         \"\"\"Sets the model's data, extracts simple data, and emits signals.\"\"\"\r\n+        log.debug(f\"PreviewTableModel.set_data called with {len(data)} items.\")\r\n         self.beginResetModel()\r\n         self._data = data or []\r\n         # Extract unique source asset paths for simple mode\r\n         unique_sources = set()\r\n-        for item in self._data:\r\n-            source = item.get('source_asset')\r\n-            if source:\r\n-                unique_sources.add(source)\r\n-        self._simple_data = sorted(list(unique_sources))\r\n+        # Check if data is a list of strings (simple paths) or list of dicts (detailed)\r\n+        if data and isinstance(data[0], str):\r\n+             log.debug(\"set_data received list of strings (simple paths).\")\r\n+             self._simple_data = sorted(list(set(data))) # Ensure uniqueness and sort\r\n+        else:\r\n+            log.debug(\"set_data received list of dicts (detailed data). Extracting simple paths.\")\r\n+            for item in self._data:\r\n+                source = item.get('source_asset')\r\n+                if source:\r\n+                    unique_sources.add(source)\r\n+            self._simple_data = sorted(list(unique_sources))\r\n+\r\n+        log.debug(f\"Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n         self.endResetModel()\r\n \r\n     def clear_data(self):\r\n         \"\"\"Clears the model's data.\"\"\"\r\n+        log.debug(\"PreviewTableModel.clear_data called.\")\r\n         self.set_data([])\r\n \r\n \r\n class PreviewSortFilterProxyModel(QSortFilterProxyModel):\r\n@@ -203,8 +230,9 @@\n     }\r\n \r\n     def __init__(self, parent=None):\r\n         super().__init__(parent)\r\n+        log.debug(\"PreviewSortFilterProxyModel initialized.\")\r\n         # Set default sort column and order (Status column, Ascending)\r\n         # This will be overridden by the custom lessThan logic\r\n         self.setSortRole(PreviewTableModel.ROLE_RAW_STATUS) # Sort using the raw status role\r\n         self.sort(PreviewTableModel.COL_STATUS, Qt.SortOrder.AscendingOrder) # Apply initial sort\r\n@@ -218,10 +246,23 @@\n         3. Original Path (Ascending)\r\n         \"\"\"\r\n         model = self.sourceModel()\r\n         if not model:\r\n+            # log.debug(\"ProxyModel.lessThan: No source model.\")\r\n             return super().lessThan(left, right) # Fallback if no source model\r\n \r\n+        # If in simple mode, sort by the simple path column\r\n+        if isinstance(model, PreviewTableModel) and model._simple_mode:\r\n+             left_path = model.data(left.siblingAtColumn(model.COL_SIMPLE_PATH), Qt.ItemDataRole.DisplayRole)\r\n+             right_path = model.data(right.siblingAtColumn(model.COL_SIMPLE_PATH), Qt.ItemDataRole.DisplayRole)\r\n+             # log.debug(f\"ProxyModel.lessThan (Simple Mode): Comparing '{left_path}' < '{right_path}'\")\r\n+             if not left_path: return True\r\n+             if not right_path: return False\r\n+             return left_path < right_path\r\n+\r\n+\r\n+        # --- Detailed Mode Sorting ---\r\n+        # log.debug(\"ProxyModel.lessThan (Detailed Mode).\")\r\n         # --- Level 1: Sort by Source Asset ---\r\n         left_asset = model.data(left.siblingAtColumn(model.COL_PREDICTED_ASSET), model.ROLE_SOURCE_ASSET)\r\n         right_asset = model.data(right.siblingAtColumn(model.COL_PREDICTED_ASSET), model.ROLE_SOURCE_ASSET)\r\n \r\n@@ -257,5 +298,6 @@\n         # We ignore the column and order here and rely on lessThan for multi-level sort\r\n         # However, calling this method is necessary to trigger the proxy model's sorting mechanism.\r\n         # We can potentially use the column/order to toggle ascending/descending within each level in lessThan,\r\n         # but for now, we'll stick to the defined order.\r\n+        log.debug(f\"ProxyModel.sort called with column {column}, order {order}. Triggering lessThan.\")\r\n         super().sort(column, order) # Call base class sort to trigger update\n\\ No newline at end of file\n"
                },
                {
                    "date": 1745332986402,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -36,16 +36,21 @@\n         self.set_data(data or []) # Initialize data and simple_data\r\n \r\n     def set_simple_mode(self, enabled: bool):\r\n         \"\"\"Toggles the model between detailed and simple view modes.\"\"\"\r\n-        log.debug(f\"PreviewTableModel.set_simple_mode called with enabled={enabled}. Current mode: {self._simple_mode}\")\r\n+        thread_id = QThread.currentThreadId() # Get current thread ID\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_simple_mode(enabled={enabled}). Current mode: {self._simple_mode}\")\r\n         if self._simple_mode != enabled:\r\n+            log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n             self.beginResetModel()\r\n+            log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from beginResetModel(). Setting mode.\")\r\n             self._simple_mode = enabled\r\n-            log.debug(f\"PreviewTableModel mode changed to: {self._simple_mode}\")\r\n+            log.info(f\"[{time.time():.4f}][T:{thread_id}]     Mode changed to: {self._simple_mode}. Calling endResetModel()...\")\r\n             self.endResetModel()\r\n+            log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from endResetModel().\")\r\n         else:\r\n-            log.debug(\"PreviewTableModel mode is already as requested. No change.\")\r\n+            log.info(f\"[{time.time():.4f}][T:{thread_id}]     PreviewTableModel mode is already as requested. No change.\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}] <-- Exiting PreviewTableModel.set_simple_mode.\")\r\n \r\n \r\n     def rowCount(self, parent=QModelIndex()):\r\n         \"\"\"Returns the number of rows in the model.\"\"\"\r\n@@ -184,10 +189,13 @@\n         return None\r\n \r\n     def set_data(self, data: list):\r\n         \"\"\"Sets the model's data, extracts simple data, and emits signals.\"\"\"\r\n-        log.debug(f\"PreviewTableModel.set_data called with {len(data)} items.\")\r\n+        thread_id = QThread.currentThreadId() # Get current thread ID\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_data. Received {len(data)} items.\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n         self.beginResetModel()\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from beginResetModel(). Processing data...\")\r\n         self._data = data or []\r\n         # Extract unique source asset paths for simple mode\r\n         unique_sources = set()\r\n         # Check if data is a list of strings (simple paths) or list of dicts (detailed)\r\n@@ -201,14 +209,18 @@\n                 if source:\r\n                     unique_sources.add(source)\r\n             self._simple_data = sorted(list(unique_sources))\r\n \r\n-        log.debug(f\"Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling endResetModel()...\")\r\n         self.endResetModel()\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from endResetModel().\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}] <-- Exiting PreviewTableModel.set_data.\")\r\n \r\n     def clear_data(self):\r\n         \"\"\"Clears the model's data.\"\"\"\r\n-        log.debug(\"PreviewTableModel.clear_data called.\")\r\n+        thread_id = QThread.currentThreadId() # Get current thread ID\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}] PreviewTableModel.clear_data called.\")\r\n         self.set_data([])\r\n \r\n \r\n class PreviewSortFilterProxyModel(QSortFilterProxyModel):\r\n"
                },
                {
                    "date": 1745333096956,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,6 +1,7 @@\n import logging # Import logging\r\n-from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex, QSortFilterProxyModel\r\n+import time # For logging timestamps\r\n+from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex, QSortFilterProxyModel, QThread # Import QThread\r\n from PySide6.QtGui import QColor\r\n \r\n log = logging.getLogger(__name__) # Get logger\r\n \r\n"
                },
                {
                    "date": 1745333182396,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -190,8 +190,9 @@\n         return None\r\n \r\n     def set_data(self, data: list):\r\n         \"\"\"Sets the model's data, extracts simple data, and emits signals.\"\"\"\r\n+        from PySide6.QtCore import QThread # <<< TEMPORARY DIAGNOSTIC IMPORT >>>\r\n         thread_id = QThread.currentThreadId() # Get current thread ID\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_data. Received {len(data)} items.\")\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n         self.beginResetModel()\r\n"
                },
                {
                    "date": 1745333288777,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -190,10 +190,10 @@\n         return None\r\n \r\n     def set_data(self, data: list):\r\n         \"\"\"Sets the model's data, extracts simple data, and emits signals.\"\"\"\r\n-        from PySide6.QtCore import QThread # <<< TEMPORARY DIAGNOSTIC IMPORT >>>\r\n-        thread_id = QThread.currentThreadId() # Get current thread ID\r\n+        # Removed diagnostic import here\r\n+        thread_id = self.thread().currentThreadId() if self.thread() else 'N/A' # Get thread ID via instance\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_data. Received {len(data)} items.\")\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n         self.beginResetModel()\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from beginResetModel(). Processing data...\")\r\n"
                },
                {
                    "date": 1745333297842,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -37,9 +37,9 @@\n         self.set_data(data or []) # Initialize data and simple_data\r\n \r\n     def set_simple_mode(self, enabled: bool):\r\n         \"\"\"Toggles the model between detailed and simple view modes.\"\"\"\r\n-        thread_id = QThread.currentThreadId() # Get current thread ID\r\n+        thread_id = self.thread().currentThreadId() if self.thread() else 'N/A' # Get thread ID via instance\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_simple_mode(enabled={enabled}). Current mode: {self._simple_mode}\")\r\n         if self._simple_mode != enabled:\r\n             log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n             self.beginResetModel()\r\n"
                },
                {
                    "date": 1745333343578,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -219,9 +219,9 @@\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] <-- Exiting PreviewTableModel.set_data.\")\r\n \r\n     def clear_data(self):\r\n         \"\"\"Clears the model's data.\"\"\"\r\n-        thread_id = QThread.currentThreadId() # Get current thread ID\r\n+        thread_id = QThread.currentThread() # Get current thread object\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] PreviewTableModel.clear_data called.\")\r\n         self.set_data([])\r\n \r\n \r\n"
                },
                {
                    "date": 1745333360189,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -37,9 +37,9 @@\n         self.set_data(data or []) # Initialize data and simple_data\r\n \r\n     def set_simple_mode(self, enabled: bool):\r\n         \"\"\"Toggles the model between detailed and simple view modes.\"\"\"\r\n-        thread_id = self.thread().currentThreadId() if self.thread() else 'N/A' # Get thread ID via instance\r\n+        thread_id = QThread.currentThread() # Get current thread object\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_simple_mode(enabled={enabled}). Current mode: {self._simple_mode}\")\r\n         if self._simple_mode != enabled:\r\n             log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n             self.beginResetModel()\r\n"
                },
                {
                    "date": 1745333368717,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -191,9 +191,9 @@\n \r\n     def set_data(self, data: list):\r\n         \"\"\"Sets the model's data, extracts simple data, and emits signals.\"\"\"\r\n         # Removed diagnostic import here\r\n-        thread_id = self.thread().currentThreadId() if self.thread() else 'N/A' # Get thread ID via instance\r\n+        thread_id = QThread.currentThread() # Get current thread object\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_data. Received {len(data)} items.\")\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n         self.beginResetModel()\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from beginResetModel(). Processing data...\")\r\n"
                },
                {
                    "date": 1745497377758,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -15,8 +15,9 @@\n     COL_PREDICTED_ASSET = 1\r\n     COL_ORIGINAL_PATH = 2\r\n     COL_PREDICTED_OUTPUT = 3 # Kept for internal data access, but hidden in view\r\n     COL_DETAILS = 4\r\n+    COL_ADDITIONAL_FILES = 5 # New column for ignored/extra files\r\n \r\n     # Define internal data roles for sorting/filtering\r\n     ROLE_RAW_STATUS = Qt.ItemDataRole.UserRole + 1\r\n     ROLE_SOURCE_ASSET = Qt.ItemDataRole.UserRole + 2\r\n@@ -28,12 +29,13 @@\n         super().__init__(parent)\r\n         log.debug(\"PreviewTableModel initialized.\")\r\n         # Data format: List of dictionaries, each representing a file's details\r\n         # Example: {'original_path': '...', 'predicted_asset_name': '...', 'predicted_output_name': '...', 'status': '...', 'details': '...', 'source_asset': '...'}\r\n-        self._data = []\r\n+        self._data = [] # Keep the original flat data for reference if needed, but not for display\r\n+        self._table_rows = [] # New structure for displaying rows\r\n         self._simple_data = [] # List of unique source asset paths for simple mode\r\n         self._simple_mode = False # Flag to toggle between detailed and simple view\r\n-        self._headers_detailed = [\"Status\", \"Predicted Asset\", \"Original Path\", \"Predicted Output\", \"Details\"]\r\n+        self._headers_detailed = [\"Status\", \"Predicted Asset\", \"Original Path\", \"Predicted Output\", \"Details\", \"Additional Files\"] # Added new column header\r\n         self._headers_simple = [\"Input Path\"]\r\n         self.set_data(data or []) # Initialize data and simple_data\r\n \r\n     def set_simple_mode(self, enabled: bool):\r\n@@ -56,17 +58,17 @@\n     def rowCount(self, parent=QModelIndex()):\r\n         \"\"\"Returns the number of rows in the model.\"\"\"\r\n         if parent.isValid():\r\n             return 0\r\n-        row_count = len(self._simple_data) if self._simple_mode else len(self._data)\r\n+        row_count = len(self._simple_data) if self._simple_mode else len(self._table_rows) # Use _table_rows for detailed mode\r\n         # log.debug(f\"PreviewTableModel.rowCount called. Mode: {self._simple_mode}, Row Count: {row_count}\")\r\n         return row_count\r\n \r\n     def columnCount(self, parent=QModelIndex()):\r\n         \"\"\"Returns the number of columns in the model.\"\"\"\r\n         if parent.isValid():\r\n             return 0\r\n-        col_count = len(self._headers_simple) if self._simple_mode else len(self._headers_detailed)\r\n+        col_count = len(self._headers_simple) if self._simple_mode else len(self._headers_detailed) # Use updated headers_detailed\r\n         # log.debug(f\"PreviewTableModel.columnCount called. Mode: {self._simple_mode}, Column Count: {col_count}\")\r\n         return col_count\r\n \r\n     def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):\r\n@@ -91,88 +93,130 @@\n                      return f\"Input Asset: {source_asset_path}\"\r\n             return None\r\n \r\n         # --- Detailed Mode ---\r\n-        if row >= len(self._data):\r\n-            # log.warning(f\"data called with out of bounds row in detailed mode: {row}/{len(self._data)}\")\r\n+        if row >= len(self._table_rows): # Use _table_rows\r\n+            # log.warning(f\"data called with out of bounds row in detailed mode: {row}/{len(self._table_rows)}\")\r\n             return None # Bounds check\r\n-        file_details = self._data[row]\r\n+        row_data = self._table_rows[row] # Get data from the structured row\r\n \r\n         # --- Handle Custom Internal Roles ---\r\n+        # These roles are now handled by the proxy model based on the structured data\r\n         if role == self.ROLE_RAW_STATUS:\r\n-            return file_details.get('status', '[No Status]')\r\n+             # Return status of the main file if it exists, otherwise a placeholder for additional rows\r\n+             main_file = row_data.get('main_file')\r\n+             return main_file.get('status', '[No Status]') if main_file else '[Additional]'\r\n         if role == self.ROLE_SOURCE_ASSET:\r\n-            return file_details.get('source_asset', 'N/A')\r\n+            return row_data.get('source_asset', 'N/A')\r\n \r\n         # --- Handle Display Role ---\r\n         if role == Qt.ItemDataRole.DisplayRole:\r\n             if col == self.COL_STATUS:\r\n-                raw_status = file_details.get('status', '[No Status]')\r\n-                details = file_details.get('details', '') # Get details for parsing\r\n+                main_file = row_data.get('main_file')\r\n+                if main_file:\r\n+                    raw_status = main_file.get('status', '[No Status]')\r\n+                    details = main_file.get('details', '') # Get details for parsing\r\n \r\n-                # Implement status text simplification\r\n-                if raw_status == \"Unmatched Extra\":\r\n-                    # Check details for regex match info\r\n-                    if details and details.startswith(\"[Unmatched Extra (Regex match:\"):\r\n-                        try:\r\n-                            pattern = details.split(\"match: '\")[1].split(\"'\")[0]\r\n-                            return f\"[Extra={pattern}]\"\r\n-                        except IndexError:\r\n-                            return \"Extra\" # Fallback if parsing fails\r\n+                    # Implement status text simplification\r\n+                    if raw_status == \"Unmatched Extra\":\r\n+                        if details and details.startswith(\"[Unmatched Extra (Regex match:\"):\r\n+                            try:\r\n+                                pattern = details.split(\"match: '\")[1].split(\"'\")[0]\r\n+                                return f\"[Extra={pattern}]\"\r\n+                            except IndexError:\r\n+                                return \"Extra\" # Fallback if parsing fails\r\n+                        else:\r\n+                            return \"Extra\"\r\n+                    elif raw_status == \"Ignored\" and details and \"Superseed by 16bit variant for\" in details:\r\n+                         try:\r\n+                             filename = details.split(\"Superseed by 16bit variant for \")[1]\r\n+                             return f\"Superseeded by 16bit {filename}\"\r\n+                         except IndexError:\r\n+                             return raw_status # Fallback if parsing fails\r\n                     else:\r\n-                        return \"Extra\"\r\n-                elif raw_status == \"Ignored\" and details and \"Superseed by 16bit variant for\" in details:\r\n-                     try:\r\n-                         # Extract filename after \"for \"\r\n-                         filename = details.split(\"Superseed by 16bit variant for \")[1]\r\n-                         return f\"Superseeded by 16bit {filename}\"\r\n-                     except IndexError:\r\n-                         return raw_status # Fallback if parsing fails\r\n-                # Add other specific simplifications here if needed\r\n+                        return raw_status # Return original status if no simplification applies\r\n                 else:\r\n-                    return raw_status # Return original status if no simplification applies\r\n+                    return \"\" # Empty for additional-only rows\r\n \r\n             elif col == self.COL_PREDICTED_ASSET:\r\n-                return file_details.get('predicted_asset_name', 'N/A')\r\n+                main_file = row_data.get('main_file')\r\n+                return main_file.get('predicted_asset_name', 'N/A') if main_file else \"\"\r\n             elif col == self.COL_ORIGINAL_PATH:\r\n-                return file_details.get('original_path', '[Missing Path]')\r\n+                main_file = row_data.get('main_file')\r\n+                return main_file.get('original_path', '[Missing Path]') if main_file else \"\"\r\n             elif col == self.COL_PREDICTED_OUTPUT:\r\n-                return file_details.get('predicted_output_name', '')\r\n+                main_file = row_data.get('main_file')\r\n+                return main_file.get('predicted_output_name', '') if main_file else \"\"\r\n             elif col == self.COL_DETAILS:\r\n-                return file_details.get('details', '')\r\n+                main_file = row_data.get('main_file')\r\n+                return main_file.get('details', '') if main_file else \"\"\r\n+            elif col == self.COL_ADDITIONAL_FILES:\r\n+                return row_data.get('additional_file_path', '')\r\n             return None # Should not happen with defined columns\r\n \r\n         # --- Handle Tooltip Role ---\r\n         if role == Qt.ItemDataRole.ToolTipRole:\r\n              if col == self.COL_ORIGINAL_PATH:\r\n-                 source_asset = file_details.get('source_asset', 'N/A')\r\n-                 original_path = file_details.get('original_path', '[Missing Path]')\r\n-                 return f\"Source Asset: {source_asset}\\nFull Path: {original_path}\"\r\n+                 main_file = row_data.get('main_file')\r\n+                 if main_file:\r\n+                     source_asset = row_data.get('source_asset', 'N/A')\r\n+                     original_path = main_file.get('original_path', '[Missing Path]')\r\n+                     return f\"Source Asset: {source_asset}\\nFull Path: {original_path}\"\r\n+                 else:\r\n+                     return \"\" # No tooltip for empty cells\r\n              elif col == self.COL_STATUS:\r\n-                 return file_details.get('details', file_details.get('status', '[No Status]'))\r\n+                 main_file = row_data.get('main_file')\r\n+                 if main_file:\r\n+                     return main_file.get('details', main_file.get('status', '[No Status]'))\r\n+                 else:\r\n+                     return \"\" # No tooltip for empty cells\r\n              elif col == self.COL_PREDICTED_ASSET:\r\n-                 predicted_asset_name = file_details.get('predicted_asset_name', 'None')\r\n-                 return f\"Predicted Asset Name: {predicted_asset_name}\"\r\n+                 main_file = row_data.get('main_file')\r\n+                 if main_file:\r\n+                     predicted_asset_name = main_file.get('predicted_asset_name', 'None')\r\n+                     return f\"Predicted Asset Name: {predicted_asset_name}\"\r\n+                 else:\r\n+                     return \"\" # No tooltip for empty cells\r\n              elif col == self.COL_PREDICTED_OUTPUT:\r\n-                 predicted_output_name = file_details.get('predicted_output_name', 'None')\r\n-                 return f\"Predicted Output Name: {predicted_output_name}\"\r\n+                 main_file = row_data.get('main_file')\r\n+                 if main_file:\r\n+                     predicted_output_name = main_file.get('predicted_output_name', 'None')\r\n+                     return f\"Predicted Output Name: {predicted_output_name}\"\r\n+                 else:\r\n+                     return \"\" # No tooltip for empty cells\r\n              elif col == self.COL_DETAILS:\r\n-                 return file_details.get('details', '')\r\n+                 main_file = row_data.get('main_file')\r\n+                 if main_file:\r\n+                     return main_file.get('details', '')\r\n+                 else:\r\n+                     return \"\" # No tooltip for empty cells\r\n+             elif col == self.COL_ADDITIONAL_FILES:\r\n+                 additional_file = row_data.get('additional_file_details')\r\n+                 if additional_file:\r\n+                     status = additional_file.get('status', '[No Status]')\r\n+                     details = additional_file.get('details', '')\r\n+                     return f\"Status: {status}\\nDetails: {details}\"\r\n+                 else:\r\n+                     return \"\" # No tooltip if no additional file in this cell\r\n              return None\r\n \r\n         # --- Handle Foreground (Text Color) Role ---\r\n         if role == Qt.ItemDataRole.ForegroundRole:\r\n-            status = file_details.get('status', '[No Status]')\r\n-            color = None\r\n-            if status == \"Mapped\": color = QColor(\"#9dd9db\")\r\n-            elif status == \"Ignored\": color = QColor(\"#c1753d\")\r\n-            elif status == \"Extra\": color = QColor(\"#cfdca4\")\r\n-            elif status == \"Unrecognised\": color = QColor(\"#92371f\")\r\n-            elif status == \"Model\": color = QColor(\"#a4b8dc\")\r\n-            elif status == \"Unmatched Extra\": color = QColor(\"#777777\") # Grey for unmatched\r\n-            elif status == \"Error\": color = QColor(Qt.GlobalColor.red)\r\n-            if color:\r\n-                return color\r\n+            main_file = row_data.get('main_file')\r\n+            if main_file:\r\n+                status = main_file.get('status', '[No Status]')\r\n+                color = None\r\n+                if status == \"Mapped\": color = QColor(\"#9dd9db\")\r\n+                elif status == \"Ignored\": color = QColor(\"#c1753d\") # This case should not happen with new logic, but keep for safety\r\n+                elif status == \"Extra\": color = QColor(\"#cfdca4\") # This case should not happen with new logic, but keep for safety\r\n+                elif status == \"Unrecognised\": color = QColor(\"#92371f\") # This case should not happen with new logic, but keep for safety\r\n+                elif status == \"Model\": color = QColor(\"#a4b8dc\")\r\n+                elif status == \"Unmatched Extra\": color = QColor(\"#777777\") # This case should not happen with new logic, but keep for safety\r\n+                elif status == \"Error\": color = QColor(Qt.GlobalColor.red)\r\n+                if color:\r\n+                    return color\r\n+            # Neutral styling for additional files column and additional-only rows\r\n+            return None # Use default text color\r\n \r\n         # --- Handle Background Role (Optional, disabled in main_window for now) ---\r\n         # if role == Qt.ItemDataRole.BackgroundRole:\r\n         #     # This would require passing asset grouping info or calculating it here\r\n@@ -196,23 +240,60 @@\n         log.info(f\"[{time.time():.4f}][T:{thread_id}] --> Entered PreviewTableModel.set_data. Received {len(data)} items.\")\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling beginResetModel()...\")\r\n         self.beginResetModel()\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from beginResetModel(). Processing data...\")\r\n-        self._data = data or []\r\n-        # Extract unique source asset paths for simple mode\r\n+        self._data = data or [] # Keep original data for reference if needed\r\n+        self._table_rows = [] # Clear previous structured data\r\n+\r\n+        # Group files by source asset\r\n+        grouped_data = {}\r\n         unique_sources = set()\r\n-        # Check if data is a list of strings (simple paths) or list of dicts (detailed)\r\n-        if data and isinstance(data[0], str):\r\n-             log.debug(\"set_data received list of strings (simple paths).\")\r\n-             self._simple_data = sorted(list(set(data))) # Ensure uniqueness and sort\r\n-        else:\r\n-            log.debug(\"set_data received list of dicts (detailed data). Extracting simple paths.\")\r\n-            for item in self._data:\r\n-                source = item.get('source_asset')\r\n-                if source:\r\n-                    unique_sources.add(source)\r\n-            self._simple_data = sorted(list(unique_sources))\r\n+        if data and isinstance(data[0], dict): # Ensure data is in detailed format\r\n+            for file_details in data:\r\n+                source_asset = file_details.get('source_asset')\r\n+                if source_asset:\r\n+                    if source_asset not in grouped_data:\r\n+                        grouped_data[source_asset] = {'main_files': [], 'additional_files': []}\r\n+                        unique_sources.add(source_asset)\r\n \r\n+                    status = file_details.get('status')\r\n+                    # Separate into main and additional files based on status\r\n+                    if status in [\"Mapped\", \"Model\", \"Error\"]:\r\n+                        grouped_data[source_asset]['main_files'].append(file_details)\r\n+                    else: # Ignored, Extra, Unrecognised, Unmatched Extra\r\n+                        grouped_data[source_asset]['additional_files'].append(file_details)\r\n+\r\n+        # Sort main and additional files within each group (e.g., by original_path)\r\n+        for asset_data in grouped_data.values():\r\n+            asset_data['main_files'].sort(key=lambda x: x.get('original_path', ''))\r\n+            asset_data['additional_files'].sort(key=lambda x: x.get('original_path', '')) # Sort additional by their path\r\n+\r\n+        # Build the _table_rows structure\r\n+        sorted_assets = sorted(list(unique_sources)) # Sort assets alphabetically\r\n+        for asset_name in sorted_assets:\r\n+            asset_data = grouped_data[asset_name]\r\n+            main_files = asset_data['main_files']\r\n+            additional_files = asset_data['additional_files']\r\n+            max_rows = max(len(main_files), len(additional_files))\r\n+\r\n+            for i in range(max_rows):\r\n+                main_file = main_files[i] if i < len(main_files) else None\r\n+                additional_file = additional_files[i] if i < len(additional_files) else None\r\n+\r\n+                row_data = {\r\n+                    'source_asset': asset_name,\r\n+                    'main_file': main_file, # Store the full dict for easy access\r\n+                    'additional_file_path': additional_file.get('original_path', '') if additional_file else '',\r\n+                    'additional_file_details': additional_file, # Store full dict for tooltip\r\n+                    'is_main_row': main_file is not None # True if this row has a main file\r\n+                }\r\n+                self._table_rows.append(row_data)\r\n+\r\n+        # Extract unique source asset paths for simple mode (still needed)\r\n+        self._simple_data = sorted(list(unique_sources))\r\n+\r\n+\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Structured data built: {len(self._table_rows)} rows.\")\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling endResetModel()...\")\r\n         self.endResetModel()\r\n         log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from endResetModel().\")\r\n@@ -275,43 +356,58 @@\n \r\n \r\n         # --- Detailed Mode Sorting ---\r\n         # log.debug(\"ProxyModel.lessThan (Detailed Mode).\")\r\n+        # Get the full row data from the source model's _table_rows\r\n+        left_row_data = model._table_rows[left.row()]\r\n+        right_row_data = model._table_rows[right.row()]\r\n+\r\n         # --- Level 1: Sort by Source Asset ---\r\n-        left_asset = model.data(left.siblingAtColumn(model.COL_PREDICTED_ASSET), model.ROLE_SOURCE_ASSET)\r\n-        right_asset = model.data(right.siblingAtColumn(model.COL_PREDICTED_ASSET), model.ROLE_SOURCE_ASSET)\r\n+        left_asset = left_row_data.get('source_asset', 'N/A')\r\n+        right_asset = right_row_data.get('source_asset', 'N/A')\r\n \r\n         if left_asset != right_asset:\r\n             # Handle None/empty strings for consistent sorting\r\n-            if not left_asset: return True # Empty asset comes first\r\n-            if not right_asset: return False # Non-empty asset comes first\r\n+            if not left_asset or left_asset == 'N/A': return True # Empty asset comes first\r\n+            if not right_asset or right_asset == 'N/A': return False # Non-empty asset comes first\r\n             return left_asset < right_asset # Alphabetical sort for assets\r\n \r\n-        # --- Level 2: Sort by Status (Custom Priority) ---\r\n-        left_status = model.data(left.siblingAtColumn(model.COL_STATUS), model.ROLE_RAW_STATUS)\r\n-        right_status = model.data(right.siblingAtColumn(model.COL_STATUS), model.ROLE_RAW_STATUS)\r\n+        # --- Level 2: Sort by Row Type (Main vs Additional-only) ---\r\n+        # Main rows (is_main_row == True) should come before additional-only rows\r\n+        left_is_main = left_row_data.get('is_main_row', False)\r\n+        right_is_main = right_row_data.get('is_main_row', False)\r\n \r\n-        # Get the priority from the dictionary (default to low priority if status not found)\r\n-        left_prio = self.STATUS_PRIORITY.get(left_status, 99)\r\n-        right_prio = self.STATUS_PRIORITY.get(right_status, 99)\r\n+        if left_is_main != right_is_main:\r\n+            return left_is_main > right_is_main # True > False\r\n \r\n-        if left_prio != right_prio:\r\n-            return left_prio < right_prio # Sort based on priority\r\n+        # --- Level 3: Sort within the row type ---\r\n+        if left_is_main: # Both are main rows\r\n+            # Sort by Original Path (Alphabetical)\r\n+            left_path = left_row_data.get('main_file', {}).get('original_path', '')\r\n+            right_path = right_row_data.get('main_file', {}).get('original_path', '')\r\n\\ No newline at end of file\n \r\n-        # --- Level 3: Sort by Original Path (Alphabetical, only if assets and status priorities are equal) ---\r\n-        left_path = model.data(left.siblingAtColumn(model.COL_ORIGINAL_PATH), Qt.ItemDataRole.DisplayRole)\r\n-        right_path = model.data(right.siblingAtColumn(model.COL_ORIGINAL_PATH), Qt.ItemDataRole.DisplayRole)\r\n+            if not left_path: return True\r\n+            if not right_path: return False\r\n+            return left_path < right_path\r\n \r\n-        # Handle None/empty strings\r\n-        if not left_path: return True\r\n-        if not right_path: return False\r\n+        else: # Both are additional-only rows\r\n+            # Sort by Additional File Path (Alphabetical)\r\n+            left_additional_path = left_row_data.get('additional_file_path', '')\r\n+            right_additional_path = right_row_data.get('additional_file_path', '')\r\n \r\n-        return left_path < right_path # Alphabetical sort for paths\r\n+            if not left_additional_path: return True\r\n+            if not right_additional_path: return False\r\n+            return left_additional_path < right_additional_path\r\n \r\n+        # Should not reach here if logic is correct, but include a fallback\r\n+        return super().lessThan(left, right)\r\n+\r\n     # Override sort method to ensure custom sorting is used\r\n     def sort(self, column: int, order: Qt.SortOrder = Qt.SortOrder.AscendingOrder):\r\n         # We ignore the column and order here and rely on lessThan for multi-level sort\r\n         # However, calling this method is necessary to trigger the proxy model's sorting mechanism.\r\n         # We can potentially use the column/order to toggle ascending/descending within each level in lessThan,\r\n         # but for now, we'll stick to the defined order.\r\n         log.debug(f\"ProxyModel.sort called with column {column}, order {order}. Triggering lessThan.\")\r\n-        super().sort(column, order) # Call base class sort to trigger update\n+        # Call base class sort to trigger update. Pass a valid column, e.g., COL_STATUS,\r\n+        # as the actual sorting logic is in lessThan.\r\n+        super().sort(PreviewTableModel.COL_STATUS, Qt.SortOrder.AscendingOrder)\n\\ No newline at end of file\n"
                },
                {
                    "date": 1745498833062,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -4,8 +4,12 @@\n from PySide6.QtGui import QColor\r\n \r\n log = logging.getLogger(__name__) # Get logger\r\n \r\n+# Define colors for alternating asset groups\r\n+COLOR_ASSET_GROUP_1 = QColor(\"#3a3a3a\") # Dark grey 1\r\n+COLOR_ASSET_GROUP_2 = QColor(\"#4a4a4a\") # Dark grey 2\r\n+\r\n class PreviewTableModel(QAbstractTableModel):\r\n     \"\"\"\r\n     Custom table model for the GUI preview table.\r\n     Holds detailed file prediction results or a simple list of source assets.\r\n@@ -34,8 +38,9 @@\n         self._table_rows = [] # New structure for displaying rows\r\n         self._simple_data = [] # List of unique source asset paths for simple mode\r\n         self._simple_mode = False # Flag to toggle between detailed and simple view\r\n         self._headers_detailed = [\"Status\", \"Predicted Asset\", \"Original Path\", \"Predicted Output\", \"Details\", \"Additional Files\"] # Added new column header\r\n+        self._sorted_unique_assets = [] # Store sorted unique asset names for coloring\r\n         self._headers_simple = [\"Input Path\"]\r\n         self.set_data(data or []) # Initialize data and simple_data\r\n \r\n     def set_simple_mode(self, enabled: bool):\r\n@@ -216,14 +221,26 @@\n                     return color\r\n             # Neutral styling for additional files column and additional-only rows\r\n             return None # Use default text color\r\n \r\n-        # --- Handle Background Role (Optional, disabled in main_window for now) ---\r\n-        # if role == Qt.ItemDataRole.BackgroundRole:\r\n-        #     # This would require passing asset grouping info or calculating it here\r\n-        #     # and might conflict with ForegroundRole. Leaving disabled for now.\r\n-        #     pass\r\n+        # --- Handle Background Role ---\r\n+        if role == Qt.ItemDataRole.BackgroundRole:\r\n+            # Apply alternating background color based on asset group\r\n+            source_asset = row_data.get('source_asset')\r\n+            if source_asset and source_asset in self._sorted_unique_assets:\r\n+                try:\r\n+                    asset_index = self._sorted_unique_assets.index(source_asset)\r\n+                    if asset_index % 2 == 0:\r\n+                        return COLOR_ASSET_GROUP_1\r\n+                    else:\r\n+                        return COLOR_ASSET_GROUP_2\r\n+                except ValueError:\r\n+                    # Should not happen if logic is correct, but handle defensively\r\n+                    log.warning(f\"Asset '{source_asset}' not found in _sorted_unique_assets.\")\r\n+                    return None # Use default background\r\n+            return None # Use default background for rows without a source asset\r\n \r\n+\r\n         return None\r\n \r\n     def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole):\r\n         \"\"\"Returns the header data for a given section, orientation, and role.\"\"\"\r\n@@ -287,18 +304,19 @@\n                     'is_main_row': main_file is not None # True if this row has a main file\r\n                 }\r\n                 self._table_rows.append(row_data)\r\n \r\n-        # Extract unique source asset paths for simple mode (still needed)\r\n-        self._simple_data = sorted(list(unique_sources))\r\n+       # Store sorted unique asset paths for simple mode and coloring\r\n+       self._sorted_unique_assets = sorted(list(unique_sources))\r\n+       self._simple_data = self._sorted_unique_assets # Simple data is just the sorted unique assets\r\n \r\n \r\n-        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Structured data built: {len(self._table_rows)} rows.\")\r\n-        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n-        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling endResetModel()...\")\r\n-        self.endResetModel()\r\n-        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from endResetModel().\")\r\n-        log.info(f\"[{time.time():.4f}][T:{thread_id}] <-- Exiting PreviewTableModel.set_data.\")\r\n+       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Structured data built: {len(self._table_rows)} rows.\")\r\n+       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n+       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling endResetModel()...\")\r\n+       self.endResetModel()\r\n+       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from endResetModel().\")\r\n+       log.info(f\"[{time.time():.4f}][T:{thread_id}] <-- Exiting PreviewTableModel.set_data.\")\r\n \r\n     def clear_data(self):\r\n         \"\"\"Clears the model's data.\"\"\"\r\n         thread_id = QThread.currentThread() # Get current thread object\r\n"
                },
                {
                    "date": 1745498842395,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -305,10 +305,10 @@\n                 }\r\n                 self._table_rows.append(row_data)\r\n \r\n        # Store sorted unique asset paths for simple mode and coloring\r\n-       self._sorted_unique_assets = sorted(list(unique_sources))\r\n-       self._simple_data = self._sorted_unique_assets # Simple data is just the sorted unique assets\r\n+        self._sorted_unique_assets = sorted(list(unique_sources))\r\n+        self._simple_data = self._sorted_unique_assets # Simple data is just the sorted unique assets\r\n \r\n \r\n        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Structured data built: {len(self._table_rows)} rows.\")\r\n        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n"
                },
                {
                    "date": 1745498851319,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -309,14 +309,14 @@\n         self._sorted_unique_assets = sorted(list(unique_sources))\r\n         self._simple_data = self._sorted_unique_assets # Simple data is just the sorted unique assets\r\n \r\n \r\n-       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Structured data built: {len(self._table_rows)} rows.\")\r\n-       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n-       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling endResetModel()...\")\r\n-       self.endResetModel()\r\n-       log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from endResetModel().\")\r\n-       log.info(f\"[{time.time():.4f}][T:{thread_id}] <-- Exiting PreviewTableModel.set_data.\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Structured data built: {len(self._table_rows)} rows.\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Simple data extracted: {len(self._simple_data)} unique sources.\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Calling endResetModel()...\")\r\n+        self.endResetModel()\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}]     Returned from endResetModel().\")\r\n+        log.info(f\"[{time.time():.4f}][T:{thread_id}] <-- Exiting PreviewTableModel.set_data.\")\r\n \r\n     def clear_data(self):\r\n         \"\"\"Clears the model's data.\"\"\"\r\n         thread_id = QThread.currentThread() # Get current thread object\r\n"
                },
                {
                    "date": 1745502633059,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -5,10 +5,10 @@\n \r\n log = logging.getLogger(__name__) # Get logger\r\n \r\n # Define colors for alternating asset groups\r\n-COLOR_ASSET_GROUP_1 = QColor(\"#3a3a3a\") # Dark grey 1\r\n-COLOR_ASSET_GROUP_2 = QColor(\"#4a4a4a\") # Dark grey 2\r\n+COLOR_ASSET_GROUP_1 = QColor(\"#292929\") # Dark grey 1\r\n+COLOR_ASSET_GROUP_2 = QColor(\"#343434\") # Dark grey 2\r\n \r\n class PreviewTableModel(QAbstractTableModel):\r\n     \"\"\"\r\n     Custom table model for the GUI preview table.\r\n"
                },
                {
                    "date": 1745503403701,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -8,8 +8,20 @@\n # Define colors for alternating asset groups\r\n COLOR_ASSET_GROUP_1 = QColor(\"#292929\") # Dark grey 1\r\n COLOR_ASSET_GROUP_2 = QColor(\"#343434\") # Dark grey 2\r\n \r\n+# Define text colors for statuses\r\n+STATUS_COLORS = {\r\n+    \"Mapped\": QColor(\"#9dd9db\"),\r\n+    \"Ignored\": QColor(\"#c1753d\"),\r\n+    \"Extra\": QColor(\"#cfdca4\"),\r\n+    \"Unrecognised\": QColor(\"#92371f\"),\r\n+    \"Model\": QColor(\"#a4b8dc\"),\r\n+    \"Unmatched Extra\": QColor(\"#777777\"),\r\n+    \"Error\": QColor(Qt.GlobalColor.red),\r\n+    \"[No Status]\": None # Use default color for no status\r\n+}\r\n+\r\n class PreviewTableModel(QAbstractTableModel):\r\n     \"\"\"\r\n     Custom table model for the GUI preview table.\r\n     Holds detailed file prediction results or a simple list of source assets.\r\n@@ -205,24 +217,34 @@\n              return None\r\n \r\n         # --- Handle Foreground (Text Color) Role ---\r\n         if role == Qt.ItemDataRole.ForegroundRole:\r\n-            main_file = row_data.get('main_file')\r\n-            if main_file:\r\n-                status = main_file.get('status', '[No Status]')\r\n-                color = None\r\n-                if status == \"Mapped\": color = QColor(\"#9dd9db\")\r\n-                elif status == \"Ignored\": color = QColor(\"#c1753d\") # This case should not happen with new logic, but keep for safety\r\n-                elif status == \"Extra\": color = QColor(\"#cfdca4\") # This case should not happen with new logic, but keep for safety\r\n-                elif status == \"Unrecognised\": color = QColor(\"#92371f\") # This case should not happen with new logic, but keep for safety\r\n-                elif status == \"Model\": color = QColor(\"#a4b8dc\")\r\n-                elif status == \"Unmatched Extra\": color = QColor(\"#777777\") # This case should not happen with new logic, but keep for safety\r\n-                elif status == \"Error\": color = QColor(Qt.GlobalColor.red)\r\n-                if color:\r\n-                    return color\r\n-            # Neutral styling for additional files column and additional-only rows\r\n-            return None # Use default text color\r\n+            row_data = self._table_rows[row] # Get data from the structured row\r\n+            status = None\r\n+            color = None\r\n \r\n+            if col == self.COL_STATUS:\r\n+                # Apply color based on main_file status\r\n+                main_file = row_data.get('main_file')\r\n+                if main_file:\r\n+                    status = main_file.get('status', '[No Status]')\r\n+            elif col == self.COL_ADDITIONAL_FILES:\r\n+                # Apply color based on additional_file status\r\n+                additional_file = row_data.get('additional_file_details')\r\n+                if additional_file:\r\n+                    status = additional_file.get('status', '[No Status]')\r\n+\r\n+            # Look up color based on determined status\r\n+            if status in self.STATUS_COLORS:\r\n+                 color = self.STATUS_COLORS[status]\r\n+            # If status is not in the dictionary or is '[No Status]', color will be None,\r\n+            # which results in the default text color being used.\r\n+\r\n+            if color:\r\n+                return color\r\n+            else:\r\n+                return None # Use default text color for other columns or if no specific status color\r\n+\r\n         # --- Handle Background Role ---\r\n         if role == Qt.ItemDataRole.BackgroundRole:\r\n             # Apply alternating background color based on asset group\r\n             source_asset = row_data.get('source_asset')\r\n"
                },
                {
                    "date": 1745503475048,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -9,24 +9,25 @@\n COLOR_ASSET_GROUP_1 = QColor(\"#292929\") # Dark grey 1\r\n COLOR_ASSET_GROUP_2 = QColor(\"#343434\") # Dark grey 2\r\n \r\n # Define text colors for statuses\r\n-STATUS_COLORS = {\r\n-    \"Mapped\": QColor(\"#9dd9db\"),\r\n-    \"Ignored\": QColor(\"#c1753d\"),\r\n-    \"Extra\": QColor(\"#cfdca4\"),\r\n-    \"Unrecognised\": QColor(\"#92371f\"),\r\n-    \"Model\": QColor(\"#a4b8dc\"),\r\n-    \"Unmatched Extra\": QColor(\"#777777\"),\r\n-    \"Error\": QColor(Qt.GlobalColor.red),\r\n-    \"[No Status]\": None # Use default color for no status\r\n-}\r\n-\r\n class PreviewTableModel(QAbstractTableModel):\r\n     \"\"\"\r\n     Custom table model for the GUI preview table.\r\n     Holds detailed file prediction results or a simple list of source assets.\r\n     \"\"\"\r\n+    # Define text colors for statuses\r\n+    STATUS_COLORS = {\r\n+        \"Mapped\": QColor(\"#9dd9db\"),\r\n+        \"Ignored\": QColor(\"#c1753d\"),\r\n+        \"Extra\": QColor(\"#cfdca4\"),\r\n+        \"Unrecognised\": QColor(\"#92371f\"),\r\n+        \"Model\": QColor(\"#a4b8dc\"),\r\n+        \"Unmatched Extra\": QColor(\"#777777\"),\r\n+        \"Error\": QColor(Qt.GlobalColor.red),\r\n+        \"[No Status]\": None # Use default color for no status\r\n+    }\r\n+\r\n     # Define column roles for clarity (Detailed Mode)\r\n     COL_STATUS = 0\r\n     COL_PREDICTED_ASSET = 1\r\n     COL_ORIGINAL_PATH = 2\r\n"
                },
                {
                    "date": 1745504469131,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -262,8 +262,18 @@\n                     return None # Use default background\r\n             return None # Use default background for rows without a source asset\r\n \r\n \r\n+        # --- Handle Text Alignment Role ---\r\n+        if role == Qt.ItemDataRole.TextAlignmentRole:\r\n+            if col == self.COL_ORIGINAL_PATH:\r\n+                return int(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)\r\n+            elif col == self.COL_ADDITIONAL_FILES:\r\n+                return int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)\r\n+            # For other columns, return default alignment (or None)\r\n+            return None\r\n+\r\n+\r\n         return None\r\n \r\n     def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole):\r\n         \"\"\"Returns the header data for a given section, orientation, and role.\"\"\"\r\n"
                },
                {
                    "date": 1745504635365,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -272,8 +272,18 @@\n             # For other columns, return default alignment (or None)\r\n             return None\r\n \r\n \r\n+        # --- Handle Text Alignment Role ---\r\n+        if role == Qt.ItemDataRole.TextAlignmentRole:\r\n+            if col == self.COL_ORIGINAL_PATH:\r\n+                return int(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)\r\n+            elif col == self.COL_ADDITIONAL_FILES:\r\n+                return int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)\r\n+            # For other columns, return default alignment (or None)\r\n+            return None\r\n+\r\n+\r\n         return None\r\n \r\n     def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole):\r\n         \"\"\"Returns the header data for a given section, orientation, and role.\"\"\"\r\n"
                },
                {
                    "date": 1745505011158,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -220,31 +220,26 @@\n         # --- Handle Foreground (Text Color) Role ---\r\n         if role == Qt.ItemDataRole.ForegroundRole:\r\n             row_data = self._table_rows[row] # Get data from the structured row\r\n             status = None\r\n-            color = None\r\n \r\n-            if col == self.COL_STATUS:\r\n-                # Apply color based on main_file status\r\n+            # Determine the relevant status based on column and row data\r\n+            if col in [self.COL_STATUS, self.COL_PREDICTED_ASSET, self.COL_ORIGINAL_PATH, self.COL_PREDICTED_OUTPUT, self.COL_DETAILS]:\r\n+                # These columns relate to the main file\r\n                 main_file = row_data.get('main_file')\r\n                 if main_file:\r\n                     status = main_file.get('status', '[No Status]')\r\n             elif col == self.COL_ADDITIONAL_FILES:\r\n-                # Apply color based on additional_file status\r\n+                # This column relates to the additional file\r\n                 additional_file = row_data.get('additional_file_details')\r\n                 if additional_file:\r\n                     status = additional_file.get('status', '[No Status]')\r\n \r\n             # Look up color based on determined status\r\n             if status in self.STATUS_COLORS:\r\n-                 color = self.STATUS_COLORS[status]\r\n-            # If status is not in the dictionary or is '[No Status]', color will be None,\r\n-            # which results in the default text color being used.\r\n-\r\n-            if color:\r\n-                return color\r\n+                 return self.STATUS_COLORS[status]\r\n             else:\r\n-                return None # Use default text color for other columns or if no specific status color\r\n+                return None # Use default text color if no specific status color or no relevant file data\r\n \r\n         # --- Handle Background Role ---\r\n         if role == Qt.ItemDataRole.BackgroundRole:\r\n             # Apply alternating background color based on asset group\r\n"
                }
            ],
            "date": 1745323013820,
            "name": "Commit-0",
            "content": "from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex, QSortFilterProxyModel\r\nfrom PySide6.QtGui import QColor\r\n\r\nclass PreviewTableModel(QAbstractTableModel):\r\n    \"\"\"\r\n    Custom table model for the GUI preview table.\r\n    Holds detailed file prediction results.\r\n    \"\"\"\r\n    # Define column roles for clarity\r\n    COL_STATUS = 0\r\n    COL_PREDICTED_ASSET = 1\r\n    COL_ORIGINAL_PATH = 2\r\n    COL_PREDICTED_OUTPUT = 3\r\n    COL_DETAILS = 4\r\n\r\n    # Define internal data roles for sorting/filtering\r\n    ROLE_RAW_STATUS = Qt.ItemDataRole.UserRole + 1\r\n    ROLE_SOURCE_ASSET = Qt.ItemDataRole.UserRole + 2\r\n\r\n    def __init__(self, data=None, parent=None):\r\n        super().__init__(parent)\r\n        # Data format: List of dictionaries, each representing a file's details\r\n        # Example: {'original_path': '...', 'predicted_asset_name': '...', 'predicted_output_name': '...', 'status': '...', 'details': '...', 'source_asset': '...'}\r\n        self._data = data or []\r\n        # Initial columns - will be adjusted later\r\n        self._headers = [\"Status\", \"Predicted Asset\", \"Original Path\", \"Predicted Output\", \"Details\"]\r\n\r\n    def rowCount(self, parent=QModelIndex()):\r\n        \"\"\"Returns the number of rows in the model.\"\"\"\r\n        if parent.isValid():\r\n            return 0\r\n        return len(self._data)\r\n\r\n    def columnCount(self, parent=QModelIndex()):\r\n        \"\"\"Returns the number of columns in the model.\"\"\"\r\n        if parent.isValid():\r\n            return 0\r\n        return len(self._headers)\r\n\r\n    def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):\r\n        \"\"\"Returns the data for a given index and role.\"\"\"\r\n        if not index.isValid():\r\n            return None\r\n\r\n        row = index.row()\r\n        col = index.column()\r\n        file_details = self._data[row]\r\n\r\n        # --- Handle Custom Internal Roles ---\r\n        if role == self.ROLE_RAW_STATUS:\r\n            return file_details.get('status', '[No Status]')\r\n        if role == self.ROLE_SOURCE_ASSET:\r\n            return file_details.get('source_asset', 'N/A')\r\n\r\n        # --- Handle Display Role ---\r\n        if role == Qt.ItemDataRole.DisplayRole:\r\n            if col == self.COL_STATUS:\r\n                # TODO: Implement status text simplification here later\r\n                return file_details.get('status', '[No Status]')\r\n            elif col == self.COL_PREDICTED_ASSET:\r\n                return file_details.get('predicted_asset_name', 'N/A')\r\n            elif col == self.COL_ORIGINAL_PATH:\r\n                return file_details.get('original_path', '[Missing Path]')\r\n            elif col == self.COL_PREDICTED_OUTPUT:\r\n                return file_details.get('predicted_output_name', '')\r\n            elif col == self.COL_DETAILS:\r\n                return file_details.get('details', '')\r\n            return None # Should not happen with defined columns\r\n\r\n        # --- Handle Tooltip Role ---\r\n        if role == Qt.ItemDataRole.ToolTipRole:\r\n             if col == self.COL_ORIGINAL_PATH:\r\n                 source_asset = file_details.get('source_asset', 'N/A')\r\n                 original_path = file_details.get('original_path', '[Missing Path]')\r\n                 return f\"Source Asset: {source_asset}\\nFull Path: {original_path}\"\r\n             elif col == self.COL_STATUS:\r\n                 return file_details.get('details', file_details.get('status', '[No Status]'))\r\n             elif col == self.COL_PREDICTED_ASSET:\r\n                 predicted_asset_name = file_details.get('predicted_asset_name', 'None')\r\n                 return f\"Predicted Asset Name: {predicted_asset_name}\"\r\n             elif col == self.COL_PREDICTED_OUTPUT:\r\n                 predicted_output_name = file_details.get('predicted_output_name', 'None')\r\n                 return f\"Predicted Output Name: {predicted_output_name}\"\r\n             elif col == self.COL_DETAILS:\r\n                 return file_details.get('details', '')\r\n             return None\r\n\r\n        # --- Handle Foreground (Text Color) Role ---\r\n        if role == Qt.ItemDataRole.ForegroundRole:\r\n            status = file_details.get('status', '[No Status]')\r\n            color = None\r\n            if status == \"Mapped\": color = QColor(\"#9dd9db\")\r\n            elif status == \"Ignored\": color = QColor(\"#c1753d\")\r\n            elif status == \"Extra\": color = QColor(\"#cfdca4\")\r\n            elif status == \"Unrecognised\": color = QColor(\"#92371f\")\r\n            elif status == \"Model\": color = QColor(\"#a4b8dc\")\r\n            elif status == \"Unmatched Extra\": color = QColor(\"#777777\") # Grey for unmatched\r\n            elif status == \"Error\": color = QColor(Qt.GlobalColor.red)\r\n            if color:\r\n                return color\r\n\r\n        # --- Handle Background Role (Optional, disabled in main_window for now) ---\r\n        # if role == Qt.ItemDataRole.BackgroundRole:\r\n        #     # This would require passing asset grouping info or calculating it here\r\n        #     # and might conflict with ForegroundRole. Leaving disabled for now.\r\n        #     pass\r\n\r\n        return None\r\n\r\n    def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole):\r\n        \"\"\"Returns the header data for a given section, orientation, and role.\"\"\"\r\n        if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:\r\n            if 0 <= section < len(self._headers):\r\n                return self._headers[section]\r\n        return None\r\n\r\n    def set_data(self, data: list):\r\n        \"\"\"Sets the model's data and emits signals to update views.\"\"\"\r\n        self.beginResetModel()\r\n        self._data = data\r\n        self.endResetModel()\r\n\r\n    def clear_data(self):\r\n        \"\"\"Clears the model's data.\"\"\"\r\n        self.set_data([])\r\n\r\n\r\nclass PreviewSortFilterProxyModel(QSortFilterProxyModel):\r\n    \"\"\"\r\n    Custom proxy model for sorting the preview table.\r\n    Implements multi-level sorting and custom status order.\r\n    \"\"\"\r\n    # Define the desired status order for sorting\r\n    # Error > Mapped > Model > Ignored > Extra\r\n    STATUS_ORDER = [\"Error\", \"Mapped\", \"Model\", \"Ignored\", \"Extra\", \"Unrecognised\", \"Unmatched Extra\", \"[No Status]\"] # Include others for completeness\r\n\r\n    def __init__(self, parent=None):\r\n        super().__init__(parent)\r\n        # Set default sort column and order (Status column, Ascending)\r\n        # This will be overridden by the custom lessThan logic\r\n        self.setSortRole(PreviewTableModel.ROLE_RAW_STATUS) # Sort using the raw status role\r\n        self.sort(PreviewTableModel.COL_STATUS, Qt.SortOrder.AscendingOrder) # Apply initial sort\r\n\r\n    def lessThan(self, left: QModelIndex, right: QModelIndex):\r\n        \"\"\"\r\n        Custom comparison logic for multi-level sorting.\r\n        Sorts by:\r\n        1. Source Asset (Ascending)\r\n        2. Status (Custom Order: Error > Mapped/Model > Ignored > Extra)\r\n        3. Original Path (Ascending)\r\n        \"\"\"\r\n        model = self.sourceModel()\r\n        if not model:\r\n            return super().lessThan(left, right) # Fallback if no source model\r\n\r\n        # --- Level 1: Sort by Source Asset ---\r\n        left_asset = model.data(left.siblingAtColumn(model.COL_PREDICTED_ASSET), model.ROLE_SOURCE_ASSET)\r\n        right_asset = model.data(right.siblingAtColumn(model.COL_PREDICTED_ASSET), model.ROLE_SOURCE_ASSET)\r\n\r\n        if left_asset != right_asset:\r\n            # Handle None/empty strings for consistent sorting\r\n            if not left_asset: return True # Empty asset comes first\r\n            if not right_asset: return False # Non-empty asset comes first\r\n            return left_asset < right_asset # Alphabetical sort for assets\r\n\r\n        # --- Level 2: Sort by Status (Custom Order) ---\r\n        left_status = model.data(left.siblingAtColumn(model.COL_STATUS), model.ROLE_RAW_STATUS)\r\n        right_status = model.data(right.siblingAtColumn(model.COL_STATUS), model.ROLE_RAW_STATUS)\r\n\r\n        # Get the index of the status in the defined order\r\n        left_status_index = self.STATUS_ORDER.index(left_status) if left_status in self.STATUS_ORDER else len(self.STATUS_ORDER)\r\n        right_status_index = self.STATUS_ORDER.index(right_status) if right_status in self.STATUS_ORDER else len(self.STATUS_ORDER)\r\n\r\n        if left_status_index != right_status_index:\r\n            return left_status_index < right_status_index # Sort based on custom order index\r\n\r\n        # --- Level 3: Sort by Original Path (Alphabetical) ---\r\n        left_path = model.data(left.siblingAtColumn(model.COL_ORIGINAL_PATH), Qt.ItemDataRole.DisplayRole)\r\n        right_path = model.data(right.siblingAtColumn(model.COL_ORIGINAL_PATH), Qt.ItemDataRole.DisplayRole)\r\n\r\n        # Handle None/empty strings\r\n        if not left_path: return True\r\n        if not right_path: return False\r\n\r\n        return left_path < right_path # Alphabetical sort for paths\r\n\r\n    # Override sort method to ensure custom sorting is used\r\n    def sort(self, column: int, order: Qt.SortOrder = Qt.SortOrder.AscendingOrder):\r\n        # We ignore the column and order here and rely on lessThan for multi-level sort\r\n        # However, calling this method is necessary to trigger the proxy model's sorting mechanism.\r\n        # We can potentially use the column/order to toggle ascending/descending within each level in lessThan,\r\n        # but for now, we'll stick to the defined order.\r\n        super().sort(column, order) # Call base class sort to trigger update"
        }
    ]
}