orange / Orange / OrangeCanvas / scheme /

Full commit
Scheme Node


from PyQt4.QtCore import QObject
from PyQt4.QtCore import pyqtSignal as Signal
from PyQt4.QtCore import pyqtProperty as Property

class UserMessage(object):
    A user message that should be displayed in a scheme view.

    contents : str
        Message text.
    severity : int
        Message severity.
    message_id : A hashable object
        Message id.
    data : dict
        A dictionary with optional extra data.

    #: Severity flags
    Info, Warning, Error = 1, 2, 3

    def __init__(self, contents, severity=Info, message_id=None, data={}):
        self.contents = contents
        self.severity = severity
        self.message_id = message_id = dict(data)

class SchemeNode(QObject):
    A node in a :class:`.Scheme`.

    description : :class:`WidgetDescription`
        Node description instance.
    title : str, optional
        Node title string (if None `` is used).
    position : tuple
        (x, y) tuple of floats for node position in a visual display.
    properties : dict
        Additional extra instance properties (settings, widget geometry, ...)
    parent : :class:`QObject`
        Parent object.


    def __init__(self, description, title=None, position=None,
                 properties=None, parent=None):
        QObject.__init__(self, parent)
        self.description = description

        if title is None:
            title =

        self.__title = title
        self.__position = position or (0, 0)
        self.__progress = -1
        self.__processing_state = 0
        self.__state_messages = {} = properties or {}

    def input_channels(self):
        Return a list of input channels (:class:`InputSignal`) for the node.
        return list(self.description.inputs)

    def output_channels(self):
        Return a list of output channels (:class:`OutputSignal`) for the node.
        return list(self.description.outputs)

    def input_channel(self, name):
        Return the input channel matching `name`. Raise a `ValueError`
        if not found.

        for channel in self.input_channels():
            if == name:
                return channel
        raise ValueError("%r is not a valid input channel name for %r." % \

    def output_channel(self, name):
        Return the output channel matching `name`. Raise an `ValueError`
        if not found.

        for channel in self.output_channels():
            if == name:
                return channel
        raise ValueError("%r is not a valid output channel name for %r." % \

    #: The title of the node has changed
    title_changed = Signal(unicode)

    def set_title(self, title):
        Set the node title.
        if self.__title != title:
            self.__title = unicode(title)

    def title(self):
        The node title.
        return self.__title

    title = Property(unicode, fset=set_title, fget=title)

    #: Position of the node in the scheme has changed
    position_changed = Signal(tuple)

    def set_position(self, pos):
        Set the position (``(x, y)`` tuple) of the node.
        if self.__position != pos:
            self.__position = pos

    def position(self):
        ``(x, y)`` tuple containing the position of the node in the scheme.
        return self.__position

    position = Property(tuple, fset=set_position, fget=position)

    #: Node's progress value has changed.
    progress_changed = Signal(float)

    def set_progress(self, value):
        Set the progress value.
        if self.__progress != value:
            self.__progress = value

    def progress(self):
        The current progress value. -1 if progress is not set.
        return self.__progress

    progress = Property(float, fset=set_progress, fget=progress)

    #: Node's processing state has changed.
    processing_state_changed = Signal(int)

    def set_processing_state(self, state):
        Set the node processing state.
        if self.__processing_state != state:
            self.__processing_state = state

    def processing_state(self):
        The node processing state, 0 for not processing, 1 the node is busy.
        return self.__processing_state

    processing_state = Property(int, fset=set_processing_state,

    def set_tool_tip(self, tool_tip):
        if self.__tool_tip != tool_tip:
            self.__tool_tip = tool_tip

    def tool_tip(self):
        return self.__tool_tip

    tool_tip = Property(str, fset=set_tool_tip,

    def set_state_message(self, message):
        Set a message to be displayed by a scheme view for this node.
        if message.message_id in self.__state_messages and \
                not message.contents:
            del self.__state_messages[message.message_id]

        self.__state_messages[message.message_id] = message


    #: The node's state message has changed
    state_message_changed = Signal(UserMessage)

    def __str__(self):
        return u"SchemeNode(description_id=%s, title=%r, ...)" % \
                (str(, self.title)

    def __repr__(self):
        return str(self)