def __setitem__(self, key, value): """ Set the setting for key. """ if not isinstance(key, str): raise TypeError(key) fullkey = self.__key(key) if fullkey in self.__defaults: value_type = self.__defaults[fullkey].value_type if not isinstance(value, value_type): if not isinstance(value, value_type): raise TypeError("Expected {0!r} got {1!r}".format( value_type.__name__, type(value).__name__) ) if key in self: oldValue = self.get(key) etype = SettingChangedEvent.SettingChanged else: oldValue = None etype = SettingChangedEvent.SettingAdded self.__store.setValue(fullkey, value) QCoreApplication.sendEvent( self, SettingChangedEvent(etype, key, value, oldValue) )
def add_link(self, link): """ Add a `link` to the scheme. Parameters ---------- link : :class:`.SchemeLink` An initialized link instance to add to the scheme. """ check_type(link, SchemeLink) self.check_connect(link) self.__links.append(link) ev = events.LinkEvent(events.LinkEvent.LinkAdded, link) QCoreApplication.sendEvent(self, ev) log.info("Added link %r (%r) -> %r (%r) to scheme %r." % \ (link.source_node.title, link.source_channel.name, link.sink_node.title, link.sink_channel.name, self.title) ) self.link_added.emit(link)
def add_link(self, link): # type: (SchemeLink) -> None """ Add a `link` to the scheme. Parameters ---------- link : :class:`.SchemeLink` An initialized link instance to add to the scheme. """ assert isinstance(link, SchemeLink) self.check_connect(link) self.__links.append(link) ev = events.LinkEvent(events.LinkEvent.LinkAdded, link) QCoreApplication.sendEvent(self, ev) log.info("Added link %r (%r) -> %r (%r) to scheme %r." % \ (link.source_node.title, link.source_channel.name, link.sink_node.title, link.sink_channel.name, self.title) ) self.link_added.emit(link)
def __setitem__(self, key, value): """ Set the setting for key. """ if not isinstance(key, str): raise TypeError(key) fullkey = self.__key(key) value_type = None if fullkey in self.__defaults: value_type = self.__defaults[fullkey].value_type if not isinstance(value, value_type): if not isinstance(value, value_type): raise TypeError("Expected {0!r} got {1!r}".format( value_type.__name__, type(value).__name__) ) if key in self: oldValue = self.get(key) etype = SettingChangedEvent.SettingChanged else: oldValue = None etype = SettingChangedEvent.SettingAdded self.__setValue(fullkey, value, value_type) QCoreApplication.sendEvent( self, SettingChangedEvent(etype, key, value, oldValue) )
def __delitem__(self, key): """ Delete the setting for key. If key is a group remove the whole group. .. note:: defaults cannot be deleted they are instead reverted to their original state. """ if key not in self: raise KeyError(key) if self.isgroup(key): group = self.group(key) for key in group: del group[key] else: fullkey = self.__key(key) oldValue = self.get(key) if self.__store.contains(fullkey): self.__store.remove(fullkey) newValue = None if fullkey in self.__defaults: newValue = self.__defaults[fullkey].default_value etype = SettingChangedEvent.SettingChanged else: etype = SettingChangedEvent.SettingRemoved QCoreApplication.sendEvent( self, SettingChangedEvent(etype, key, newValue, oldValue) )
def viewportEvent(self, event: QEvent) -> bool: if event.type() == QEvent.Wheel: # delegate wheel events to parent StickyGraphicsView parent = self.parent().parent().parent() if isinstance(parent, StickyGraphicsView): QCoreApplication.sendEvent(parent.viewport(), event) if event.isAccepted(): return True return super().viewportEvent(event)
def contextMenu(widget: QWidget, pos: QPoint, delay=-1) -> None: """ Simulates a contextMenuEvent on the widget. """ ev = QContextMenuEvent(QContextMenuEvent.Mouse, pos, widget.mapToGlobal(pos)) if delay > 0: QTest.qWait(delay) QCoreApplication.sendEvent(widget, ev)
def _stateChanged(self, future, state): """ The `future` state has changed (called by :class:`Future`). """ ev = StateChangedEvent(state) if self.thread() is QThread.currentThread(): QCoreApplication.sendEvent(self, ev) else: QCoreApplication.postEvent(self, ev)
def set_runtime_env(self, key, value): # type: (str, Any) -> None """ Set a runtime environment variable `key` to `value` """ oldvalue = self.__env.get(key, None) if value != oldvalue: self.__env[key] = value QCoreApplication.sendEvent( self, WorkflowEnvChanged(key, value, oldvalue)) self.runtime_env_changed.emit(key, value, oldvalue)
def __add_widget_for_node(self, node): # type: (SchemeNode) -> None item = self.__item_for_node.get(node) if item is not None: return if node not in self.__workflow.nodes: return if node in self.__init_queue: self.__init_queue.remove(node) item = Item(node, None, -1) # Insert on the node -> item mapping. self.__item_for_node[node] = item log.debug("Creating widget for node %s", node) try: w = self.create_widget_for_node(node) except Exception: # pylint: disable=broad-except log.critical("", exc_info=True) lines = traceback.format_exception(*sys.exc_info()) text = "".join(lines) errorwidget = QLabel( textInteractionFlags=Qt.TextSelectableByMouse, wordWrap=True, objectName="widgetmanager-error-placeholder", text="<pre>" + escape(text) + "</pre>" ) item.errorwidget = errorwidget node.set_state_message(UserMessage(text, UserMessage.Error, 0)) return else: item.widget = w self.__item_for_widget[w] = item self.__set_float_on_top_flag(w) w.installEventFilter(self.__activation_monitor) # Up shortcut (activate/open parent) up_shortcut = QShortcut( QKeySequence(Qt.ControlModifier + Qt.Key_Up), w) up_shortcut.activated.connect(self.__on_activate_parent) # send all the post creation notification events workflow = self.__workflow assert workflow is not None inputs = workflow.find_links(sink_node=node) for link in inputs: ev = LinkEvent(LinkEvent.InputLinkAdded, link) QCoreApplication.sendEvent(w, ev) outputs = workflow.find_links(source_node=node) for link in outputs: ev = LinkEvent(LinkEvent.OutputLinkAdded, link) QCoreApplication.sendEvent(w, ev) self.widget_for_node_added.emit(node, w)
def remove_annotation(self, annotation): # type: (BaseSchemeAnnotation) -> None """ Remove the `annotation` instance from the scheme. """ index = self.__annotations.index(annotation) self.__annotations.pop(index) ev = AnnotationEvent(AnnotationEvent.AnnotationRemoved, annotation, index) QCoreApplication.sendEvent(self, ev) self.annotation_removed.emit(annotation)
def remove_annotation(self, annotation): # type: (BaseSchemeAnnotation) -> None """ Remove the `annotation` instance from the scheme. """ self.__annotations.remove(annotation) ev = events.AnnotationEvent(events.AnnotationEvent.AnnotationRemoved, annotation) QCoreApplication.sendEvent(self, ev) self.annotation_removed.emit(annotation)
def __on_link_removed(self, link): # type: (SchemeLink) -> None assert link.source_node in self.__workflow.nodes assert link.sink_node in self.__workflow.nodes source = self.__item_for_widget.get(link.source_node) sink = self.__item_for_widget.get(link.sink_node) # notify the node gui of an removed link if source is not None: ev = LinkEvent(LinkEvent.OutputLinkRemoved, link) QCoreApplication.sendEvent(source.widget, ev) if sink is not None: ev = LinkEvent(LinkEvent.InputLinkRemoved, link) QCoreApplication.sendEvent(sink.widget, ev)
def remove_annotation(self, annotation): """ Remove the `annotation` instance from the scheme. """ check_arg(annotation in self.__annotations, "Annotation is not in the scheme.") self.__annotations.remove(annotation) ev = events.AnnotationEvent(events.AnnotationEvent.AnnotationRemoved, annotation) QCoreApplication.sendEvent(self, ev) self.annotation_removed.emit(annotation)
def __on_link_removed(self, link): # type: (SchemeLink) -> None assert self.__workflow is not None assert link.source_node in self.__workflow.nodes assert link.sink_node in self.__workflow.nodes source = self.__item_for_node.get(link.source_node) sink = self.__item_for_node.get(link.sink_node) # notify the node gui of an removed link if source is not None and source.widget is not None: ev = LinkEvent(LinkEvent.OutputLinkRemoved, link) QCoreApplication.sendEvent(source.widget, ev) if sink is not None and sink.widget is not None: ev = LinkEvent(LinkEvent.InputLinkRemoved, link) QCoreApplication.sendEvent(sink.widget, ev)
def insert_node(self, index: int, node: Node): """ Insert `node` into self.nodes at the specified position `index` """ assert isinstance(node, SchemeNode) check_arg(node not in self.__nodes, "Node already in scheme.") self.__nodes.insert(index, node) ev = NodeEvent(NodeEvent.NodeAdded, node, index) QCoreApplication.sendEvent(self, ev) log.info("Added node %r to scheme %r." % (node.title, self.title)) self.node_added.emit(node) self.node_inserted.emit(index, node)
def init(self): """ Initialize the QCoreApplication.organizationDomain, applicationName, applicationVersion and the default settings format. Should only be run once at application startup. """ QCoreApplication.setOrganizationDomain(self.OrganizationDomain) QCoreApplication.setApplicationName(self.ApplicationName) QCoreApplication.setApplicationVersion(self.ApplicationVersion) QSettings.setDefaultFormat(QSettings.IniFormat) app = QCoreApplication.instance() if app is not None: QCoreApplication.sendEvent(app, QEvent(QEvent.PolishRequest))
def insert_annotation(self, index: int, annotation: Annotation) -> None: """ Insert `annotation` into `self.annotations` at the specified position `index`. """ assert isinstance(annotation, BaseSchemeAnnotation) if annotation in self.__annotations: raise ValueError("Cannot add the same annotation multiple times") self.__annotations.insert(index, annotation) ev = AnnotationEvent(AnnotationEvent.AnnotationAdded, annotation, index) QCoreApplication.sendEvent(self, ev) self.annotation_inserted.emit(index, annotation) self.annotation_added.emit(annotation)
def add_annotation(self, annotation): # type: (BaseSchemeAnnotation) -> None """ Add an annotation (:class:`BaseSchemeAnnotation` subclass) instance to the scheme. """ assert isinstance(annotation, BaseSchemeAnnotation) if annotation in self.__annotations: raise ValueError("Cannot add the same annotation multiple times") self.__annotations.append(annotation) ev = events.AnnotationEvent(events.AnnotationEvent.AnnotationAdded, annotation) QCoreApplication.sendEvent(self, ev) self.annotation_added.emit(annotation)
def add_annotation(self, annotation): """ Add an annotation (:class:`BaseSchemeAnnotation` subclass) instance to the scheme. """ check_arg(annotation not in self.__annotations, "Cannot add the same annotation multiple times.") check_type(annotation, BaseSchemeAnnotation) self.__annotations.append(annotation) ev = events.AnnotationEvent(events.AnnotationEvent.AnnotationAdded, annotation) QCoreApplication.sendEvent(self, ev) self.annotation_added.emit(annotation)
def set_runtime_state(self, state): # type: (Union[State, int]) -> None """ Set the link's runtime state. Parameters ---------- state : SchemeLink.State """ if self.__state != state: self.__state = state ev = LinkEvent(LinkEvent.InputLinkStateChange, self) QCoreApplication.sendEvent(self.sink_node, ev) ev = LinkEvent(LinkEvent.OutputLinkStateChange, self) QCoreApplication.sendEvent(self.source_node, ev) self.state_changed.emit(state)
def __on_help_request(self): """ Help shortcut was pressed. We send a `QWhatsThisClickedEvent` to the scheme and hope someone responds to it. """ # Sender is the QShortcut, and parent the OWBaseWidget widget = self.sender().parent() try: node = self.node_for_widget(widget) except KeyError: pass else: qualified_name = node.description.qualified_name help_url = "help://search?" + urlencode({"id": qualified_name}) event = QWhatsThisClickedEvent(help_url) QCoreApplication.sendEvent(self.scheme(), event)
def __dispatch_events(self, node: Node, event: QEvent) -> None: """ Dispatch relevant workflow events to the GUI widget """ if event.type() in ( WorkflowEvent.InputLinkAdded, WorkflowEvent.InputLinkRemoved, WorkflowEvent.InputLinkStateChange, WorkflowEvent.OutputLinkAdded, WorkflowEvent.OutputLinkRemoved, WorkflowEvent.OutputLinkStateChange, WorkflowEvent.NodeStateChange, WorkflowEvent.WorkflowEnvironmentChange, ): item = self.__item_for_node.get(node) if item is not None and item.widget is not None: QCoreApplication.sendEvent(item.widget, event)
def __updateView(self, view: QGraphicsView, rect: QRectF) -> None: view.setSceneRect(rect) viewrect = view.mapFromScene(rect).boundingRect() view.setFixedHeight(int(math.ceil(viewrect.height()))) container = view.parent() if rect.isEmpty(): container.setVisible(False) return # map the rect to (main) viewport coordinates viewrect = qgraphicsview_map_rect_from_scene(self, rect).boundingRect() viewrect = qrectf_to_inscribed_rect(viewrect) viewportrect = self.viewport().rect() visible = (viewrect.top() < viewportrect.top() or viewrect.y() + viewrect.height() > viewportrect.y() + viewportrect.height()) container.setVisible(visible) # force immediate layout of the container overlay QCoreApplication.sendEvent(container, QEvent(QEvent.LayoutRequest))
def set_state(self, state): # type: (Union[State, int]) -> None """ Set the node runtime state flags Parameters ---------- state: SchemeNode.State """ if self.__state != state: curr = self.__state self.__state = state QCoreApplication.sendEvent( self, NodeEvent(NodeEvent.NodeStateChange, self)) self.state_changed.emit(state) if curr & SchemeNode.Running != state & SchemeNode.Running: self.processing_state_changed.emit( int(bool(state & SchemeNode.Running)))
def add_node(self, node): """ Add a node to the scheme. An error is raised if the node is already in the scheme. Parameters ---------- node : :class:`.SchemeNode` Node instance to add to the scheme. """ check_arg(node not in self.__nodes, "Node already in scheme.") check_type(node, SchemeNode) self.__nodes.append(node) ev = events.NodeEvent(events.NodeEvent.NodeAdded, node) QCoreApplication.sendEvent(self, ev) log.info("Added node %r to scheme %r." % (node.title, self.title)) self.node_added.emit(node)
def remove_node(self, node): """ Remove a `node` from the scheme. All links into and out of the `node` are also removed. If the node in not in the scheme an error is raised. Parameters ---------- node : :class:`.SchemeNode` Node instance to remove. """ check_arg(node in self.__nodes, "Node is not in the scheme.") self.__remove_node_links(node) self.__nodes.remove(node) ev = events.NodeEvent(events.NodeEvent.NodeRemoved, node) QCoreApplication.sendEvent(self, ev) log.info("Removed node %r from scheme %r." % (node.title, self.title)) self.node_removed.emit(node) return node
def mouseMove(widget, buttons, modifier=Qt.NoModifier, pos=QPoint(), delay=-1): # type: (QWidget, Qt.MouseButtons, Qt.KeyboardModifier, QPoint, int) -> None """ Like QTest.mouseMove, but with `buttons` and `modifier` parameters. Parameters ---------- widget : QWidget buttons: Qt.MouseButtons modifier : Qt.KeyboardModifiers pos : QPoint delay : int """ if pos.isNull(): pos = widget.rect().center() me = QMouseEvent(QMouseEvent.MouseMove, pos, widget.mapToGlobal(pos), Qt.NoButton, buttons, modifier) if delay > 0: QTest.qWait(delay) QCoreApplication.sendEvent(widget, me)
def remove_link(self, link): """ Remove a link from the scheme. Parameters ---------- link : :class:`.SchemeLink` Link instance to remove. """ check_arg(link in self.__links, "Link is not in the scheme.") self.__links.remove(link) ev = events.LinkEvent(events.LinkEvent.LinkRemoved, link) QCoreApplication.sendEvent(self, ev) log.info("Removed link %r (%r) -> %r (%r) from scheme %r." % \ (link.source_node.title, link.source_channel.name, link.sink_node.title, link.sink_channel.name, self.title) ) self.link_removed.emit(link)
def add_default_slot(self, default): """ Add a default slot to the settings This also replaces any previously set value for the key. """ value = default.default_value oldValue = None etype = SettingChangedEvent.SettingAdded key = default.key if key in self: oldValue = self.get(key) etype = SettingChangedEvent.SettingChanged if not self.isdefault(key): # Replacing a default value. self.__store.remove(self.__key(key)) self.__defaults[key] = default event = SettingChangedEvent(etype, key, value, oldValue) QCoreApplication.sendEvent(self, event)
def insert_link(self, index: int, link: Link): """ Insert `link` into `self.links` at the specified position `index`. """ assert isinstance(link, SchemeLink) self.check_connect(link) self.__links.insert(index, link) source_index, _ = findf(enumerate( self.find_links(source_node=link.source_node)), lambda t: t[1] == link, default=(-1, None)) sink_index, _ = findf(enumerate( self.find_links(sink_node=link.sink_node)), lambda t: t[1] == link, default=(-1, None)) assert sink_index != -1 and source_index != -1 QCoreApplication.sendEvent( link.source_node, LinkEvent(LinkEvent.OutputLinkAdded, link, source_index)) QCoreApplication.sendEvent( link.sink_node, LinkEvent(LinkEvent.InputLinkAdded, link, sink_index)) QCoreApplication.sendEvent(self, LinkEvent(LinkEvent.LinkAdded, link, index)) log.info("Added link %r (%r) -> %r (%r) to scheme %r." % \ (link.source_node.title, link.source_channel.name, link.sink_node.title, link.sink_channel.name, self.title) ) self.link_inserted.emit(index, link) self.link_added.emit(link)
def eventFilter(self, obj, event): if (event.type() == QEvent.StatusTip and not isinstance(event, QuickHelpTipEvent) and hasattr(obj, "whatsThis") and isinstance(obj.whatsThis, Callable)): tip = event.tip() try: text = obj.whatsThis() except Exception: text = None if text: ev = QuickHelpTipEvent(tip, text if tip else "") return QCoreApplication.sendEvent(obj, ev) return QObject.eventFilter(self, obj, event)
def eventFilter(self, obj, event): if event.type() == QEvent.StatusTip and \ not isinstance(event, QuickHelpTipEvent) and \ hasattr(obj, "whatsThis") and \ isinstance(obj.whatsThis, Callable): tip = event.tip() try: text = obj.whatsThis() except Exception: text = None if text: ev = QuickHelpTipEvent(tip, text if tip else "") return QCoreApplication.sendEvent(obj, ev) return QObject.eventFilter(self, obj, event)
def eventFilter(self, obj, event): # type: (QObject, QEvent) -> bool if event.type() == QEvent.StatusTip and \ not isinstance(event, QuickHelpTipEvent) and \ hasattr(obj, "whatsThis") and \ callable(obj.whatsThis): assert isinstance(event, QStatusTipEvent) tip = event.tip() try: text = obj.whatsThis() except Exception: text = None if text: ev = QuickHelpTipEvent(tip, text if tip else "") return QCoreApplication.sendEvent(obj, ev) return super().eventFilter(obj, event)
def remove_link(self, link): # type: (SchemeLink) -> None """ Remove a link from the scheme. Parameters ---------- link : :class:`.SchemeLink` Link instance to remove. """ check_arg(link in self.__links, "Link is not in the scheme.") source_index, _ = findf( enumerate(self.find_links(source_node=link.source_node)), lambda t: t[1] == link, default=(-1, None) ) sink_index, _ = findf( enumerate(self.find_links(sink_node=link.sink_node)), lambda t: t[1] == link, default=(-1, None) ) assert sink_index != -1 and source_index != -1 index = self.__links.index(link) self.__links.pop(index) QCoreApplication.sendEvent( link.sink_node, LinkEvent(LinkEvent.InputLinkRemoved, link, sink_index) ) QCoreApplication.sendEvent( link.source_node, LinkEvent(LinkEvent.OutputLinkRemoved, link, source_index) ) QCoreApplication.sendEvent( self, LinkEvent(LinkEvent.LinkRemoved, link, index) ) log.info("Removed link %r (%r) -> %r (%r) from scheme %r." % \ (link.source_node.title, link.source_channel.name, link.sink_node.title, link.sink_channel.name, self.title) ) self.link_removed.emit(link)
def __on_activate_parent(self): event = WorkflowEvent(WorkflowEvent.ActivateParentRequest) QCoreApplication.sendEvent(self.scheme(), event)
def __on_env_changed(self, key, newvalue, oldvalue): # Notify widgets of a runtime environment change for item in self.__item_for_node.values(): if item.widget is not None: ev = WorkflowEnvChanged(key, newvalue, oldvalue) QCoreApplication.sendEvent(item.widget, ev)
def __on_activate_parent(self): """ Activate parent shortcut was pressed. """ event = ActivateParentEvent() QCoreApplication.sendEvent(self.scheme(), event)
def close(self): QCoreApplication.sendEvent(self, QEvent(QEvent.Close))