def connect(cls, controller_widget, control_name, control_instance): """ Connect an 'Enum' controller trait and an 'EnumControlWidget' controller widget control. Parameters ---------- cls: EnumControlWidget (mandatory) an EnumControlWidget control controller_widget: ControllerWidget (mandatory) a controller widget that contains the controller we want to update control_name: str (mandatory) the name of the controller widget control we want to synchronize with the controller control_instance: QComboBox (mandatory) the instance of the controller widget control we want to synchronize with the controller """ # Update one element of the controller widget. # Hook: function that will be called to update the specific widget # when a trait event is detected. controller_hook = SomaPartial(cls.update_controller_widget, weak_proxy(controller_widget), control_name, weak_proxy(control_instance)) # When the 'control_name' controller trait value is modified, update # the corresponding control controller_widget.controller.on_trait_change(controller_hook, name=control_name, dispatch='ui') # Store the trait - control connection we just build control_instance._controller_connections = (controller_hook, ) logger.debug("Add 'Compound' connection: {0} / {1}".format( control_name, control_instance))
def __setstate__(self, state): """ Restore the callbacks that have been removed by __getstate__. """ state['_callbacks'] = dict((i, SomaPartial(self._value_callback, *i)) for i in state['_callbacks']) if state['pipeline'] is state['process']: state['pipeline'] = state['process'] = weak_proxy( state['pipeline']) else: state['pipeline'] = weak_proxy(state['pipeline']) super(Node, self).__setstate__(state) for callback_key, value_callback in six.iteritems(self._callbacks): self.set_callback_on_plug(callback_key[0], value_callback)
def __init__(self, pipeline, name, process, **kwargs): """ Generate a ProcessNode Parameters ---------- pipeline: Pipeline (mandatory) the pipeline object where the node is added. name: str (mandatory) the node name. process: instance a process/interface instance. kwargs: dict process default values. """ if process is pipeline: self.process = weak_proxy(process) else: self.process = process self.kwargs = kwargs inputs = [] outputs = [] for parameter, trait in six.iteritems(self.process.user_traits()): if parameter in ('nodes_activation', 'selection_changed'): continue if trait.output: outputs.append( dict(name=parameter, optional=bool(trait.optional), output=True)) else: inputs.append( dict(name=parameter, optional=bool(trait.optional or parameter in kwargs))) super(ProcessNode, self).__init__(pipeline, name, inputs, outputs)
def __init__(self, process, name=None): super(ProcessCompletionEngine, self).__init__( process=process, name=name) self.process = weak_proxy(process) self.name = name self.completion_ongoing = False self.add_trait('completion_progress', traits.Float(0.)) self.add_trait('completion_progress_total', traits.Float(1.))
def connect(self, source_plug_name, dest_node, dest_plug_name): """ Connect linked plugs of two nodes Parameters ---------- source_plug_name: str (mandatory) the source plug name dest_node: Node (mandatory) the destination node dest_plug_name: str (mandatory) the destination plug name """ # add a callback to spread the source plug value value_callback = SomaPartial(self.__class__._value_callback, weak_proxy(self), source_plug_name, weak_proxy(dest_node), dest_plug_name) self._callbacks[(source_plug_name, dest_node, dest_plug_name)] = value_callback self.set_callback_on_plug(source_plug_name, value_callback)
def connect(cls, controller_widget, control_name, control_instance): """ Connect a 'Str' or 'String' controller trait and a 'StrControlWidget' controller widget control. Parameters ---------- cls: StrControlWidget (mandatory) a StrControlWidget control controller_widget: ControllerWidget (mandatory) a controller widget that contains the controller we want to update control_name: str (mandatory) the name of the controller widget control we want to synchronize with the controller control_instance: QLineEdit (mandatory) the instance of the controller widget control we want to synchronize with the controller """ # Check if the control is connected if not control_instance.connected: # Update one element of the controller. # Hook: function that will be called to update a specific # controller trait when a 'userModification' qt signal is emited widget_hook = partial(cls.update_controller, weak_proxy(controller_widget), control_name, weak_proxy(control_instance), False) # When a qt 'userModification' signal is emited, update the # 'control_name' controller trait value control_instance.userModification.connect(widget_hook) widget_hook2 = partial(cls.update_controller, weak_proxy(controller_widget), control_name, weak_proxy(control_instance), True) control_instance.editingFinished.connect(widget_hook2) # Update the control. # Hook: function that will be called to update the control value # when the 'control_name' controller trait is modified. controller_hook = SomaPartial(cls.update_controller_widget, weak_proxy(controller_widget), control_name, weak_proxy(control_instance)) # When the 'control_name' controller trait value is modified, # update the corresponding control controller_widget.controller.on_trait_change(controller_hook, name=control_name, dispatch='ui') # Store the trait - control connection we just build control_instance._controller_connections = (widget_hook, widget_hook2, controller_hook) logger.debug("Add 'String' connection: {0} / {1}.".format( control_name, control_instance)) # Update the control connection status control_instance.connected = True
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 _install_subprogress_moniotoring(self, subprocess_compl): monitor_subprocess_progress = getattr( self, 'monitor_subprocess_progress', True) if monitor_subprocess_progress: self._old_monitor_sub = getattr( subprocess_compl, 'monitor_subprocess_progress', True) subprocess_compl.monitor_subprocess_progress = False self._current_progress = self.completion_progress self._monitoring_callback = SomaPartial( self.__class__._substep_completion_progress, weak_proxy(self), subprocess_compl) subprocess_compl.on_trait_change( self._monitoring_callback, 'completion_progress')
def check(cls, control_instance): """ Check if a controller widget control is filled correctly. Parameters ---------- cls: EnumControlWidget (mandatory) an EnumControlWidget control control_instance: QComboBox (mandatory) the control widget we want to validate """ # Hook: function that will be called to check for typo # when a 'textEdited' qt signal is emited widget_callback = partial(cls.is_valid, weak_proxy(control_instance)) # Execute manually the first time the control check method widget_callback()
def check(cls, control_instance): """ Check if a controller widget control is filled correctly. Parameters ---------- cls: StrControlWidget (mandatory) a StrControlWidget control control_instance: QLineEdit (mandatory) the control widget we want to validate """ # Hook: function that will be called to check for typo # when a 'userModification' qt signal is emited widget_callback = partial(cls.is_valid, weak_proxy(control_instance)) # The first time execute manually the control check method widget_callback() # When a qt 'userModification' signal is emited, check if the new # user value is correct control_instance.userModification.connect(widget_callback)
def __init__(self, pipeline, name, inputs, outputs): """ Generate a Node Parameters ---------- pipeline: Pipeline (mandatory) the pipeline object where the node is added name: str (mandatory) the node name inputs: list of dict (mandatory) a list of input parameters containing a dictionary with default values (mandatory key: name) outputs: dict (mandatory) a list of output parameters containing a dictionary with default values (mandatory key: name) """ super(Node, self).__init__() self.pipeline = weak_proxy(pipeline) self.name = name self.plugs = SortedDictionary() # _callbacks -> (src_plug_name, dest_node, dest_plug_name) self._callbacks = {} # generate a list with all the inputs and outputs # the second parameter (parameter_type) is False for an input, # True for an output parameters = list(zip(inputs, [ False, ] * len(inputs))) parameters.extend(list(zip(outputs, [ True, ] * len(outputs)))) for parameter, parameter_type in parameters: # check if parameter is a dictionary as specified in the # docstring if isinstance(parameter, dict): # check if parameter contains a name item # as specified in the docstring if "name" not in parameter: raise Exception( "Can't create parameter with unknown" "identifier and parameter {0}".format(parameter)) parameter = parameter.copy() plug_name = parameter.pop("name") # force the parameter type parameter["output"] = parameter_type # generate plug with input parameter and identifier name plug = Plug(**parameter) else: raise Exception("Can't create Node. Expect a dict structure " "to initialize the Node, " "got {0}: {1}".format(type(parameter), parameter)) # update plugs list self.plugs[plug_name] = plug # add an event on plug to validate the pipeline plug.on_trait_change(pipeline.update_nodes_and_plugs_activation, "enabled") # add an event on the Node instance traits to validate the pipeline self.on_trait_change(pipeline.update_nodes_and_plugs_activation, "enabled")
def create_widget(parent, control_name, control_value, trait, label_class=None, user_data=None): """ Method to create the list widget. Parameters ---------- parent: QWidget (mandatory) the parent widget control_name: str (mandatory) the name of the control we want to create control_value: list of items (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)) """ widget, label = OffscreenListFileControlWidget.create_widget( parent, control_name, control_value, trait, label_class=label_class, user_data=user_data) layout = widget.layout() project = user_data.get('project') scan_list = user_data.get('scan_list') main_window = user_data.get('main_window') if project and scan_list: # Create a browse button button = Qt.QPushButton("Filter", widget) button.setObjectName('filter_button') button.setStyleSheet('QPushButton#filter_button ' '{padding: 2px 10px 2px 10px; margin: 0px;}') layout.addWidget(button) widget.filter_b = button # Set a callback on the browse button control_class = parent.get_control_class(trait) node_name = getattr(parent.controller, 'name', None) if node_name is None: node_name = parent.controller.__class__.__name__ browse_hook = partial(control_class.filter_clicked, weak_proxy(widget), node_name, control_name) #parameters, process) widget.filter_b.clicked.connect(browse_hook) return (widget, label)
def create_widget(parent, control_name, control_value, trait, label_class=None, user_data=None): """ Method to create the file widget. Parameters ---------- parent: QWidget (mandatory) the parent widget control_name: str (mandatory) the name of the control we want to create control_value: str (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: QWidget with two elements, a QLineEdit in the 'path' parameter and a browse button in the 'browse' parameter, associated label: QLabel) """ # Create the widget that will be used to select a file widget, label = FileControlWidget.create_widget( parent, control_name, control_value, trait, label_class=label_class, user_data=user_data) if user_data is None: user_data = {} widget.user_data = user_data # regular File does not store data layout = widget.layout() project = user_data.get('project') scan_list = user_data.get('scan_list') connected_inputs = user_data.get('connected_inputs', set()) def is_number(x): try: int(x) return True except ValueError: return False main_window = user_data.get('main_window') # files in a list don't get a Filter button. if project and scan_list and not trait.output \ and control_name not in connected_inputs \ and not is_number(control_name): # Create a browse button button = Qt.QPushButton("Filter", widget) button.setObjectName('filter_button') button.setStyleSheet('QPushButton#filter_button ' '{padding: 2px 10px 2px 10px; margin: 0px;}') layout.addWidget(button) widget.filter_b = button # Set a callback on the browse button control_class = parent.get_control_class(trait) node_name = getattr(parent.controller, 'name', None) if node_name is None: node_name = parent.controller.__class__.__name__ browse_hook = partial(control_class.filter_clicked, weak_proxy(widget), node_name, control_name) widget.filter_b.clicked.connect(browse_hook) return (widget, label)