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
class SelectorWidget(QtWidgets.QWidget): container_picked = QtCore.Signal(str, dict) host_selected = QtCore.Signal(str) version_changed = QtCore.Signal(str, io.ObjectId) def __init__(self, side, parent=None): super(SelectorWidget, self).__init__(parent=parent) def icon(name): return qtawesome.icon("fa.{}".format(name), color=SIDE_COLOR[side]) body = { "tab": QtWidgets.QTabWidget(), } selector = { "host": HostSelectorWidget(), "databse": DatabaseSelectorWidget(), } body["tab"].addTab(selector["databse"], icon("cloud"), "Published") body["tab"].addTab(selector["host"], icon("home"), "In Scene") layout = QtWidgets.QHBoxLayout(self) layout.addWidget(body["tab"]) # Connect selector["host"].container_picked.connect(self.on_container_picked) selector["host"].host_selected.connect(self.on_host_selected) selector["databse"].version_changed.connect(self.on_version_changed) # Init self.selector = selector self.side = side if not has_host() or side == SIDE_B: body["tab"].setCurrentIndex(0) else: body["tab"].setCurrentIndex(1) def connect_comparer(self, comparer): self.container_picked.connect(comparer.on_container_picked) self.host_selected.connect(comparer.on_host_selected) self.version_changed.connect(comparer.on_version_changed) def on_container_picked(self, container): self.container_picked.emit(self.side, container) def on_host_selected(self): self.host_selected.emit(self.side) def on_version_changed(self, version_id): self.version_changed.emit(self.side, version_id)
def calculate_window_geometry(self): """Respond to status changes On creation, align window with screen bottom right. """ window = self width = window.width() width = max(width, window.minimumWidth()) height = window.height() height = max(height, window.sizeHint().height()) desktop_geometry = QtWidgets.QDesktopWidget().availableGeometry() screen_geometry = window.geometry() screen_width = screen_geometry.width() screen_height = screen_geometry.height() # Calculate width and height of system tray systray_width = screen_geometry.width() - desktop_geometry.width() systray_height = screen_geometry.height() - desktop_geometry.height() padding = 10 x = screen_width - width y = screen_height - height x -= systray_width + padding y -= systray_height + padding return QtCore.QRect(x, y, width, height)
class ResolutionDelegate(QtWidgets.QStyledItemDelegate): # DEPRECATED value_changed = QtCore.Signal(list) def displayText(self, value, locale): return "{} x {}".format(*value) def createEditor(self, parent, option, index): editor = ResolutionEditor(parent) def commit_data(value): self.commitData.emit(editor) # Update model data self.value_changed.emit(value) editor.value_changed.connect(commit_data) return editor def setEditorData(self, editor, index): value = index.data(QtCore.Qt.DisplayRole) editor.set_value(value) def setModelData(self, editor, model, index): value = editor.get_value() model.setData(index, value) def updateEditorGeometry(self, editor, option, index): editor.setGeometry(option.rect)
class NameEditDelegate(QtWidgets.QStyledItemDelegate): name_changed = QtCore.Signal() def displayText(self, value, locale): return value def createEditor(self, parent, option, index): editor = QtWidgets.QLineEdit(parent) def commit_data(): self.commitData.emit(editor) # Update model data self.name_changed.emit() # Display model data editor.editingFinished.connect(commit_data) return editor def setEditorData(self, editor, index): value = index.data(QtCore.Qt.DisplayRole) editor.setText(value) def setModelData(self, editor, model, index): name = editor.text() model.setData(index, name) def updateEditorGeometry(self, editor, option, index): editor.setGeometry(option.rect)
def copy_file_to_clipboard(path): from avalon.vendor.Qt import QtCore, QtWidgets app = QtWidgets.QApplication.instance() assert app, "Must have running QApplication instance" # Build mime data for clipboard file_path = QtCore.QUrl.fromLocalFile(path) byte_array = QtCore.QByteArray("copy\n").append(file_path) mime = QtCore.QMimeData() mime.setData("text/uri-list", byte_array) # Set to Clipboard clipboard = app.clipboard() clipboard.setMimeData(mime)
class MatchOutliner(QtWidgets.QWidget): selection_changed = QtCore.Signal() def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) # look manager layout layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(10) # Looks from database title = QtWidgets.QLabel("Matches:") title.setAlignment(QtCore.Qt.AlignLeft) title.setStyleSheet("font-weight: bold; font-size: 12px") model = models.MatchModel() view = views.View() view.setModel(model) view.setSortingEnabled(False) view.setHeaderHidden(True) view.setMinimumHeight(180) view.setIndentation(10) layout.addWidget(title) layout.addWidget(view) selection_model = view.selectionModel() selection_model.selectionChanged.connect(self.selection_changed) self.view = view self.model = model self._selection_model = selection_model def clear(self): self.model.clear() def add_items(self, items): self.model.add_items(items) def clear_selection(self): flags = self._selection_model.Clear self._selection_model.select(QtCore.QModelIndex(), flags) def select_index(self, index, flags=None): flags = flags or self._selection_model.ClearAndSelect self._selection_model.select(index, flags) def get_selected_items(self): """Get current selected items from view Returns: list: list of dictionaries """ datas = [i.data(NODEROLE) for i in self.view.get_indices()] items = [d for d in datas if d is not None] # filter Nones return items
def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) # look manager layout layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(10) # Looks from database title = QtWidgets.QLabel("Looks") title.setAlignment(QtCore.Qt.AlignCenter) title.setStyleSheet("font-weight: bold; font-size: 12px") title.setAlignment(QtCore.Qt.AlignCenter) model = models.LookModel() # Proxy for dynamic sorting proxy = QtCore.QSortFilterProxyModel() proxy.setSourceModel(model) view = views.View() view.setModel(proxy) view.setMinimumHeight(180) view.setToolTip("Use right mouse button menu for direct actions") view.customContextMenuRequested.connect(self.right_mouse_menu) view.sortByColumn(0, QtCore.Qt.AscendingOrder) layout.addWidget(title) layout.addWidget(view) self.view = view self.model = model
class Navigation(QtWidgets.QWidget): """Navigation panel widget""" index_changed = QtCore.Signal(int) log = logging.getLogger("Navigation") def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent=parent) # self.setWindowFlag() self.setStyleSheet(style.flat_button) layout = QtWidgets.QVBoxLayout() dynamic_layout = QtWidgets.QVBoxLayout() static_layout = QtWidgets.QVBoxLayout() static_layout.addStretch() layout.addLayout(dynamic_layout) layout.addStretch() layout.addLayout(static_layout) self.dynamic_layout = dynamic_layout self.static_layout = static_layout self.setLayout(layout) self.layout = layout def add_button(self, label, order, widget=None): """Add a button to the navigation panel with the given label and order Args: label(str): Name displayed on the button order(int): Number which dictates its order in the panel widget(QtWidgets.QWidget): Instance of a widget Returns: None """ if order < 0: layout = self.static_layout else: layout = self.dynamic_layout # Check new position widget_at_item = layout.itemAt(abs(order)) if widget_at_item: self.log.warning("Found multiple items for the same order: `%i`" % order) return button = QtWidgets.QPushButton(label) if widget: button.clicked.connect(partial(widget.show)) layout.insertWidget(order, button) return button
def __init__(self, parent=None): super(ComparingTable, self).__init__(parent=parent) data = { "model": models.ComparerModel(), "proxy": QtCore.QSortFilterProxyModel(), "view": QtWidgets.QTreeView(), "diff": delegates.DiffDelegate(), "path": delegates.PathTextDelegate(), } data["view"].setIndentation(20) data["view"].setStyleSheet(""" QTreeView::item{ padding: 6px 1px; border: 0px; } """) data["view"].setContextMenuPolicy(QtCore.Qt.CustomContextMenu) data["view"].setAllColumnsShowFocus(True) data["view"].setAlternatingRowColors(True) data["view"].setSortingEnabled(True) data["view"].setSelectionBehavior( QtWidgets.QAbstractItemView.SelectItems) data["view"].setSelectionMode( QtWidgets.QAbstractItemView.ExtendedSelection) header = data["view"].header() header.setMinimumSectionSize(delegates.DiffDelegate.ICON_SPACE) # Delegate diff_delegate = data["diff"] column = data["model"].Columns.index("diff") data["view"].setItemDelegateForColumn(column, diff_delegate) path_delegate = data["path"] column = data["model"].Columns.index(SIDE_A) data["view"].setItemDelegateForColumn(column, path_delegate) column = data["model"].Columns.index(SIDE_B) data["view"].setItemDelegateForColumn(column, path_delegate) # Set Model data["proxy"].setSourceModel(data["model"]) data["view"].setModel(data["proxy"]) layout = QtWidgets.QHBoxLayout(self) layout.addWidget(data["view"]) # Connect data["view"].customContextMenuRequested.connect(self.on_context_menu) # Init data["view"].setColumnWidth(0, 90) # "diff" column data["view"].setColumnWidth(1, 310) # "side A" column self.data = data
def _parseMapString(exprText): """Return a list of map file item from expression in an object attribute This function was modified from `ExpressionUI.parseMapString`. """ from xgenm.ui.widgets.xgExpressionUI import ExpressionUI # vmap and map expressions mapExprStrings = _getMapExprStrings() exprStrings = [ [mapExprStrings[0], "3dpaint"], [mapExprStrings[1], "file"], [mapExprStrings[2], "vpaint"], [mapExprStrings[3], ""], # map() without comment [mapExprStrings[4], ""], # vmap() without comment [mapExprStrings[5], "_plain"], # plain map(), no comment [mapExprStrings[6], "_plain"], # plain vmap(), no comment ] poses = [] retMaps = [] for s in exprStrings: re = QtCore.QRegExp(s[0]) offset = 0 while True: item = ExpressionUI.MapItem() pos = re.indexIn(exprText, offset) if (pos < 0): break offset = pos + 1 if pos in poses: # Possible already matched via previous regex if current # regex does no matching comment string. continue poses.append(pos) if s[1] == "_plain": item.name = "" item.file = re.cap(1) item.mode = "" else: item.name = re.cap(1) item.file = re.cap(2) item.mode = s[1] if s[1] == "3dpaint": item.mode = item.mode + "," + re.cap(3) item.pos = pos retMaps.append(item) return retMaps
def data(self, index, role=None): if not index.isValid() or not (0 <= index.row() < len(self.items)): return QtCore.QVariant() if role == QtCore.Qt.DisplayRole: return self.items[index.row()][1] elif role == QtCore.Qt.DecorationRole: return self.icons[self.items[index.row()][0]] elif role == QtCore.Qt.UserRole: return self.items[index.row()]
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 resizeEvent(self, event=None): ''' Helps resize shadow widget ''' position_x = (self.frameGeometry().width() - self.shadow_widget.frameGeometry().width()) / 2 position_y = (self.frameGeometry().height() - self.shadow_widget.frameGeometry().height()) / 2 self.shadow_widget.move(position_x, position_y) w = self.frameGeometry().width() h = self.frameGeometry().height() self.shadow_widget.resize(QtCore.QSize(w, h)) if event: super().resizeEvent(event)
def copy_file_to_clipboard(path): from avalon.vendor.Qt import QtCore, QtWidgets clipboard = QtWidgets.QApplication.clipboard() assert clipboard, "Must have running QApplication instance" # Build mime data for clipboard data = QtCore.QMimeData() url = QtCore.QUrl.fromLocalFile(path) data.setUrls([url]) # Set to Clipboard clipboard.setMimeData(data)
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 main(launch_args): # Be sure server won't crash at any moment but just print traceback sys.excepthook = safe_excepthook # Create QtApplication for tools # - QApplicaiton is also main thread/event loop of the server qt_app = QtWidgets.QApplication([]) # Execute pipeline installation api.install(tvpaint) # Create Communicator object and trigger launch # - this must be done before anything is processed communicator = CommunicationWrapper.create_communicator(qt_app) communicator.launch(launch_args) def process_in_main_thread(): """Execution of `MainThreadItem`.""" item = communicator.main_thread_listen() if item: item.execute() timer = QtCore.QTimer() timer.setInterval(100) timer.timeout.connect(process_in_main_thread) timer.start() # Register terminal signal handler def signal_handler(*_args): print("You pressed Ctrl+C. Process ended.") communicator.stop() signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) qt_app.setQuitOnLastWindowClosed(False) qt_app.setStyleSheet(style.load_stylesheet()) # Load avalon icon icon_path = get_icon_path() if icon_path: icon = QtGui.QIcon(icon_path) qt_app.setWindowIcon(icon) # Set application name to be able show application icon in task bar if platform.system().lower() == "windows": ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID( u"WebsocketServer") # Run Qt application event processing sys.exit(qt_app.exec_())
def __init__(self, parent=None): super(SequenceWidget, self).__init__(parent=parent) data = { "model": SequenceModel(), "proxy": QtCore.QSortFilterProxyModel(), "view": QtWidgets.QTreeView(), "fpatternDel": None, "nameDel": None, } data["proxy"].setSourceModel(data["model"]) data["view"].setModel(data["proxy"]) data["fpatternDel"] = delegates.LineHTMLDelegate(data["view"]) data["nameDel"] = delegates.NameEditDelegate() fpattern_delegate = data["fpatternDel"] column = data["model"].Columns.index("fpattern") data["view"].setItemDelegateForColumn(column, fpattern_delegate) name_delegate = data["nameDel"] column = data["model"].Columns.index("name") data["view"].setItemDelegateForColumn(column, name_delegate) data["proxy"].setSortCaseSensitivity(QtCore.Qt.CaseInsensitive) data["view"].setContextMenuPolicy(QtCore.Qt.CustomContextMenu) data["view"].setSelectionMode(ExtendedSelection) data["view"].setSortingEnabled(True) data["view"].sortByColumn(0, QtCore.Qt.AscendingOrder) data["view"].setAlternatingRowColors(True) data["view"].setAllColumnsShowFocus(True) data["view"].setIndentation(6) data["view"].setStyleSheet(""" QTreeView::item{ padding: 8px 1px; border: 0px; } """) data["view"].setColumnWidth(0, 360) # fpattern data["view"].setColumnWidth(1, 100) # name data["view"].setColumnWidth(2, 80) # frames layout = QtWidgets.QVBoxLayout(self) layout.addWidget(data["view"]) layout.setContentsMargins(0, 0, 0, 0) data["view"].customContextMenuRequested.connect(self.on_context_menu) self.data = data
def copy_id_to_clipboard(path): from avalon.vendor.Qt import QtCore, QtWidgets app = QtWidgets.QApplication.instance() assert app, "Must have running QApplication instance" # Build mime data for clipboard mime = QtCore.QMimeData() mime.setText(path) mime.setUrls([QtCore.QUrl.fromLocalFile(path)]) # Set to Clipboard clipboard = app.clipboard() clipboard.setMimeData(mime)
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 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 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 _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
class View(QtWidgets.QTreeView): data_changed = QtCore.Signal() def __init__(self, parent=None): super(View, self).__init__(parent=parent) # view settings self.setAlternatingRowColors(False) self.setSortingEnabled(True) self.setSelectionMode(self.SingleSelection) self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) def get_indices(self): """Get the selected rows""" selection_model = self.selectionModel() return selection_model.selectedRows()