Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/scheme/widgetsscheme.py

    r11411 r11470  
    215215        SignalManager.__init__(self, scheme) 
    216216 
     217        scheme.installEventFilter(self) 
    217218        # We keep a mapping from node->widget after the node/widget has been 
    218219        # removed from the scheme until we also process all the outgoing signal 
    219220        # updates. The reason is the old OWBaseWidget's MULTI channel protocol 
    220221        # where the actual source widget instance is passed to the signal 
    221         # handler, and in the delaeyd update the mapping in `scheme()` is no 
     222        # handler, and in the delayed update the mapping in `scheme()` is no 
    222223        # longer available. 
    223224        self._widget_backup = {} 
    224  
     225        self._widgets_to_delete = set() 
     226        self._active_node = None 
    225227        self.freezing = 0 
     228 
     229        self.__scheme_deleted = False 
     230        scheme.destroyed.connect(self.__on_scheme_destroyed) 
    226231 
    227232    def on_node_removed(self, node): 
    228233        widget = self.scheme().widget_for_node[node] 
     234 
     235        assert not self.scheme().find_links(sink_node=node), \ 
     236            "Node removed but still has input links" 
     237 
     238        signals = self.compress_signals(self.pending_input_signals(node)) 
     239        if not all(signal.value is None for signal in signals): 
     240            log.error("Non 'None' signals pending for a removed node %r", 
     241                         node.title) 
     242 
    229243        SignalManager.on_node_removed(self, node) 
    230244 
     245        if self.runtime_state() == SignalManager.Processing and \ 
     246                node is self._active_node or self.is_blocking(node): 
     247            # Delay the widget delete until it finishes. 
     248            # Keep a reference to the widget and install a filter. 
     249            self._widgets_to_delete.add(widget) 
     250            widget.installEventFilter(self) 
     251 
    231252        # Store the node->widget mapping for possible delayed signal id. 
    232         # It will be removes in `process_queued` when all signals 
     253        # It will be removed in `process_queued` when all signals 
    233254        # originating from this widget are delivered. 
    234255        self._widget_backup[node] = widget 
     
    239260        """ 
    240261        scheme = self.scheme() 
     262 
     263        if widget not in scheme.node_for_widget: 
     264            # The Node/Widget was already removed from the scheme 
     265            return 
     266 
    241267        node = scheme.node_for_widget[widget] 
    242268 
     
    259285 
    260286        """ 
    261         widget = self.scheme().widget_for_node[node] 
     287        if node in self.scheme().widget_for_node: 
     288            widget = self.scheme().widget_for_node[node] 
     289        else: 
     290            widget = self._widget_backup[node] 
     291 
     292        self._active_node = node 
    262293        self.process_signals_for_widget(node, widget, signals) 
     294        self._active_node = None 
     295 
     296        if widget in self._widgets_to_delete: 
     297            # If this node/widget was removed during the 
     298            # 'process_signals_for_widget' 
     299            self._widgets_to_delete.remove(widget) 
     300            widget.deleteLater() 
    263301 
    264302    def compress_signals(self, signals): 
     
    354392 
    355393        if widget.processingHandler: 
    356             widget.processingHandler(self, 0) 
     394            widget.processingHandler(widget, 0) 
    357395 
    358396    def scheduleSignalProcessing(self, widget=None): 
     
    480518                return False 
    481519 
     520            if self.__scheme_deleted: 
     521                log.debug("Scheme has been/is being deleted. No more " 
     522                          "signals will be delivered to any nodes.") 
     523                event.setAccepted(True) 
     524                return True 
     525        # Retain a reference to the scheme until the 'process_queued' finishes 
     526        # in SignalManager.event. 
     527        scheme = self.scheme() 
    482528        return SignalManager.event(self, event) 
     529 
     530    def eventFilter(self, receiver, event): 
     531        if receiver is self.scheme() and event.type() == QEvent.DeferredDelete: 
     532            if self.runtime_state() == SignalManager.Processing: 
     533                log.info("Deferring a 'DeferredDelete' event for the Scheme " 
     534                         "instance until SignalManager exits the current " 
     535                         "update loop.") 
     536                event.setAccepted(False) 
     537                self.processingFinished.connect(self.scheme().deleteLater) 
     538                self.__scheme_deleted = True 
     539                return True 
     540        elif receiver in self._widgets_to_delete and \ 
     541                event.type() == QEvent.DeferredDelete: 
     542            if self._widget_backup.get(self._active_node, None) is receiver: 
     543                # The widget is still being updated. We need to keep it alive, 
     544                # it will be deleted in `send_to_node`. 
     545                log.info("Deferring a 'DeferredDelete' until widget exits " 
     546                         "the 'process_signals_for_widget'.") 
     547                event.setAccepted(False) 
     548                return True 
     549 
     550        return SignalManager.eventFilter(self, receiver, event) 
     551 
     552    def __on_scheme_destroyed(self, obj): 
     553        self.__scheme_deleted = True 
    483554 
    484555 
    485556class SignalLink(object): 
    486557    """ 
    487     Back compatiblity with old orngSignalManager, do not use. 
     558    Back compatibility with old orngSignalManager, do not use. 
    488559    """ 
    489560    def __init__(self, widgetFrom, outputSignal, widgetTo, inputSignal, 
Note: See TracChangeset for help on using the changeset viewer.