Ignore:
Location:
Orange/OrangeCanvas
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/application/canvasmain.py

    r11469 r11446  
    223223 
    224224        self.scheme_widget = SchemeEditWidget() 
    225         self.scheme_widget.setScheme(widgetsscheme.WidgetsScheme(parent=self)) 
     225        self.scheme_widget.setScheme(widgetsscheme.WidgetsScheme()) 
    226226 
    227227        w.layout().addWidget(self.scheme_widget) 
     
    810810                return QDialog.Rejected 
    811811 
    812         new_scheme = widgetsscheme.WidgetsScheme(parent=self) 
     812        new_scheme = widgetsscheme.WidgetsScheme() 
    813813 
    814814        settings = QSettings() 
     
    884884 
    885885        """ 
    886         new_scheme = widgetsscheme.WidgetsScheme(parent=self) 
     886        new_scheme = widgetsscheme.WidgetsScheme() 
    887887        errors = [] 
    888888        try: 
     
    940940        manager = new_scheme.signal_manager 
    941941        if self.freeze_action.isChecked(): 
    942             manager.pause() 
     942            manager.freeze().push() 
    943943 
    944944        scheme_doc.setScheme(new_scheme) 
     
    946946        old_scheme.save_widget_settings() 
    947947        old_scheme.close_all_open_widgets() 
    948         old_scheme.signal_manager.stop() 
     948 
    949949        old_scheme.deleteLater() 
    950950 
     
    13211321    def set_signal_freeze(self, freeze): 
    13221322        scheme = self.current_document().scheme() 
    1323         manager = scheme.signal_manager 
    13241323        if freeze: 
    1325             manager.pause() 
     1324            scheme.signal_manager.freeze().push() 
    13261325        else: 
    1327             manager.resume() 
     1326            scheme.signal_manager.freeze().pop() 
    13281327 
    13291328    def remove_selected(self): 
     
    13351334        """Quit the application. 
    13361335        """ 
    1337         if QApplication.activePopupWidget(): 
    1338             # On OSX the actions in the global menu bar are triggered 
    1339             # even if an popup widget is running it's own event loop 
    1340             # (in exec_) 
    1341             log.debug("Ignoring a quit shortcut during an active " 
    1342                       "popup dialog.") 
    1343         else: 
    1344             self.close() 
     1336        self.close() 
    13451337 
    13461338    def select_all(self): 
     
    14911483                return 
    14921484 
    1493         # Set an empty scheme to clear the document 
    1494         document.setScheme(widgetsscheme.WidgetsScheme()) 
    1495  
    14961485        scheme = document.scheme() 
    14971486        scheme.save_widget_settings() 
    14981487        scheme.close_all_open_widgets() 
    1499         scheme.signal_manager.stop() 
    1500         scheme.deleteLater() 
     1488 
     1489        # Set an empty scheme to clear the document 
     1490        document.setScheme(widgetsscheme.WidgetsScheme()) 
     1491        document.deleteLater() 
    15011492 
    15021493        config.save_config() 
  • Orange/OrangeCanvas/canvas/layout.py

    r11463 r11207  
    99import sip 
    1010 
    11 from PyQt4.QtGui import QGraphicsObject, QApplication 
    12 from PyQt4.QtCore import QRectF, QLineF, QEvent 
     11from PyQt4.QtGui import QGraphicsObject 
     12from PyQt4.QtCore import QRectF, QLineF, QTimer 
    1313 
    1414from .items import NodeItem, LinkItem, SourceAnchorItem, SinkAnchorItem 
     
    135135        if self.isEnabled() and not self.__layoutPending: 
    136136            self.__layoutPending = True 
    137             QApplication.postEvent(self, QEvent(QEvent.LayoutRequest)) 
     137            QTimer.singleShot(0, self.__delayedActivate) 
    138138 
    139139    def __delayedActivate(self): 
    140140        if self.__layoutPending: 
    141141            self.activate() 
    142  
    143     def event(self, event): 
    144         if event.type() == QEvent.LayoutRequest: 
    145             self.activate() 
    146             return True 
    147  
    148         return QGraphicsObject.event(self, event) 
    149142 
    150143 
  • Orange/OrangeCanvas/canvas/scene.py

    r11464 r11442  
    127127        Clear (reset) the scene. 
    128128        """ 
    129         if self.scheme is not None: 
    130             self.scheme.node_added.disconnect(self.add_node) 
    131             self.scheme.node_removed.disconnect(self.remove_node) 
    132  
    133             self.scheme.link_added.disconnect(self.add_link) 
    134             self.scheme.link_removed.disconnect(self.remove_link) 
    135  
    136             self.scheme.annotation_added.disconnect(self.add_annotation) 
    137             self.scheme.annotation_removed.disconnect(self.remove_annotation) 
    138  
    139             self.scheme.node_state_changed.disconnect( 
    140                 self.on_widget_state_change 
    141             ) 
    142             self.scheme.channel_state_changed.disconnect( 
    143                 self.on_link_state_change 
    144             ) 
    145  
    146             # Remove all items to make sure all signals from scheme items 
    147             # to canvas items are disconnected. 
    148  
    149             for annot in self.scheme.annotations: 
    150                 if annot in self.__item_for_annotation: 
    151                     self.remove_annotation(annot) 
    152  
    153             for link in self.scheme.links: 
    154                 if link in self.__item_for_link: 
    155                     self.remove_link(link) 
    156  
    157             for node in self.scheme.nodes: 
    158                 if node in self.__item_for_node: 
    159                     self.remove_node(node) 
    160  
    161129        self.scheme = None 
    162130        self.__node_items = [] 
     
    187155        if self.scheme is not None: 
    188156            # Clear the old scheme 
     157            self.scheme.node_added.disconnect(self.add_node) 
     158            self.scheme.node_removed.disconnect(self.remove_node) 
     159 
     160            self.scheme.link_added.disconnect(self.add_link) 
     161            self.scheme.link_removed.disconnect(self.remove_link) 
     162 
     163            self.scheme.annotation_added.disconnect(self.add_annotation) 
     164            self.scheme.annotation_removed.disconnect(self.remove_annotation) 
     165 
     166            self.scheme.node_state_changed.disconnect( 
     167                self.on_widget_state_change 
     168            ) 
     169            self.scheme.channel_state_changed.disconnect( 
     170                self.on_link_state_change 
     171            ) 
     172 
    189173            self.clear_scene() 
    190174 
     
    506490        item = self.__item_for_link.pop(scheme_link) 
    507491        scheme_link.enabled_changed.disconnect(item.setEnabled) 
    508  
    509         if scheme_link.is_dynamic(): 
    510             scheme_link.dynamic_enabled_changed.disconnect( 
    511                 item.setDynamicEnabled 
    512             ) 
    513  
    514492        self.remove_link_item(item) 
    515493 
  • Orange/OrangeCanvas/document/quickmenu.py

    r11462 r11420  
    2121    QStandardItemModel, QSortFilterProxyModel, QStyleOptionToolButton, 
    2222    QStylePainter, QStyle, QApplication, QStyledItemDelegate, 
    23     QStyleOptionViewItemV4, QSizeGrip, QKeySequence 
     23    QStyleOptionViewItemV4, QSizeGrip 
    2424) 
    2525 
     
    948948        FramelessWindow.keyPressEvent(self, event) 
    949949        event.accept() 
    950  
    951     def event(self, event): 
    952         if event.type() == QEvent.ShortcutOverride: 
    953             log.debug("Overriding shortcuts") 
    954             event.accept() 
    955             return True 
    956         return FramelessWindow.event(self, event) 
    957950 
    958951    def eventFilter(self, obj, event): 
  • Orange/OrangeCanvas/document/schemeedit.py

    r11471 r11451  
    554554            ) 
    555555 
     556            self.__scene.clear() 
    556557            self.__scene.removeEventFilter(self) 
    557  
    558             # Clear all items from the scene 
    559             self.__scene.blockSignals(True) 
    560             self.__scene.clear_scene() 
    561  
    562558            self.__scene.deleteLater() 
    563559 
  • Orange/OrangeCanvas/scheme/signalmanager.py

    r11467 r11269  
    1010 
    1111import logging 
    12 import itertools 
    13  
    14 from collections import namedtuple, defaultdict, deque 
     12 
     13from collections import namedtuple, defaultdict 
    1514from operator import attrgetter, add 
    16 from functools import partial 
    1715 
    1816 
     
    173171        # NOTE: This does not remove output signals this node. In particular 
    174172        # the final 'None' values might be left on the queue. 
    175         log.info("Node %r removed. Removing pending signals.", 
    176                  node.title) 
     173        log.info("Node %r removed. Removing pending signals.") 
    177174        self.remove_pending_signals(node) 
    178175 
     
    299296 
    300297        log.info("Processing queued signals") 
    301  
    302         node_update_front = self.node_update_front() 
     298        scheme = self.scheme() 
     299 
     300        blocking_nodes = set(self.blocking_nodes()) 
     301 
     302        blocked_nodes = reduce(set.union, 
     303                               map(scheme.downstream_nodes, blocking_nodes), 
     304                               set(blocking_nodes)) 
     305 
     306        pending = set(self.pending_nodes()) 
     307 
     308        pending_downstream = reduce(set.union, 
     309                                    map(scheme.downstream_nodes, pending), 
     310                                    set()) 
     311 
     312        log.debug("Pending nodes: %s", pending) 
     313        log.debug("Blocking nodes: %s", blocking_nodes) 
     314 
     315        # nodes on the update front (they have no ancestor which is 
     316        # either scheduled for update or is in blocking state) 
     317        node_update_front = list(pending - pending_downstream - blocked_nodes) 
    303318 
    304319        if max_nodes is not None: 
     
    310325        self._set_runtime_state(SignalManager.Processing) 
    311326        try: 
    312             # TODO: What if the update front changes in the loop? 
    313327            for node in node_update_front: 
    314328                self.process_node(node) 
     
    397411        return False 
    398412 
    399     def node_update_front(self): 
    400         """ 
    401         Return a list of nodes on the update front, i.e. nodes scheduled for 
    402         an update that have no ancestor which is either itself scheduled 
    403         for update or is in a blocking state) 
    404  
    405         .. note:: 
    406             The node's ancestors are only computed over enabled links. 
    407  
    408         """ 
    409         scheme = self.scheme() 
    410  
    411         blocking_nodes = set(self.blocking_nodes()) 
    412  
    413         dependents = partial(dependent_nodes, scheme) 
    414  
    415         blocked_nodes = reduce(set.union, 
    416                                map(dependents, blocking_nodes), 
    417                                set(blocking_nodes)) 
    418  
    419         pending = set(self.pending_nodes()) 
    420  
    421         pending_downstream = reduce(set.union, 
    422                                     map(dependents, pending), 
    423                                     set()) 
    424  
    425         log.debug("Pending nodes: %s", pending) 
    426         log.debug("Blocking nodes: %s", blocking_nodes) 
    427  
    428         return list(pending - pending_downstream - blocked_nodes) 
    429  
    430413    def event(self, event): 
    431414        if event.type() == QEvent.UpdateRequest: 
    432415            if not self.__state == SignalManager.Running: 
    433                 log.debug("Received 'UpdateRequest' event while not " 
     416                log.debug("Received UpdateRequest event while not " 
    434417                          "in 'Running' state") 
    435418                event.setAccepted(False) 
     
    437420 
    438421            if self.__runtime_state == SignalManager.Processing: 
    439                 log.debug("Received 'UpdateRequest' event while in " 
     422                log.debug("received UpdateRequest event while in " 
    440423                          "'process_queued'") 
    441424                # This happens if someone calls QCoreApplication.processEvents 
     
    445428                return True 
    446429 
    447             log.info("'UpdateRequest' event, queued signals: %i", 
     430            log.debug("UpdateRequest event, queued signals: %i", 
    448431                      len(self._input_queue)) 
    449432            if self._input_queue: 
    450                 self.process_queued(max_nodes=1) 
     433                self.process_queued() 
    451434            event.accept() 
    452435 
    453436            if self.__reschedule: 
    454                 log.debug("Rescheduling 'UpdateRequest' event") 
     437                log.debug("Rescheduling UpdateRequest event") 
    455438                self._update() 
    456439                self.__reschedule = False 
    457             elif self.node_update_front(): 
    458                 log.debug("More nodes are eligible for an update. " 
    459                           "Scheduling another update.") 
    460                 self._update() 
    461440 
    462441            return True 
     
    497476 
    498477    return list(reversed(signals)) 
    499  
    500  
    501 def dependent_nodes(scheme, node): 
    502     """ 
    503     Return a list of all nodes (in breadth first order) in `scheme` that 
    504     are dependent on `node`, 
    505  
    506     .. note:: 
    507         This does not include nodes only reachable by disables links. 
    508  
    509     """ 
    510     def expand(node): 
    511         return [link.sink_node 
    512                 for link in scheme.find_links(source_node=node) 
    513                 if link.enabled] 
    514  
    515     nodes = list(traverse_bf(node, expand)) 
    516     assert nodes[0] is node 
    517     # Remove the first item (`node`). 
    518     return nodes[1:] 
    519  
    520  
    521 def traverse_bf(start, expand): 
    522     queue = deque([start]) 
    523     visited = set() 
    524     while queue: 
    525         item = queue.popleft() 
    526         if item not in visited: 
    527             yield item 
    528             visited.add(item) 
    529             queue.extend(expand(item)) 
    530478 
    531479 
  • Orange/OrangeCanvas/scheme/widgetsscheme.py

    r11470 r11411  
    215215        SignalManager.__init__(self, scheme) 
    216216 
    217         scheme.installEventFilter(self) 
    218217        # We keep a mapping from node->widget after the node/widget has been 
    219218        # removed from the scheme until we also process all the outgoing signal 
    220219        # updates. The reason is the old OWBaseWidget's MULTI channel protocol 
    221220        # where the actual source widget instance is passed to the signal 
    222         # handler, and in the delayed update the mapping in `scheme()` is no 
     221        # handler, and in the delaeyd update the mapping in `scheme()` is no 
    223222        # longer available. 
    224223        self._widget_backup = {} 
    225         self._widgets_to_delete = set() 
    226         self._active_node = None 
     224 
    227225        self.freezing = 0 
    228  
    229         self.__scheme_deleted = False 
    230         scheme.destroyed.connect(self.__on_scheme_destroyed) 
    231226 
    232227    def on_node_removed(self, node): 
    233228        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  
    243229        SignalManager.on_node_removed(self, node) 
    244230 
    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  
    252231        # Store the node->widget mapping for possible delayed signal id. 
    253         # It will be removed in `process_queued` when all signals 
     232        # It will be removes in `process_queued` when all signals 
    254233        # originating from this widget are delivered. 
    255234        self._widget_backup[node] = widget 
     
    260239        """ 
    261240        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  
    267241        node = scheme.node_for_widget[widget] 
    268242 
     
    285259 
    286260        """ 
    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 
     261        widget = self.scheme().widget_for_node[node] 
    293262        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() 
    301263 
    302264    def compress_signals(self, signals): 
     
    392354 
    393355        if widget.processingHandler: 
    394             widget.processingHandler(widget, 0) 
     356            widget.processingHandler(self, 0) 
    395357 
    396358    def scheduleSignalProcessing(self, widget=None): 
     
    518480                return False 
    519481 
    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() 
    528482        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 
    554483 
    555484 
    556485class SignalLink(object): 
    557486    """ 
    558     Back compatibility with old orngSignalManager, do not use. 
     487    Back compatiblity with old orngSignalManager, do not use. 
    559488    """ 
    560489    def __init__(self, widgetFrom, outputSignal, widgetTo, inputSignal, 
Note: See TracChangeset for help on using the changeset viewer.