551 lines
31 KiB
Python
551 lines
31 KiB
Python
# gui/unified_view_model.py
|
|
import logging # Added for debugging
|
|
log = logging.getLogger(__name__) # Added for debugging
|
|
from PySide6.QtCore import QAbstractItemModel, QModelIndex, Qt, Signal # Added Signal
|
|
from PySide6.QtGui import QColor # Added for background role
|
|
from pathlib import Path # Added for file_name extraction
|
|
from rule_structure import SourceRule, AssetRule, FileRule # Removed AssetType, ItemType import
|
|
from configuration import load_base_config # Import load_base_config
|
|
|
|
class UnifiedViewModel(QAbstractItemModel):
|
|
# --- Color Constants for Row Backgrounds ---
|
|
# Old colors removed, using config now + fixed source color
|
|
SOURCE_RULE_COLOR = QColor("#306091") # Fixed color for SourceRule rows
|
|
# -----------------------------------------
|
|
|
|
"""
|
|
A QAbstractItemModel for displaying and editing the hierarchical structure
|
|
of SourceRule -> AssetRule -> FileRule.
|
|
"""
|
|
Columns = [
|
|
"Name", "Supplier", "Asset-Type Override", # Renamed "Supplier Override"
|
|
"Target Asset Name Override", "Item-Type Override",
|
|
"Status", "Output Path"
|
|
]
|
|
|
|
COL_NAME = 0
|
|
COL_SUPPLIER = 1
|
|
COL_ASSET_TYPE = 2
|
|
COL_TARGET_ASSET = 3
|
|
COL_ITEM_TYPE = 4
|
|
COL_STATUS = 5
|
|
COL_OUTPUT_PATH = 6
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self._source_rules = [] # Now stores a list of SourceRule objects
|
|
|
|
def load_data(self, source_rules_list: list): # Accepts a list
|
|
"""Loads or reloads the model with a list of SourceRule objects."""
|
|
self.beginResetModel()
|
|
self._source_rules = source_rules_list if source_rules_list else [] # Assign the new list
|
|
# Ensure back-references for parent lookup are set on the NEW items
|
|
for source_rule in self._source_rules:
|
|
for asset_rule in source_rule.assets:
|
|
asset_rule.parent_source = source_rule # Set parent SourceRule
|
|
for file_rule in asset_rule.files:
|
|
file_rule.parent_asset = asset_rule # Set parent AssetRule
|
|
self.endResetModel()
|
|
|
|
def clear_data(self):
|
|
"""Clears the model data."""
|
|
self.beginResetModel()
|
|
self._source_rules = [] # Clear the list
|
|
self.endResetModel()
|
|
|
|
def get_all_source_rules(self) -> list:
|
|
"""Returns the internal list of SourceRule objects."""
|
|
return self._source_rules
|
|
def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
|
|
"""Returns the number of rows under the given parent."""
|
|
if not parent.isValid():
|
|
# Parent is the invisible root. Children are the SourceRules.
|
|
return len(self._source_rules)
|
|
|
|
parent_item = parent.internalPointer()
|
|
|
|
if isinstance(parent_item, SourceRule):
|
|
# Parent is a SourceRule. Children are AssetRules.
|
|
return len(parent_item.assets)
|
|
elif isinstance(parent_item, AssetRule):
|
|
# Parent is an AssetRule. Children are FileRules.
|
|
return len(parent_item.files)
|
|
elif isinstance(parent_item, FileRule):
|
|
return 0 # FileRules have no children
|
|
|
|
return 0 # Should not happen for valid items
|
|
|
|
|
|
def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
|
|
"""Returns the number of columns."""
|
|
return len(self.Columns)
|
|
|
|
def parent(self, index: QModelIndex) -> QModelIndex:
|
|
"""Returns the parent of the model item with the given index."""
|
|
if not index.isValid():
|
|
return QModelIndex()
|
|
|
|
child_item = index.internalPointer()
|
|
if child_item is None:
|
|
return QModelIndex()
|
|
|
|
# Determine the parent based on the item type
|
|
if isinstance(child_item, SourceRule):
|
|
# Parent is the invisible root
|
|
return QModelIndex()
|
|
elif isinstance(child_item, AssetRule):
|
|
# Parent is a SourceRule. Find its row in the _source_rules list.
|
|
parent_item = getattr(child_item, 'parent_source', None)
|
|
if parent_item and parent_item in self._source_rules:
|
|
try:
|
|
parent_row = self._source_rules.index(parent_item)
|
|
return self.createIndex(parent_row, 0, parent_item)
|
|
except ValueError:
|
|
return QModelIndex() # Should not happen if parent_source is correct
|
|
else:
|
|
return QModelIndex() # Parent SourceRule not found or reference missing
|
|
|
|
elif isinstance(child_item, FileRule):
|
|
# Parent is an AssetRule. Find its row within its parent SourceRule.
|
|
parent_item = getattr(child_item, 'parent_asset', None) # Get parent AssetRule
|
|
if parent_item:
|
|
grandparent_item = getattr(parent_item, 'parent_source', None) # Get the SourceRule
|
|
if grandparent_item:
|
|
try:
|
|
parent_row = grandparent_item.assets.index(parent_item)
|
|
# We need the index of the grandparent (SourceRule) to create the parent index
|
|
grandparent_row = self._source_rules.index(grandparent_item)
|
|
return self.createIndex(parent_row, 0, parent_item) # Create index for the AssetRule parent
|
|
except ValueError:
|
|
return QModelIndex() # Parent AssetRule or Grandparent SourceRule not found in respective lists
|
|
else:
|
|
return QModelIndex() # Grandparent (SourceRule) reference missing
|
|
else:
|
|
return QModelIndex() # Parent AssetRule reference missing
|
|
|
|
return QModelIndex() # Should not be reached
|
|
|
|
|
|
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
|
|
"""Returns the index of the item in the model specified by the given row, column and parent index."""
|
|
if not self.hasIndex(row, column, parent):
|
|
return QModelIndex()
|
|
|
|
parent_item = None
|
|
if not parent.isValid():
|
|
# Parent is invisible root. Children are SourceRules.
|
|
if row < len(self._source_rules):
|
|
child_item = self._source_rules[row]
|
|
return self.createIndex(row, column, child_item)
|
|
else:
|
|
return QModelIndex() # Row out of bounds for top-level items
|
|
else:
|
|
# Parent is a valid index, get its item
|
|
parent_item = parent.internalPointer()
|
|
|
|
child_item = None
|
|
if isinstance(parent_item, SourceRule):
|
|
# Parent is SourceRule. Children are AssetRules.
|
|
if row < len(parent_item.assets):
|
|
child_item = parent_item.assets[row]
|
|
# Ensure parent reference is set
|
|
if not hasattr(child_item, 'parent_source'):
|
|
child_item.parent_source = parent_item
|
|
elif isinstance(parent_item, AssetRule):
|
|
# Parent is AssetRule. Children are FileRules.
|
|
if row < len(parent_item.files):
|
|
child_item = parent_item.files[row]
|
|
# Ensure parent reference is set
|
|
if not hasattr(child_item, 'parent_asset'):
|
|
child_item.parent_asset = parent_item
|
|
|
|
if child_item:
|
|
# Create index for the child item under the parent
|
|
return self.createIndex(row, column, child_item)
|
|
else:
|
|
# Invalid row or parent type has no children (FileRule)
|
|
return QModelIndex()
|
|
|
|
def data(self, index: QModelIndex, role: int = Qt.DisplayRole):
|
|
"""Returns the data stored under the given role for the item referred to by the index."""
|
|
if not index.isValid(): # Check only index validity, data list might be empty but valid
|
|
return None
|
|
|
|
item = index.internalPointer()
|
|
column = index.column()
|
|
|
|
# --- Handle Background Role ---
|
|
if role == Qt.BackgroundRole:
|
|
# item is already fetched at line 172
|
|
if isinstance(item, SourceRule):
|
|
return self.SOURCE_RULE_COLOR # Use the class constant
|
|
elif isinstance(item, AssetRule):
|
|
# Determine effective asset type
|
|
asset_type = item.asset_type_override if item.asset_type_override else item.asset_type
|
|
if asset_type:
|
|
try:
|
|
base_config = load_base_config() # Load base config
|
|
asset_type_definitions = base_config.get('ASSET_TYPE_DEFINITIONS', {}) # Get definitions
|
|
type_info = asset_type_definitions.get(asset_type)
|
|
if type_info:
|
|
hex_color = type_info.get("color")
|
|
if hex_color:
|
|
try:
|
|
return QColor(hex_color)
|
|
except ValueError:
|
|
# Optional: Add logging for invalid hex color
|
|
# print(f"Warning: Invalid hex color '{hex_color}' for asset type '{asset_type}' in config.")
|
|
return None # Fallback for invalid hex
|
|
else:
|
|
# Optional: Add logging for missing color key
|
|
# print(f"Warning: No color defined for asset type '{asset_type}' in config.")
|
|
return None # Fallback if color key missing
|
|
else:
|
|
# Optional: Add logging for missing asset type definition
|
|
# print(f"Warning: Asset type '{asset_type}' not found in ASSET_TYPE_DEFINITIONS.")
|
|
return None # Fallback if type not in config
|
|
except Exception: # Catch errors during config loading
|
|
return None # Fallback on error
|
|
else:
|
|
return None # Fallback if no asset_type determined
|
|
elif isinstance(item, FileRule):
|
|
# Determine effective item type: Prioritize override, then use base type
|
|
effective_item_type = item.item_type_override if item.item_type_override is not None else item.item_type
|
|
if effective_item_type:
|
|
try:
|
|
base_config = load_base_config() # Load base config
|
|
file_type_definitions = base_config.get('FILE_TYPE_DEFINITIONS', {}) # Get definitions
|
|
type_info = file_type_definitions.get(effective_item_type)
|
|
if type_info:
|
|
hex_color = type_info.get("color")
|
|
if hex_color:
|
|
try:
|
|
return QColor(hex_color)
|
|
except ValueError:
|
|
# Optional: Add logging for invalid hex color
|
|
# print(f"Warning: Invalid hex color '{hex_color}' for file type '{item_type}' in config.")
|
|
return None # Fallback for invalid hex
|
|
else:
|
|
# Optional: Add logging for missing color key
|
|
# print(f"Warning: No color defined for file type '{item_type}' in config.")
|
|
return None # Fallback if color key missing
|
|
else:
|
|
# File types often don't have specific colors, so no warning needed unless debugging
|
|
return None # Fallback if type not in config
|
|
except Exception: # Catch errors during config loading
|
|
return None # Fallback on error
|
|
else:
|
|
return None # Fallback if no item_type determined
|
|
else: # Other item types or if item is None
|
|
return None
|
|
|
|
# --- Handle other roles (Display, Edit, etc.) ---
|
|
if isinstance(item, SourceRule):
|
|
if role == Qt.DisplayRole or role == Qt.EditRole: # Combine Display and Edit logic
|
|
if column == self.COL_NAME:
|
|
return Path(item.input_path).name # Display only basename for SourceRule
|
|
elif column == self.COL_SUPPLIER:
|
|
# Return override if set, otherwise the original identifier, else empty string
|
|
display_value = item.supplier_override if item.supplier_override is not None else item.supplier_identifier
|
|
return display_value if display_value is not None else ""
|
|
# Other columns return None or "" for SourceRule in Display/Edit roles
|
|
return None # Default for SourceRule for other roles/columns
|
|
|
|
elif isinstance(item, AssetRule):
|
|
if role == Qt.DisplayRole:
|
|
if column == self.COL_NAME: return item.asset_name
|
|
if column == self.COL_ASSET_TYPE:
|
|
display_value = item.asset_type_override if item.asset_type_override is not None else item.asset_type
|
|
return display_value if display_value else ""
|
|
if column == self.COL_STATUS: return "" # Status (Not handled yet)
|
|
if column == self.COL_OUTPUT_PATH: return "" # Output Path (Not handled yet)
|
|
elif role == Qt.EditRole:
|
|
if column == self.COL_ASSET_TYPE:
|
|
return item.asset_type_override # Return string or None
|
|
return None # Default for AssetRule
|
|
|
|
elif isinstance(item, FileRule):
|
|
if role == Qt.DisplayRole:
|
|
if column == self.COL_NAME: return Path(item.file_path).name # Display only filename
|
|
if column == self.COL_TARGET_ASSET:
|
|
return item.target_asset_name_override if item.target_asset_name_override is not None else ""
|
|
if column == self.COL_ITEM_TYPE:
|
|
# Reverted Logic: Display override if set, otherwise base type. Shows prefixed keys.
|
|
override = item.item_type_override
|
|
initial_type = item.item_type
|
|
|
|
if override is not None:
|
|
return override
|
|
else:
|
|
return initial_type if initial_type else ""
|
|
if column == self.COL_STATUS: return "" # Status (Not handled yet)
|
|
if column == self.COL_OUTPUT_PATH: return "" # Output Path (Not handled yet)
|
|
elif role == Qt.EditRole:
|
|
if column == self.COL_TARGET_ASSET: return item.target_asset_name_override if item.target_asset_name_override is not None else ""
|
|
if column == self.COL_ITEM_TYPE: return item.item_type_override # Return string or None
|
|
return None # Default for FileRule
|
|
|
|
return None # Default return if role/item combination not handled
|
|
|
|
def setData(self, index: QModelIndex, value, role: int = Qt.EditRole) -> bool:
|
|
"""Sets the role data for the item at index to value."""
|
|
if not index.isValid() or role != Qt.EditRole: # Check only index and role
|
|
return False
|
|
|
|
item = index.internalPointer()
|
|
if item is None: # Extra check for safety
|
|
return False
|
|
column = index.column()
|
|
changed = False
|
|
|
|
# --- Handle different item types ---
|
|
if isinstance(item, SourceRule): # If SourceRule is editable
|
|
if column == self.COL_SUPPLIER:
|
|
# Get the new value, strip whitespace, treat empty as None
|
|
new_value = str(value).strip() if value is not None and str(value).strip() else None
|
|
|
|
# Get the original identifier (assuming it exists on SourceRule)
|
|
original_identifier = getattr(item, 'supplier_identifier', None)
|
|
|
|
# If the new value is the same as the original, clear the override
|
|
if new_value == original_identifier:
|
|
new_value = None # Effectively removes the override
|
|
|
|
# Update supplier_override only if it's different
|
|
if item.supplier_override != new_value:
|
|
item.supplier_override = new_value
|
|
changed = True
|
|
|
|
elif isinstance(item, AssetRule):
|
|
if column == self.COL_ASSET_TYPE:
|
|
# Delegate provides string value (e.g., "Surface", "Model") or None
|
|
new_value = str(value) if value is not None else None
|
|
if new_value == "": new_value = None # Treat empty string as None
|
|
# Update asset_type_override
|
|
if item.asset_type_override != new_value:
|
|
item.asset_type_override = new_value
|
|
changed = True
|
|
|
|
elif isinstance(item, FileRule):
|
|
if column == self.COL_TARGET_ASSET: # Target Asset Name Override
|
|
# Ensure value is string or None
|
|
new_value = str(value).strip() if value is not None else None
|
|
if new_value == "": new_value = None # Treat empty string as None
|
|
# Update target_asset_name_override
|
|
if item.target_asset_name_override != new_value:
|
|
old_value = item.target_asset_name_override # Store old value for potential revert/comparison
|
|
item.target_asset_name_override = new_value
|
|
changed = True
|
|
|
|
# --- Start: New Direct Model Restructuring Logic ---
|
|
old_parent_asset = getattr(item, 'parent_asset', None)
|
|
if old_parent_asset: # Ensure we have the old parent
|
|
source_rule = getattr(old_parent_asset, 'parent_source', None)
|
|
if source_rule: # Ensure we have the grandparent
|
|
new_target_name = new_value # Can be None or a string
|
|
|
|
# Get old parent index and source row
|
|
try:
|
|
grandparent_row = self._source_rules.index(source_rule)
|
|
old_parent_row = source_rule.assets.index(old_parent_asset)
|
|
source_row = old_parent_asset.files.index(item)
|
|
old_parent_index = self.createIndex(old_parent_row, 0, old_parent_asset)
|
|
grandparent_index = self.createIndex(grandparent_row, 0, source_rule) # Needed for insert/remove parent
|
|
except ValueError:
|
|
print("Error: Could not find item, parent, or grandparent in model structure during setData.")
|
|
item.target_asset_name_override = old_value # Revert data change
|
|
return False # Indicate failure
|
|
|
|
target_parent_asset = None
|
|
target_parent_index = QModelIndex()
|
|
target_parent_row = -1 # Row within source_rule.assets
|
|
target_row = -1 # Row within target_parent_asset.files
|
|
move_occurred = False # Flag to track if a move happened
|
|
|
|
# 1. Find existing target parent
|
|
if new_target_name: # Only search if a specific target is given
|
|
for i, asset in enumerate(source_rule.assets):
|
|
if asset.asset_name == new_target_name:
|
|
target_parent_asset = asset
|
|
target_parent_row = i
|
|
target_parent_index = self.createIndex(target_parent_row, 0, target_parent_asset)
|
|
break
|
|
|
|
# 2. Handle Move/Creation
|
|
if target_parent_asset:
|
|
# --- Move to Existing Parent ---
|
|
if target_parent_asset != old_parent_asset: # Don't move if target is the same as old parent
|
|
target_row = len(target_parent_asset.files) # Append to the end
|
|
# print(f"DEBUG: Moving {Path(item.file_path).name} from {old_parent_asset.asset_name} ({source_row}) to {target_parent_asset.asset_name} ({target_row})")
|
|
self.beginMoveRows(old_parent_index, source_row, source_row, target_parent_index, target_row)
|
|
# Restructure internal data
|
|
old_parent_asset.files.pop(source_row)
|
|
target_parent_asset.files.append(item)
|
|
item.parent_asset = target_parent_asset # Update parent reference
|
|
self.endMoveRows()
|
|
move_occurred = True
|
|
else:
|
|
# Target is the same as the old parent. No move needed.
|
|
pass
|
|
|
|
elif new_target_name: # Only create if a *new* specific target name was given
|
|
# --- Create New Parent and Move ---
|
|
# print(f"DEBUG: Creating new parent '{new_target_name}' and moving {Path(item.file_path).name}")
|
|
# Create new AssetRule
|
|
new_asset_rule = AssetRule(asset_name=new_target_name)
|
|
new_asset_rule.asset_type = old_parent_asset.asset_type # Copy type from old parent
|
|
new_asset_rule.asset_type_override = old_parent_asset.asset_type_override # Copy override too
|
|
new_asset_rule.parent_source = source_rule # Set parent reference
|
|
|
|
# Determine insertion row for the new parent (e.g., append)
|
|
new_parent_row = len(source_rule.assets)
|
|
# print(f"DEBUG: Inserting new parent at row {new_parent_row} under {Path(source_rule.input_path).name}")
|
|
|
|
# Emit signals for inserting the new parent row
|
|
self.beginInsertRows(grandparent_index, new_parent_row, new_parent_row)
|
|
source_rule.assets.insert(new_parent_row, new_asset_rule) # Insert into data structure
|
|
self.endInsertRows()
|
|
|
|
# Get index for the newly inserted parent
|
|
target_parent_index = self.createIndex(new_parent_row, 0, new_asset_rule)
|
|
target_row = 0 # Insert file at the beginning of the new parent (for signal)
|
|
|
|
# Emit signals for moving the file row
|
|
# print(f"DEBUG: Moving {Path(item.file_path).name} from {old_parent_asset.asset_name} ({source_row}) to new {new_asset_rule.asset_name} ({target_row})")
|
|
self.beginMoveRows(old_parent_index, source_row, source_row, target_parent_index, target_row)
|
|
# Restructure internal data
|
|
old_parent_asset.files.pop(source_row)
|
|
new_asset_rule.files.append(item) # Append is fine, target_row=0 was for signal
|
|
item.parent_asset = new_asset_rule # Update parent reference
|
|
self.endMoveRows()
|
|
move_occurred = True
|
|
|
|
# Update target_parent_asset for potential cleanup check later
|
|
target_parent_asset = new_asset_rule
|
|
|
|
else: # new_target_name is None or empty
|
|
# No move happens when the override is simply cleared.
|
|
pass
|
|
|
|
# 3. Cleanup Empty Old Parent (only if a move occurred and old parent is empty)
|
|
if move_occurred and not old_parent_asset.files:
|
|
# print(f"DEBUG: Removing empty old parent {old_parent_asset.asset_name}")
|
|
try:
|
|
# Find the row of the old parent again, as it might have shifted
|
|
old_parent_row_for_removal = source_rule.assets.index(old_parent_asset)
|
|
# print(f"DEBUG: Removing parent at row {old_parent_row_for_removal} under {Path(source_rule.input_path).name}")
|
|
self.beginRemoveRows(grandparent_index, old_parent_row_for_removal, old_parent_row_for_removal)
|
|
source_rule.assets.pop(old_parent_row_for_removal)
|
|
self.endRemoveRows()
|
|
except ValueError:
|
|
print(f"Error: Could not find old parent '{old_parent_asset.asset_name}' for removal.")
|
|
# Log error, but continue
|
|
else:
|
|
print("Error: Could not find grandparent SourceRule during setData restructuring.")
|
|
item.target_asset_name_override = old_value # Revert
|
|
return False
|
|
else:
|
|
print("Error: Could not find parent AssetRule during setData restructuring.")
|
|
item.target_asset_name_override = old_value # Revert
|
|
return False
|
|
# --- End: New Direct Model Restructuring Logic ---
|
|
elif column == self.COL_ITEM_TYPE: # Item-Type Override
|
|
# Delegate provides string value (e.g., "MAP_COL") or None
|
|
new_value = str(value) if value is not None else None
|
|
if new_value == "": new_value = None # Treat empty string as None
|
|
# Update item_type_override
|
|
if item.item_type_override != new_value:
|
|
log.debug(f"setData COL_ITEM_TYPE: File='{Path(item.file_path).name}', Original Override='{item.item_type_override}', Original Standard='{getattr(item, 'standard_map_type', 'N/A')}', New Value='{new_value}'") # DEBUG LOG - Added getattr for safety
|
|
old_override = item.item_type_override # Store old value for logging
|
|
item.item_type_override = new_value
|
|
changed = True
|
|
|
|
# --- BEGIN FIX: Update standard_map_type ---
|
|
try:
|
|
base_config = load_base_config()
|
|
file_type_definitions = base_config.get('FILE_TYPE_DEFINITIONS', {})
|
|
|
|
# Determine the type to look up (override first, then original)
|
|
type_to_lookup = new_value if new_value is not None else item.item_type
|
|
|
|
new_standard_type = None
|
|
if type_to_lookup:
|
|
type_info = file_type_definitions.get(type_to_lookup)
|
|
if type_info:
|
|
new_standard_type = type_info.get("standard_type")
|
|
# If standard_type itself is missing in the definition, treat as None or keep old? Let's default to None.
|
|
if new_standard_type is None:
|
|
log.warning(f"setData: No 'standard_type' defined for item type '{type_to_lookup}' in FILE_TYPE_DEFINITIONS.")
|
|
else:
|
|
log.warning(f"setData: Item type '{type_to_lookup}' not found in FILE_TYPE_DEFINITIONS.")
|
|
# Fallback: Keep the existing standard_map_type if lookup fails completely
|
|
new_standard_type = getattr(item, 'standard_map_type', None)
|
|
else:
|
|
# If both override and original type are None, standard type should be None
|
|
new_standard_type = None
|
|
|
|
# Update the standard_map_type if it changed or needs setting
|
|
current_standard_type = getattr(item, 'standard_map_type', None)
|
|
if current_standard_type != new_standard_type:
|
|
item.standard_map_type = new_standard_type
|
|
log.debug(f"setData: Updated standard_map_type from '{current_standard_type}' to '{new_standard_type}' for file '{Path(item.file_path).name}' based on type '{type_to_lookup}'")
|
|
# No need to set 'changed = True' again, already set above
|
|
|
|
except Exception as e:
|
|
log.exception(f"setData: Error updating standard_map_type for file '{Path(item.file_path).name}': {e}")
|
|
# --- END FIX ---
|
|
|
|
log.debug(f"setData COL_ITEM_TYPE: File='{Path(item.file_path).name}', Final Override='{item.item_type_override}', Final Standard='{getattr(item, 'standard_map_type', 'N/A')}'") # DEBUG LOG - Updated
|
|
|
|
|
|
if changed:
|
|
# Emit dataChanged for the specific index and affected roles
|
|
self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole])
|
|
return True
|
|
|
|
return False
|
|
|
|
def flags(self, index: QModelIndex) -> Qt.ItemFlags:
|
|
"""Returns the item flags for the given index."""
|
|
if not index.isValid():
|
|
return Qt.NoItemFlags # No flags for invalid index
|
|
|
|
# Start with default flags for a valid item
|
|
default_flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
|
|
item = index.internalPointer()
|
|
column = index.column()
|
|
|
|
can_edit = False
|
|
# Determine editability based on item type and column
|
|
if isinstance(item, SourceRule): # If SourceRule is displayed/editable
|
|
if column == 1: can_edit = True
|
|
elif isinstance(item, AssetRule):
|
|
if column == 2: can_edit = True
|
|
elif isinstance(item, FileRule):
|
|
if column == 3: can_edit = True
|
|
if column == 4: can_edit = True
|
|
|
|
if can_edit:
|
|
return default_flags | Qt.ItemIsEditable
|
|
else:
|
|
return default_flags
|
|
|
|
def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.DisplayRole):
|
|
"""Returns the data for the given role and section in the header."""
|
|
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
|
if 0 <= section < len(self.Columns):
|
|
return self.Columns[section]
|
|
# Optionally handle Vertical header (row numbers)
|
|
# if orientation == Qt.Vertical and role == Qt.DisplayRole:
|
|
# return str(section + 1)
|
|
return None
|
|
|
|
# Helper to get item from index
|
|
def getItem(self, index: QModelIndex):
|
|
"""Safely returns the item associated with the index."""
|
|
if index.isValid():
|
|
item = index.internalPointer()
|
|
if item: # Ensure internal pointer is not None
|
|
return item
|
|
return None # Return None for invalid index or None pointer |