Source code for cgl.ui.widgets.containers.model

import logging
import re
from typing import List, Union, Optional

from PySide6 import QtGui
from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex
from cgl.core.config.query import AlchemyConfigManager

CFG = AlchemyConfigManager()


[docs] class LJItemModel(QAbstractTableModel):
[docs] def headerData(self, section, orientation, role): try: if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self.headers[section] except IndexError: logging.debug("IndexError in headerData")
[docs] def rowCount(self, index): if self.data_: return len(self.data_) else: return 0
[docs] def columnCount(self, index): return len(self.headers)
[docs] def data(self, index, role=Qt.DisplayRole): if not index.isValid(): return None if role == Qt.DisplayRole: return self._data[index.row()][index.column()] return None
[docs] def clear_data(self): self.beginResetModel() # Notify views and delegates that model data will be cleared self._data = [] # Clear the data self.endResetModel() # Notify views and delegates that model data is cleared
[docs] class LGListDictionaryItemModel(LJItemModel): def __init__(self, data): LJItemModel.__init__(self) self.headers = [] self.data_ = [] if data: self.data_ = data self.keys = data[0].keys()
[docs] def data(self, index, role): row = index.row() key = self.keys[index.column()] if role == Qt.DisplayRole: return str(self.data_[row][key])
[docs] class LGShotgunListDictionaryItemModel(LGListDictionaryItemModel): def __init__(self, data, display_filter=None): LJItemModel.__init__(self) self.headers = [] self.data_ = [] self.keys = [] self.data_filter = False if data: self.data_ = data self.data_filter = True if display_filter: for key in display_filter: self.keys = display_filter.keys() self.headers.append(display_filter[key]) else: self.keys = data[0].keys() for key in self.keys: self.headers.append( key.replace("sg_", "").replace("_", " ").title_label() )
[docs] def data(self, index, role): row = index.row() key = self.keys[index.column()] if role == Qt.DisplayRole: try: data = self.data_[row][key] if data is None: return "" if isinstance(data, dict): if "name" in data: return data["name"] elif "code" in data: return data["code"] return str(data) except KeyError: return ""
[docs] class DictionaryItemModel(LJItemModel): def __init__(self, dict_, header_titles=None): LJItemModel.__init__(self) self.data_ = dict_ if header_titles is None: header_titles = ["key", "value"] self.headers = header_titles
[docs] def data(self, index, role): row = index.row() col = index.column() if role == Qt.DisplayRole: if col == 0: return self.data_.keys()[row] elif col == 1: return self.data_.values()[row] return
[docs] class ListItemModel(LJItemModel): """ ListItemModel is a custom model for a Qt-based application that inherits from the LJItemModel class. This model is designed to be used with Qt views (e.g., QTableView, QListView) to display data in a structured way with an icon in the first column. """ def __init__( self, data_list: List[List[Union[dict, QtGui.QPixmap, str]]], header_titles: Optional[List[str]] = None, data_filter: bool = False, icon_height: int = 30, ): """ Initializes the ListItemModel with the provided data and optional parameters. Args: data_list (List[List[Union[dict, QtGui.QPixmap, str]]]): A list of data to be displayed in the view. header_titles (Optional[List[str]], optional): A list of column headers. Defaults to None. data_filter (bool, optional): A boolean flag to indicate whether the model should have a filter. Defaults to False. icon_height (int, optional): The height of the icon to be displayed in the first column. Defaults to 30. """ LJItemModel.__init__(self) if header_titles is None: header_titles = [] self.data_ = data_list self.headers = header_titles self.data_filter = data_filter self.icon_height = icon_height
[docs] def columnCount(self, parent=None) -> int: """ Returns the number of columns in the model. Args: parent (optional): The parent QModelIndex. Defaults to None. Returns: int: The number of columns in the model, which is 2 in this case. """ return len(self.headers)
[docs] def data( self, index: QModelIndex, role: int ) -> Optional[Union[QtGui.QPixmap, str]]: """ Provides the appropriate data based on the given QModelIndex `index` and the role `role`. Args: index (QModelIndex): The QModelIndex of the data. role (int): The role of the data (e.g., Qt.DisplayRole, Qt.DecorationRole). Returns: Optional[Union[QtGui.QPixmap, str]]: The data to be displayed or decorated, or None if not applicable. """ col = index.column() if col == 1: return self._handle_icon_column(index, role) else: return self._handle_data_column(index, role)
[docs] def clear_data(self): print("clearing data") self.beginResetModel() # Notify views and delegates that model data will be cleared self.data_ = [] # Clear the data self.endResetModel() # Notify views and delegates that model data is cleared
def _handle_icon_column( self, index: QModelIndex, role: int ) -> Optional[QtGui.QPixmap]: if role == Qt.DecorationRole: row = index.row() # icon_path = str(self.data_[row][1]) icon_path = str(self.data_[row][0]) self.icon_pixmap = QtGui.QPixmap(icon_path) self.scaled_icon_pixmap = self.icon_pixmap.scaledToHeight( self.icon_height, Qt.SmoothTransformation ) return self.scaled_icon_pixmap else: return None def _handle_data_column(self, index: QModelIndex, role: int) -> Optional[str]: row = index.row() col = index.column() # check if data is a list of list # logging.debug(f"data being handled on column is {self.data_}") data = self.data_[row][col] if role == Qt.DisplayRole: return self._format_data_for_display(data) elif role == Qt.DecorationRole: if isinstance(data, QtGui.QPixmap): return data return None @staticmethod def _format_data_for_display(data: Union[dict, QtGui.QPixmap, str]) -> str: if data is None: return "" if isinstance(data, dict): if "name" in data: return data["name"] elif "code" in data: return data["code"] if isinstance(data, QtGui.QPixmap): return "" return str(data) @staticmethod def _format_data_for_display(data: Union[dict, QtGui.QPixmap, str]) -> str: if data is None: return "" if isinstance(data, dict): if "name" in data: return data["name"] elif "code" in data: return data["code"] if isinstance(data, QtGui.QPixmap): return "" return str(data)
[docs] class TreeItemModel(LJItemModel): def __init__(self, data_list, header_titles=None, data_filter=False): super().__init__() self.data_ = data_list self.headers = header_titles self.data_filter = data_filter
[docs] def data(self, index, role): row = index.row() col = index.column() if role == Qt.DisplayRole: try: data = self.data_[row][col] if data is None: return "" if isinstance(data, dict): if "name" in data: return data["name"] elif "code" in data: return data["code"] return str(data) except KeyError: return ""
[docs] class FileTableModel(ListItemModel):
[docs] def data(self, index, role): row = index.row() col = index.column() if role == Qt.DisplayRole: return self.data_[row][col]
# if role == Qt.DecorationRole: # logging.info("Decoration Role", self.data_[row][col]) # keeping this here for reference # data = self.data_[row][col]
[docs] class FilesModel(QAbstractTableModel): def __init__( self, data_list, header_titles=None, data_filter=False, path_object=None, cfg=None, ): QAbstractTableModel.__init__(self) # self.setHeaderData(Qt.Horizontal, Qt.AlignLeft, Qt.TextAlignmentRole) # self.setHeaderData(Qt.Horizontal, Qt.AlignLeft, Qt.TextAlignmentRole) self.path_object = path_object self.data_ = data_list self.headers = header_titles self.data_filter = data_filter
[docs] def data(self, index, role): try: data = self.data_[index.row()][index.column()] if role == Qt.DisplayRole: if data is None: return "" elif isinstance(data, dict): if "name" in data: return data["name"] elif "code" in data: return data["code"] return data if role == Qt.DecorationRole: if "." not in data: icon_path_ = CFG.get_icon_path("folder24px.png") return QtGui.QIcon(icon_path_) if role == Qt.ForegroundRole: padding_difference = self.has_approved_frame_padding(data) if padding_difference: logging.info( "Padding {} does not match studio padding {}".format( padding_difference[0], padding_difference[1] ) ) return QtGui.QColor("red") except KeyError: return ""
[docs] def has_approved_frame_padding(self, filename): hashes = re.compile("#+") m = re.search(hashes, filename) if m: this_padding = int(len(m.group())) studio_padding = int(CFG.project_config["default"]["padding"]) if this_padding == studio_padding: return 0 else: return [this_padding, studio_padding]
[docs] def headerData(self, section, orientation, role): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self.headers[section]
[docs] def rowCount(self, index): if self.data_: return len(self.data_) else: return 0
[docs] def columnCount(self, index): return len(self.headers) + 1