source: orange/Orange/OrangeCanvas/scheme/widgetsscheme.py @ 11135:111e30422c5a

Revision 11135:111e30422c5a, 5.0 KB checked in by Ales Erjavec <ales.erjavec@…>, 18 months ago (diff)

When adding a new link schedule delayed signal processing.

Line 
1import logging
2from functools import partial
3
4from PyQt4.QtCore import QTimer
5
6from .. import orngSignalManager
7from .scheme import Scheme
8from .utils import name_lookup
9from ..config import rc
10from ..gui.utils import signals_disabled
11
12log = logging.getLogger(__name__)
13
14
15class WidgetsScheme(Scheme):
16    """A Scheme containing Orange Widgets managed with a SignalManager
17    instance.
18
19    """
20    def __init__(self, parent=None, title=None, description=None):
21        Scheme.__init__(self, parent, title, description)
22
23        self.widgets = []
24        self.widget_for_node = {}
25        self.signal_manager = orngSignalManager.SignalManager()
26
27        self.__loaded_from = None
28
29    def add_node(self, node):
30        widget = self.create_widget_instance(node)
31
32        # don't emit the node_added signal until the widget is successfully
33        # added to signal manager etc.
34        with signals_disabled(self):
35            Scheme.add_node(self, node)
36
37        self.widgets.append(widget)
38
39        self.widget_for_node[node] = widget
40
41        self.signal_manager.addWidget(widget)
42
43        self.node_added.emit(node)
44
45    def remove_node(self, node):
46        Scheme.remove_node(self, node)
47        widget = self.widget_for_node[node]
48        self.signal_manager.removeWidget(widget)
49        del self.widget_for_node[node]
50
51        # Save settings to user global settings.
52        if not self.__loaded_from:
53            widget.saveSettings()
54
55        # Notify the widget it will be deleted.
56        widget.onDeleteWidget()
57        # And schedule it for deletion.
58        widget.deleteLater()
59
60    def add_link(self, link):
61        Scheme.add_link(self, link)
62        source_widget = self.widget_for_node[link.source_node]
63        sink_widget = self.widget_for_node[link.sink_node]
64        source_channel = link.source_channel.name
65        sink_channel = link.sink_channel.name
66        self.signal_manager.addLink(source_widget, sink_widget, source_channel,
67                                    sink_channel, enabled=link.enabled)
68
69        link.enabled_changed.connect(
70            partial(self.signal_manager.setLinkEnabled,
71                    source_widget, sink_widget)
72        )
73
74        QTimer.singleShot(0, self.signal_manager.processNewSignals)
75
76    def remove_link(self, link):
77        Scheme.remove_link(self, link)
78
79        source_widget = self.widget_for_node[link.source_node]
80        sink_widget = self.widget_for_node[link.sink_node]
81        source_channel = link.source_channel.name
82        sink_channel = link.sink_channel.name
83
84        self.signal_manager.removeLink(source_widget, sink_widget,
85                                       source_channel, sink_channel)
86
87    def create_widget_instance(self, node):
88        desc = node.description
89        klass = name_lookup(desc.qualified_name)
90
91        log.info("Creating %r instance.", klass)
92        widget = klass.__new__(
93            klass,
94            _owInfo=rc.get("canvas.show-state-info", True),
95            _owWarning=rc.get("canvas.show-state-warning", True),
96            _owError=rc.get("canvas.show-state-error", True),
97            _owShowStatus=rc.get("OWWidget.show-status", True),
98            _useContexts=rc.get("OWWidget.use-contexts", True),
99            _category=desc.category,
100            _settingsFromSchema=node.properties
101        )
102
103        widget.__init__(None, self.signal_manager)
104        widget.setCaption(node.title)
105        widget.widgetInfo = desc
106
107        widget.setVisible(node.properties.get("visible", False))
108
109        node.title_changed.connect(widget.setCaption)
110        # Bind widgets progress/processing state back to the node's properties
111        widget.progressBarValueChanged.connect(node.set_progress)
112        widget.processingStateChanged.connect(node.set_processing_state)
113
114        return widget
115
116    def close_all_open_widgets(self):
117        for widget in self.widget_for_node.values():
118            widget.close()
119
120    def sync_node_properties(self):
121        """Sync the widget settings/properties with the SchemeNode.properties.
122        Return True if there were any changes in the properties (i.e. if the
123        new node.properties differ from the old value) and False otherwise.
124
125        .. note:: this should hopefully be removed in the feature, when the
126            widget can notify a changed setting property.
127
128        """
129        changed = False
130        for node in self.nodes:
131            widget = self.widget_for_node[node]
132            settings = widget.getSettings()
133            if settings != node.properties:
134                node.properties = settings
135                changed = True
136        log.debug("Scheme node properties sync (changed: %s)", changed)
137        return changed
138
139    def save_to(self, stream):
140        self.sync_node_properties()
141        Scheme.save_to(self, stream)
142
143    def load_from(self, stream):
144        """Load the scheme from xml formated stream.
145        """
146        if isinstance(stream, basestring):
147            self.__loaded_from = stream
148            stream = open(stream, "rb")
149        elif isinstance(stream, file):
150            self.__loaded_from = stream.name
151
152        Scheme.load_from(self, stream)
Note: See TracBrowser for help on using the repository browser.