# # Copyright 2016 Pixar # # Licensed under the Apache License, Version 2.0 (the "Apache License") # with the following modification; you may not use this file except in # compliance with the Apache License and the following modification to it: # Section 6. Trademarks. is deleted and replaced with: # # 6. Trademarks. This License does not grant permission to use the trade # names, trademarks, service marks, or product names of the Licensor # and its affiliates, except as required to comply with Section 4(c) of # the License and to reproduce the content of the NOTICE file. # # You may obtain a copy of the Apache License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the Apache License with the above modification is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the Apache License for the specific # language governing permissions and limitations under the Apache License. # from .qt import QtGui, QtWidgets, QtCore from pxr import Sdf from .usdviewContextMenuItem import UsdviewContextMenuItem from .common import (PropertyViewIndex, PropertyViewDataRoles, PrimNotFoundException, PropertyNotFoundException) # # Specialized context menu for running commands in the attribute viewer. # class AttributeViewContextMenu(QtWidgets.QMenu): def __init__(self, parent, item, dataModel): QtWidgets.QMenu.__init__(self, parent) self._menuItems = _GetContextMenuItems(item, dataModel) for menuItem in self._menuItems: # create menu actions if menuItem.isValid() and menuItem.ShouldDisplay(): action = self.addAction(menuItem.GetText(), menuItem.RunCommand) # set enabled if not menuItem.IsEnabled(): action.setEnabled(False) def _GetContextMenuItems(item, dataModel): return [ # Root selection methods CopyAttributeNameMenuItem(dataModel, item), CopyAttributeValueMenuItem(dataModel, item), CopyAllTargetPathsMenuItem(dataModel, item), SelectAllTargetPathsMenuItem(dataModel, item), # Individual/multi target selection menus CopyTargetPathMenuItem(dataModel, item), SelectTargetPathMenuItem(dataModel, item)] def _selectPrimsAndProps(dataModel, paths): prims = [] props = [] for path in paths: primPath = path.GetAbsoluteRootOrPrimPath() prim = dataModel.stage.GetPrimAtPath(primPath) if not prim: raise PrimNotFoundException(primPath) prims.append(prim) if path.IsPropertyPath(): prop = prim.GetProperty(path.name) if not prop: raise PropertyNotFoundException(path) props.append(prop) with dataModel.selection.batchPrimChanges: dataModel.selection.clearPrims() for prim in prims: dataModel.selection.addPrim(prim) with dataModel.selection.batchPropChanges: dataModel.selection.clearProps() for prop in props: dataModel.selection.addProp(prop) dataModel.selection.clearComputedProps() # # The base class for propertyview context menu items. # class AttributeViewContextMenuItem(UsdviewContextMenuItem): def __init__(self, dataModel, item): self._dataModel = dataModel self._item = item self._role = self._item.data(PropertyViewIndex.TYPE, QtCore.Qt.ItemDataRole.WhatsThisRole) self._name = self._item.text(PropertyViewIndex.NAME) if self._item else "" self._value = self._item.text(PropertyViewIndex.VALUE) if self._item else "" def IsEnabled(self): return True def ShouldDisplay(self): return True def GetText(self): return "" def RunCommand(self): pass # # Copy the attribute's name to clipboard. # class CopyAttributeNameMenuItem(AttributeViewContextMenuItem): def ShouldDisplay(self): return self._role not in (PropertyViewDataRoles.TARGET, PropertyViewDataRoles.CONNECTION) def GetText(self): return "Copy Property Name" def RunCommand(self): if self._name == "": return cb = QtWidgets.QApplication.clipboard() cb.setText(self._name, QtGui.QClipboard.Selection) cb.setText(self._name, QtGui.QClipboard.Clipboard) # # Copy the attribute's value to clipboard. # class CopyAttributeValueMenuItem(AttributeViewContextMenuItem): def ShouldDisplay(self): return self._role not in (PropertyViewDataRoles.TARGET, PropertyViewDataRoles.CONNECTION) def GetText(self): return "Copy Property Value" def RunCommand(self): # We display relationships targets as: # /f, /g/a ... # But when we ask to copy the value, we'd like to get back: # [Sdf.Path('/f'), Sdf.Path('/g/a')] # Which is useful for pasting into a python interpreter. if self._role == PropertyViewDataRoles.RELATIONSHIP_WITH_TARGETS: valueStr = str([Sdf.Path("".join(p.split())) \ for p in self._value.split(",")]) else: valueStr = self._value if self._item: rawVal = self._item.rawValue if rawVal is not None: valueStr = str(rawVal) cb = QtWidgets.QApplication.clipboard() cb.setText(valueStr, QtGui.QClipboard.Selection) cb.setText(valueStr, QtGui.QClipboard.Clipboard) # -------------------------------------------------------------------- # Individual target selection menus # -------------------------------------------------------------------- # # Copy the target path to clipboard. # class CopyTargetPathMenuItem(AttributeViewContextMenuItem): def ShouldDisplay(self): return self._role in (PropertyViewDataRoles.TARGET, PropertyViewDataRoles.CONNECTION) def GetText(self): return "Copy Target Path As Text" def GetSelectedOfType(self): getRole = lambda s: s.data(PropertyViewIndex.TYPE, QtCore.Qt.ItemDataRole.WhatsThisRole) return [s for s in self._item.treeWidget().selectedItems() \ if getRole(s) in (PropertyViewDataRoles.TARGET, PropertyViewDataRoles.CONNECTION)] def RunCommand(self): if not self._item: return value = ", ".join([s.text(PropertyViewIndex.NAME) for s in self.GetSelectedOfType()]) cb = QtWidgets.QApplication.clipboard() cb.setText(value, QtGui.QClipboard.Selection) cb.setText(value, QtGui.QClipboard.Clipboard) # # Jump to the target path in the prim browser # This will include all other highlighted paths of this type, if any. # class SelectTargetPathMenuItem(CopyTargetPathMenuItem): def GetText(self): return "Select Target Path" def RunCommand(self): paths = [Sdf.Path(s.text(PropertyViewIndex.NAME)) for s in self.GetSelectedOfType()] _selectPrimsAndProps(self._dataModel, paths) # -------------------------------------------------------------------- # Target owning property selection menus # -------------------------------------------------------------------- def _GetTargetPathsForItem(item): paths = [Sdf.Path(item.child(i).text(PropertyViewIndex.NAME)) for i in range (0, item.childCount())] # If there are no children, the value column must hold a valid path # (since the command is enabled). if len(paths) == 0: itemText = item.text(PropertyViewIndex.VALUE) if len(itemText) > 0: paths.append(Sdf.Path(itemText)) return paths # # Select all target paths under the selected attribute # class SelectAllTargetPathsMenuItem(AttributeViewContextMenuItem): def ShouldDisplay(self): return (self._role == PropertyViewDataRoles.RELATIONSHIP_WITH_TARGETS or self._role == PropertyViewDataRoles.ATTRIBUTE_WITH_CONNNECTIONS) def IsEnabled(self): if not self._item: return False # Enable the menu item if there are one or more targets for this # rel/attribute connection if self._item.childCount() > 0: return True # Enable the menu if the item holds a valid SdfPath. itemText = self._item.text(2) return Sdf.Path.IsValidPathString(itemText) def GetText(self): return "Select Target Path(s)" def RunCommand(self): if not self._item: return _selectPrimsAndProps(self._dataModel, _GetTargetPathsForItem(self._item)) # # Copy all target paths under the currently selected relationship to the clipboard # class CopyAllTargetPathsMenuItem(SelectAllTargetPathsMenuItem): def GetText(self): return "Copy Target Path(s) As Text" def RunCommand(self): if not self._item: return value = ", ".join(_GetTargetPathsForItem(self._item)) cb = QtWidgets.QApplication.clipboard() cb.setText(value, QtGui.QClipboard.Selection) cb.setText(value, QtGui.QClipboard.Clipboard)