def addHandlerRules(self, module, handlersList=[], *args, **kwargs): ''' This method is used to add handler rules (renaming rule, deleting rule, ...) . @module module: module object to apply rules to. @handlersList list: a list of handlers to the module. ''' for handler in handlersList: self.addPartialRules(module, [partial(handler, *args, **kwargs)])
def connect_keys(self): if not self.editable_labels or self._keys_connections: return keys_connect = {} # Go through all the controller widget controls for control_name, control_groups in six.iteritems(self._controls): for group_name, control in six.iteritems(control_groups): hook1 = partial(self.__class__._key_modified, weakref.proxy(self), control_name) hook2 = partial(self.__class__._delete_key, weakref.proxy(self), control_name) #control = self._controls[control_name] label_control = control[3] if isinstance(label_control, tuple): label_control = label_control[0] label_control.userModification.connect(hook1) label_control.buttonPressed.connect(hook2) keys_connect[control_name] = (label_control, hook1, hook2) self._keys_connections = keys_connect
def loadUi(ui_file, *args, **kwargs): '''Load a ``.ui`` file and returns the widget instance. This function is a replacement of PyQt4.uic.loadUi. The only difference is that relative icon or pixmap file names that are stored in the ``*.ui`` file are considered to be relative to the directory containing the ui file. With PyQt4.uic.loadUi, relative file names are considered relative to the current working directory therefore if this directory is not the one containing the ui file, icons cannot be loaded. ''' from . import QtGui if get_qt_backend() in ('PyQt4', 'PyQt5'): # the problem is corrected in version > 4.7.2, from . import QtCore if QtCore.PYQT_VERSION > 0x040702: from . import uic return uic.loadUi(ui_file, *args, **kwargs) else: # needed import and def from .uic.Loader import loader if not hasattr(globals(), 'partial'): from soma.functiontools import partial def _iconset(self, prop): return QtGui.QIcon( os.path.join(self._basedirectory, prop.text).replace("\\", "\\\\")) def _pixmap(self, prop): return QtGui.QPixmap( os.path.join(self._basedirectory, prop.text).replace("\\", "\\\\")) uiLoader = loader.DynamicUILoader() uiLoader.wprops._basedirectory = os.path.dirname( os.path.abspath(ui_file)) uiLoader.wprops._iconset = partial(_iconset, uiLoader.wprops) uiLoader.wprops._pixmap = partial(_pixmap, uiLoader.wprops) return uiLoader.loadUi(ui_file, *args, **kwargs) else: from PySide.QtUiTools import QUiLoader return QUiLoader().load(ui_file) # , *args, **kwargs )
def _create_group_widget(self, group): group_widget = QtGui.QGroupBox() last_row = self._grid_layout.rowCount() self._grid_layout.addWidget(group_widget, last_row, 0, 1, 2) lay1 = QtGui.QVBoxLayout() lay1.setContentsMargins(0, 0, 0, 0) lay2 = QtGui.QHBoxLayout() lay1.addLayout(lay2) lay2.setContentsMargins(10, 0, 0, 0) lay2.addWidget(QtGui.QLabel('<html><em>%s</em></html>' % group)) lay2.addStretch(1) icon = QtGui.QIcon() icon.addPixmap( QtGui.QPixmap(_fromUtf8(":/soma_widgets_icons/nav_down")), QtGui.QIcon.Normal, QtGui.QIcon.Off) group_widget.fold_button = QtGui.QPushButton(icon, '') group_widget.fold_button.setFixedSize(30, 20) lay2.addWidget(group_widget.fold_button) widget = QtGui.QWidget() group_widget.setLayout(lay1) lay1.addWidget(widget) group_widget.hideable_widget = widget layout = QtGui.QGridLayout() widget.setLayout(layout) layout.setAlignment(QtCore.Qt.AlignTop) layout.setSpacing(3) layout.setContentsMargins(5, 5, 5, 5) group_widget.setAlignment(QtCore.Qt.AlignLeft) visible_groups = getattr(self.controller, 'visible_groups', set()) if group in visible_groups: show = True else: show = False group_widget.hideable_widget.setVisible(show) if not show: icon = QtGui.QIcon() icon.addPixmap( QtGui.QPixmap(_fromUtf8(":/soma_widgets_icons/nav_right")), QtGui.QIcon.Normal, QtGui.QIcon.Off) group_widget.fold_button.setIcon(icon) #group_widget.fold_button.clicked.connect(SomaPartial( #self._toggle_group_visibility, group)) # FIXME: if we use this, self gets deleted somewhere. This is not # normal. group_widget.fold_button.clicked.connect( partial(self.__class__._toggle_group_visibility, weak_proxy(self), group)) return group_widget
def connect(self): """ Connect the controller trait and the controller widget controls At the end al control will be connected with the associated trait, and when a 'user_traits_changed' signal is emited, the controls are updated (ie, deleted if necessary). """ # If the controller and controller widget are not yet connected if not self.connected: # Go through all the controller widget controls for control_name, control_groups in six.iteritems(self._controls): for group_name, control in six.iteritems(control_groups): # Unpack the control item trait, control_class, control_instance, control_label \ = control # Call the current control specific connection method logger.debug("Connecting control '{0}: {1}'...".format( control_name, control_instance)) control_class.connect(self, control_name, control_instance) # Add an event connected with the 'user_traits_changed' controller # signal: update the controls self.controller.on_trait_change(self.update_controls, "user_traits_changed", dispatch='ui') # if 'visible_groups' is a trait, connect it to groups if self.controller.trait('visible_groups'): self.controller.on_trait_change(self.groups_vibility_changed, 'visible_groups', dispatch='ui') # Update the controller widget values self.update_controller_widget() # notifications should be removed when the GUI is destroyed # (on C++ side) self.destroyed.connect( partial(self.static_disconnect, self.controller, self.update_controls, self.groups_vibility_changed, self._controls)) # Update the connection status self.connected = True
def __getattr__(self, name): value = ThreadSafeProxy.pyroThreadCall(getattr, self._proxy, name) if isinstance(value, Pyro.core._RemoteMethod) or inspect.ismethod(value): return partial(ThreadSafeProxy.pyroThreadCall, value) return value
def create_widget(parent, control_name, control_value, trait, label_class=None): """ Method to create the controller widget. Parameters ---------- parent: QWidget (mandatory) the parent widget control_name: str (mandatory) the name of the control we want to create control_value: instance of Controller (mandatory) the default control value trait: Tait (mandatory) the trait associated to the control label_class: Qt widget class (optional, default: None) the label widget will be an instance of this class. Its constructor will be called using 2 arguments: the label string and the parent widget. Returns ------- out: 2-uplet a two element tuple of the form (control widget: , associated labels: (a label QLabel, the tools QWidget)) """ # Create the list widget: a frame frame = QtGui.QFrame(parent=parent) frame.setFrameShape(QtGui.QFrame.StyledPanel) # Create tools to interact with the list widget: expand or collapse - # add a list item - remove a list item tool_widget = QtGui.QWidget(parent) layout = QtGui.QHBoxLayout() layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) tool_widget.setLayout(layout) # Create the tool buttons resize_button = QtGui.QToolButton() layout.addWidget(resize_button) # Set the tool icons icon = QtGui.QIcon() icon.addPixmap( QtGui.QPixmap(_fromUtf8(":/soma_widgets_icons/nav_down")), QtGui.QIcon.Normal, QtGui.QIcon.Off) resize_button.setIcon(icon) resize_button.setFixedSize(30, 22) editable_labels = False if trait.handler.inner_traits(): editable_labels = True frame.inner_trait = trait.handler.inner_traits()[0] add_button = QtGui.QToolButton() delete_button = QtGui.QToolButton() layout.addWidget(add_button) # Set the tool icons icon = QtGui.QIcon() icon.addPixmap( QtGui.QPixmap(_fromUtf8(":/soma_widgets_icons/add")), QtGui.QIcon.Normal, QtGui.QIcon.Off) add_button.setIcon(icon) add_button.setFixedSize(30, 22) delete_button.setFixedSize(30, 22) # Add list item callback add_hook = partial(ControllerControlWidget.add_item, weak_proxy(parent), control_name, weak_proxy(frame)) add_button.clicked.connect(add_hook) # Create the associated controller widget controller_widget = ControllerWidget(control_value, parent=frame, live=True, editable_labels=editable_labels) # Store some parameters in the list widget frame.trait = trait frame.controller = control_value frame.controller_widget = controller_widget frame.connected = False # Add the list controller widget to the list widget frame.setLayout(controller_widget.layout()) # Set some callback on the controller control tools # Resize callback resize_hook = partial(ControllerControlWidget.expand_or_collapse, weak_proxy(frame), weak_proxy(resize_button)) resize_button.clicked.connect(resize_hook) if getattr(trait, 'expanded') is False: ControllerControlWidget.set_expanded(frame, resize_button, False) # Create the label associated with the controller widget control_label = trait.label if control_label is None: control_label = control_name if label_class is None: label_class = QtGui.QLabel if control_label is not None: label = label_class(control_label, parent) else: label = None return (frame, (label, tool_widget))
def create_control(self, trait_name, trait): """ Create a control associated to a trait. Parameters ---------- trait_name: str (mandatory) the name of the trait from which we want to create a control. The control widget will share the same name trait: Trait (mandatory) a trait item """ # Search if the current trait has already been processed control_groups = self._controls.get(trait_name) control_instances = [] control_labels = [] # If no control has been found in the class intern parameters if control_groups is None: # Call the search function that will map the trait type to the # corresponding control type control_class = self.get_control_class(trait) # If no control has been found, skip this trait and print # an error message. Note that the parameter will not be # accessible in the user interface. if control_class is None: logger.error("No control defined for trait '{0}': {1}. This " "parameter will not be accessible in the " "user interface.".format(trait_name, trait_ids(trait))) return # handle groups layouts = [] groups = trait.groups if groups: for group in groups: group_widget = self._groups.get(group) if group_widget is None: group_widget = self._create_group_widget(group) self._groups[group] = group_widget layouts.append(group_widget.hideable_widget.layout()) else: layouts.append(self._grid_layout) group = None for i, layout in enumerate(layouts): if groups: group = groups[i] control_instance, control_label \ = self._create_control_in_layout(trait_name, trait, layout, group) control_instances.append(control_instance) if control_label: if not isinstance(control_label, tuple): control_label = [control_label] control_labels += list(control_label) if isinstance(control_label[0], QtGui.QLabel): control_label[0].setTextInteractionFlags( QtCore.Qt.TextSelectableByKeyboard | QtCore.Qt.TextSelectableByMouse) control_label[0].setContextMenuPolicy( Qt.Qt.CustomContextMenu) control_label[0].customContextMenuRequested.connect( partial(self._label_context_menu, weakref.ref(control_label[0]), trait_name)) # Otherwise, the control associated with the current trait name is # already inserted in the grid layout, just unpack the values # contained in the private '_controls' class parameter else: for group, control in six.iteritems(control_groups): _, _, control_instance, control_label = control control_instances.append(control_instance) if control_label: if isinstance(control_label, tuple): control_labels += list(control_label) else: control_labels.append(control_label) # Each trait has a hidden property. Take care of this information hide = (getattr(trait, 'hidden', False) or getattr(trait, 'unused', False) or (getattr(trait, 'userlevel', 0) is not None and trait.userlevel > self.userlevel)) # Show/Hide the control and associated labels for control_instance in control_instances: control_instance.setVisible(not hide) for label in control_labels: if not sip.isdeleted(label): # sometimes happens... label.setVisible(not hide)