source: orange/Orange/OrangeCanvas/scheme/widgetsscheme.py @ 11226:a01ffbd72688

Revision 11226:a01ffbd72688, 5.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 17 months ago (diff)

Saving global widget settings.

Line 
1import logging
2from functools import partial
3
4from PyQt4.QtCore import QTimer, SIGNAL
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    def add_node(self, node):
28        widget = self.create_widget_instance(node)
29
30        # don't emit the node_added signal until the widget is successfully
31        # added to signal manager etc.
32        with signals_disabled(self):
33            Scheme.add_node(self, node)
34
35        self.widgets.append(widget)
36
37        self.widget_for_node[node] = widget
38
39        self.signal_manager.addWidget(widget)
40
41        self.node_added.emit(node)
42
43    def remove_node(self, node):
44        Scheme.remove_node(self, node)
45        widget = self.widget_for_node[node]
46        self.signal_manager.removeWidget(widget)
47        del self.widget_for_node[node]
48
49        # Save settings to user global settings.
50        widget.saveSettings()
51
52        # Notify the widget it will be deleted.
53        widget.onDeleteWidget()
54        # And schedule it for deletion.
55        widget.deleteLater()
56
57    def add_link(self, link):
58        Scheme.add_link(self, link)
59        source_widget = self.widget_for_node[link.source_node]
60        sink_widget = self.widget_for_node[link.sink_node]
61        source_channel = link.source_channel.name
62        sink_channel = link.sink_channel.name
63        self.signal_manager.addLink(source_widget, sink_widget, source_channel,
64                                    sink_channel, enabled=link.enabled)
65
66        link.enabled_changed.connect(
67            partial(self.signal_manager.setLinkEnabled,
68                    source_widget, sink_widget)
69        )
70
71        QTimer.singleShot(0, self.signal_manager.processNewSignals)
72
73    def remove_link(self, link):
74        Scheme.remove_link(self, link)
75
76        source_widget = self.widget_for_node[link.source_node]
77        sink_widget = self.widget_for_node[link.sink_node]
78        source_channel = link.source_channel.name
79        sink_channel = link.sink_channel.name
80
81        self.signal_manager.removeLink(source_widget, sink_widget,
82                                       source_channel, sink_channel)
83
84    def create_widget_instance(self, node):
85        desc = node.description
86        klass = name_lookup(desc.qualified_name)
87
88        log.info("Creating %r instance.", klass)
89        widget = klass.__new__(
90            klass,
91            _owInfo=rc.get("canvas.show-state-info", True),
92            _owWarning=rc.get("canvas.show-state-warning", True),
93            _owError=rc.get("canvas.show-state-error", True),
94            _owShowStatus=rc.get("OWWidget.show-status", True),
95            _useContexts=rc.get("OWWidget.use-contexts", True),
96            _category=desc.category,
97            _settingsFromSchema=node.properties
98        )
99
100        widget.__init__(None, self.signal_manager)
101        widget.setCaption(node.title)
102        widget.widgetInfo = desc
103
104        widget.setVisible(node.properties.get("visible", False))
105
106        node.title_changed.connect(widget.setCaption)
107        # Bind widgets progress/processing state back to the node's properties
108        widget.progressBarValueChanged.connect(node.set_progress)
109        widget.processingStateChanged.connect(node.set_processing_state)
110
111        # TODO: Change how the signal is emitted in signal manager (should
112        # notify the SchemeLink directly).
113        widget.connect(
114           widget,
115           SIGNAL("dynamicLinkEnabledChanged(PyQt_PyObject, bool)"),
116           self.__on_dynamic_link_enabled_changed
117        )
118
119        return widget
120
121    def __on_dynamic_link_enabled_changed(self, link, enabled):
122        rev = dict(map(reversed, self.widget_for_node.items()))
123
124        source_node = rev[link.widgetFrom]
125        sink_node = rev[link.widgetTo]
126        source_channel = source_node.output_channel(link.signalNameFrom)
127        sink_channel = sink_node.input_channel(link.signalNameTo)
128
129        links = self.find_links(source_node, source_channel,
130                                sink_node, sink_channel)
131
132        if links:
133            link = links[0]
134            link.set_dynamic_enabled(enabled)
135
136    def close_all_open_widgets(self):
137        for widget in self.widget_for_node.values():
138            widget.close()
139
140    def widget_settings(self):
141        """Return a list of dictionaries with widget settings.
142        """
143        return [self.widget_for_node[node].getSettings(alsoContexts=False)
144                for node in self.nodes]
145
146    def save_widget_settings(self):
147        """Save all widget settings to their global settings file.
148        """
149        for node in self.nodes:
150            widget = self.widget_for_node[node]
151            widget.saveSettings()
152
153    def sync_node_properties(self):
154        """Sync the widget settings/properties with the SchemeNode.properties.
155        Return True if there were any changes in the properties (i.e. if the
156        new node.properties differ from the old value) and False otherwise.
157
158        .. note:: this should hopefully be removed in the feature, when the
159            widget can notify a changed setting property.
160
161        """
162        changed = False
163        for node in self.nodes:
164            widget = self.widget_for_node[node]
165            settings = widget.getSettings(alsoContexts=False)
166            if settings != node.properties:
167                node.properties = settings
168                changed = True
169        log.debug("Scheme node properties sync (changed: %s)", changed)
170        return changed
171
172    def save_to(self, stream):
173        self.sync_node_properties()
174        Scheme.save_to(self, stream)
Note: See TracBrowser for help on using the repository browser.