def get_indexes(self): indexes = [] row_count = self.rowCount(QtCore.QModelIndex()) for row in range(row_count): idx = self.index(row, 0, QtCore.QModelIndex()) indexes.append(idx) return indexes
def parent(self, index): item = index.internalPointer() parent_item = item.parent() # If it has no parents we return invalid if parent_item == self._root_item or not parent_item: return QtCore.QModelIndex() return self.createIndex(parent_item.row(), 0, parent_item)
def mousePressEvent(self, event): index = self.indexAt(event.pos()) if not index.isValid(): # clear the selection self.clearSelection() # clear the current index self.setCurrentIndex(QtCore.QModelIndex()) QtWidgets.QTreeView.mousePressEvent(self, event)
def parent(self, index): node = index.internalPointer() parent_node = node.parent() # If it has no parents we return invalid if parent_node == self._root_node or not parent_node: return QtCore.QModelIndex() return self.createIndex(parent_node.row(), 0, parent_node)
def filterAcceptsRow(self, row=0, parent=QtCore.QModelIndex()): model = self.sourceModel() index = model.index(row, 0, parent=parent) # Ensure index is valid if not index.isValid() or index is None: return True node = model.data(index, TreeModel.ItemRole) return node.get("status", 0) > 0
def refresh_side(self, side, profile, host=False): items = self._root_item.children() root_index = QtCore.QModelIndex() # Remove previous data of this side remove = list() for item in items: if item.has_other(side): item.pop_this(side) else: remove.append(item) for item in remove: row = item.row() self.beginRemoveRows(root_index, row, row) items.remove(item) self.endRemoveRows() # Place new data shared_root = self.extract_shared_root(profile) self._origin_shared_root = shared_root for name, data in profile.items(): data["longName"] = data.get("fullPath", name) data["shortName"] = name[len(shared_root):] data["fromHost"] = host if name in items: # Has matched item = items[items.index(name)] item.add_this(side, data, matched=1) item.compare() else: id = data["avalonId"] for item in items: if item.id == id: # Matched by Id item.add_this(side, data, matched=2) item.compare() break else: # No match item = ComparerItem(name, id) item.add_this(side, data) last = self.rowCount(root_index) self.beginInsertRows(root_index, last, last) self.add_child(item) self.endInsertRows()
def _validate_queue_entry(self, entry): """If an entry already exists return false""" parent = QtCore.QModelIndex() for row in range(self.queue_model.rowCount(parent)): idx = self.queue_model.index(row, 0, parent) data = idx.data(self._noderole) if entry == data: self.log.info("Already in queue") return False return True
def on_selected(self, *args, **kwargs): # Sync view selection if not self._selection_sync: return OBJ = { "view": self.widgets["view"], "model": self.widgets["view"].model(), } if not OBJ["model"].rowCount(QtCore.QModelIndex()): return OBJ["view"].clearSelection() selected = set() sel = OpenMaya.MGlobal.getActiveSelectionList() iter = OpenMaya.MItSelectionList(sel) # Loop though iterator objects while not iter.isDone(): try: obj = iter.getDependNode() dagPath = OpenMaya.MDagPath.getAPathTo(obj) fullname = dagPath.fullPathName() except RuntimeError: pass else: selected.add(fullname) finally: iter.next() if not selected: return # Hightlight item selection_model = OBJ["view"].selectionModel() selection = selection_model.selection() for index in tools_lib.iter_model_rows(OBJ["model"], 0): item = index.data(model.SelectionModel.ItemRole) node = item.get("node") if node in selected: selection.select(index, index.sibling(index.row(), 1)) selected.remove(node) if len(selected) == 0: break selection_model.select(selection, selection_model.Select) OBJ["view"].scrollTo(index) # Ensure visible
def index(self, row, column, parent): """Return index for row/column under parent""" if not parent.isValid(): parent_item = self._root_item else: parent_item = parent.internalPointer() child_item = parent_item.child(row) if child_item: return self.createIndex(row, column, child_item) else: return QtCore.QModelIndex()
def _get_queued_items(self): """Get all queued items in form of dictionaries Returns: list """ items = [] parent = QtCore.QModelIndex() for row in range(self.queue_model.rowCount(parent)): idx = self.queue_model.index(row, 0, parent) data = idx.data(self._noderole) items.append(data) return items
def _iter_model_rows(model, column, include_root=False): """Iterate over all row indices in a model""" indices = [QtCore.QModelIndex()] # start iteration at root for index in indices: # Add children to the iterations child_rows = model.rowCount(index) for child_row in range(child_rows): child_index = model.index(child_row, column, index) indices.append(child_index) if not include_root and not index.isValid(): continue yield index
def clear_stage(self): all_nodes = self._root_item.children() if all(n.get("status", 0) == 0 for n in all_nodes): # All staged, clear all self.clear() return # Remove staged only root = QtCore.QModelIndex() for node in list(all_nodes): if node.get("status", 0) == 0: row = node.row() self.beginRemoveRows(root, row, row) all_nodes.remove(node) self.endRemoveRows()
def collected(self, with_keys=None): model = self.data["model"] with_keys = with_keys or list() sequences = dict() root_index = QtCore.QModelIndex() for row in range(model.rowCount(root_index)): index = model.index(row, column=0, parent=root_index) item = index.internalPointer() if all(item.get(k) for k in with_keys): if model._stereo: item["fpattern"] = item["stereoPattern"] if item["name"] not in sequences: sequences[item["name"]] = item return sequences
def __init__(self, data, parent=None): super(CustomListModel, self).__init__(parent) self.items = data index = QtCore.QModelIndex() self.beginInsertRows(index, 0, len(data)) for item in data: self.beginInsertRows(index, 0, 0) pass self.endInsertRows() self.icons = [] app_path = os.path.dirname(os.path.realpath(__file__)) self.icons.append( QtGui.QIcon(os.path.join(app_path, 'res/not_converted.png'))) self.icons.append(QtGui.QIcon(os.path.join(app_path, 'res/source.png'))) self.icons.append(QtGui.QIcon(os.path.join(app_path, 'res/exr.png')))
def filterAcceptsRow(self, row=0, parent=QtCore.QModelIndex()): model = self.sourceModel() index = model.index(row, 0, parent=parent) # Ensure index is valid if not index.isValid() or index is None: return True # Check if index is top node and if it has any children # Get the node data and validate node = model.data(index, self.NodeRole) family = node.get("family", None) if family is None: return True # We want to keep the families which are not in the list return self._filter_family(family)
def _append(self, data): package = PackageItem(data) # Check duplicated all_nodes = self._root_item.children() if package in all_nodes: # If duplicated package has completed, allow to stage # again. find = list(reversed(all_nodes)) if find[find.index(package)]["status"] <= 2: return # Start root = QtCore.QModelIndex() last = self.rowCount(root) self.beginInsertRows(root, last, last) self.add_child(package) self.endInsertRows()
def select_task(self, taskname): """Select task by name Args: taskname(str): name of the task to select Returns: None """ parent = QtCore.QModelIndex() model = self._task_view.model() selectionmodel = self._task_view.selectionModel() for row in range(model.rowCount(parent)): idx = model.index(row, 0, parent) task = idx.data(QtCore.Qt.DisplayRole) if task == taskname: selectionmodel.select(idx, QtCore.QItemSelectionModel.Select) self._task_view.setCurrentIndex(idx) self._last_selected_task = taskname return
def search_channel_name(self, head, tail): if not head and not tail: return pattern = re.compile(".*?%s([0-9a-zA-Z_]*)%s.*" % (head, tail)) root_index = QtCore.QModelIndex() last = self.rowCount(root_index) column = self.Columns.index("name") for row in range(last): index = self.index(row, column=column, parent=root_index) item = index.internalPointer() result = pattern.search(item["fpattern"]) if result and result.groups(): name = pattern.search(item["fpattern"]).group(1) # Arnold light groups if "_lgroups" in item.get("head", ""): name += "_lgroups" self.setData(index, name)
def _remove_selected_queued(self): """Remove selected item(s) from the queue""" model_index = QtCore.QModelIndex() active = self.queue_view.currentIndex() active_row = active.row() items = [] for row in range(self.queue_model.rowCount(model_index)): idx = self.queue_model.index(row, 0, model_index) index_data = idx.data(self._noderole) items.append(index_data) items.pop(active_row) self.queue_model.clear() if not items: self.queue_widgets.setCurrentIndex(0) return self.queue_model.add_items(items)
import logging from collections import defaultdict from avalon.vendor.Qt import QtWidgets, QtCore # TODO: expose this better in avalon core from avalon.tools import lib from avalon.tools.models import TreeModel from . import models from . import commands from . import views from maya import cmds MODELINDEX = QtCore.QModelIndex() class AssetOutliner(QtWidgets.QWidget): refreshed = QtCore.Signal() selection_changed = QtCore.Signal() def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) layout = QtWidgets.QVBoxLayout() title = QtWidgets.QLabel("Assets") title.setAlignment(QtCore.Qt.AlignCenter) title.setStyleSheet("font-weight: bold; font-size: 12px")
def clear_selection(self): flags = self._selection_model.Clear self._selection_model.select(QtCore.QModelIndex(), flags)
def refresh_side(self, side, profile, host=False): profile = profile or dict() items = self._root_item.children() root_index = QtCore.QModelIndex() # Remove previous data of this side to_remove = list() for item in items: if item.has_other(side): item.pop_this(side) else: to_remove.append(item) for item in to_remove: row = item.row() self.beginRemoveRows(root_index, row, row) items.remove(item) self.endRemoveRows() # Place new data not_matched_items = list(items) not_matched_data = list() def short(name): # No namespace return name.rsplit("|", 1)[-1].rsplit(":", 1)[-1] def long(name): # No namespace return "|".join(n.rsplit(":", 1)[-1] for n in name.split("|")) def related(this, that): return this == that or this.endswith(that) or that.endswith(this) for name, data in profile.items(): data = { "fullPath": name, "fromHost": host, "shortName": short(name), "longName": long(name), "avalonId": data["avalonId"], "protected": data.get("protected"), "points": data["points"], "uvmap": data.get("uvmap", ""), } not_matched_data.append(data) not_matched_data.sort(key=lambda d: d["longName"] + d["fullPath"]) for data in list(not_matched_data): # Matching avalonId & longName state = 0 for item in not_matched_items: if item.id == data["avalonId"]: state |= 1 if related(item.name, data["longName"]): state |= 2 if state: not_matched_items.remove(item) not_matched_data.remove(data) item.add_this(side, data, matched=state) item.compare() break for data in list(not_matched_data): # Try matching only by longName state = 0 for item in not_matched_items: if related(item.name, data["longName"]): state |= 2 not_matched_items.remove(item) not_matched_data.remove(data) item.add_this(side, data, matched=state) item.compare() break for data in not_matched_data: # Finally, try matching by shortName for item in not_matched_items: other_side = item[item.get_other(side)] if other_side["shortName"] == data["shortName"]: not_matched_items.remove(item) item.add_this(side, data, matched=0) item.compare() break else: item = ComparerItem(data["longName"], data["avalonId"]) item.add_this(side, data) last = self.rowCount(root_index) self.beginInsertRows(root_index, last, last) self.add_child(item) self.endInsertRows()
def on_changed(self): index_a = self.index(0, 1, QtCore.QModelIndex()) index_b = self.index(1, 1, QtCore.QModelIndex()) # passing `list()` for PyQt5 (see PYSIDE-462) args = () if Qt.IsPySide or Qt.IsPyQt4 else ([],) self.dataChanged.emit(index_a, index_b, *args)
def add_sequence(self, sequence): root_index = QtCore.QModelIndex() last = self.rowCount(root_index) self.beginInsertRows(root_index, last, last) item = models.Item() item.update(sequence) # Must have item["root"] = sequence["root"] item["fpattern"] = sequence["fpattern"] item["paddingStr"] = sequence["paddingStr"] item["frames"] = "%d-%d" % (sequence["start"], sequence["end"]) # Optional item["name"] = sequence.get("name", "") # Collect stereo data even user did not specify def take_side(fpattern): if "Left" in fpattern: return "Left", fpattern.replace("Left", "{stereo}") elif "Right" in fpattern: return "Right", fpattern.replace("Right", "{stereo}") else: return None, fpattern this_side, this_side_p = take_side(item["fpattern"]) if this_side is not None: for row in reversed(range(last)): index = self.index(row, column=0, parent=root_index) other = index.internalPointer() if other.get("stereoSide"): # Paired continue other_side, other_side_p = take_side(other["fpattern"]) if other_side is None: continue if this_side != other_side and this_side_p == other_side_p: item["stereoSide"] = this_side item["stereoPattern"] = this_side_p other["stereoSide"] = other_side other["stereoPattern"] = other_side_p break html_fpattern = "{dir}{head}{padding}{tail}" dir, fname = os.path.split(item["fpattern"]) head, tail = fname.split(item["paddingStr"], 1) padding = item["paddingStr"] dir = "<span style=\"color:#666666\">%s/ </span>" % dir head = "<span style=\"color:#EEEEEE\">%s</span>" % head padding = "<span style=\"color:#666666\">%s</span>" % padding tail = "<span style=\"color:#999999\">%s</span>" % tail item["fpatternHTML"] = html_fpattern.format(dir=dir, head=head, padding=padding, tail=tail) self.add_child(item) self.endInsertRows()