def dragMoveEvent(self, e): """ desc: Handles drag-move events to see if the item tree can handle incoming drops. arguments: e: desc: A drag-move event. type: QDragMoveEvent """ data = drag_and_drop.receive(e) if drag_and_drop.matches(data, [u'url-local']): e.accept() return if not drag_and_drop.matches(data, [u'item-new', u'item-existing']): e.accept() return target = self.itemAt(e.pos()) if not self.droppable(target, data): e.ignore() return e.accept()
def drop_event_item_move(self, data, e): """ desc: Handles drop events for item moves. arguments: data: desc: A drop-data dictionary. type: dict: e: desc: A drop event. type: QDropEvent """ if not drag_and_drop.matches(data, [u"item-existing"]): e.ignore() return target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): debug.msg(u"Drop ignored: target not droppable") self.main_window.set_status(_(u"Drop cancelled: Target not droppable")) e.ignore() return # If the drop comes from this application, check for recursion etc. if data[u"application-id"] == self.main_window._id(): target_item_name, target_item_ancestry = target_treeitem.ancestry() item_name = data[u"item-name"] item = self.experiment.items[item_name] if target_item_name in item.children(): debug.msg(u"Drop ignored: recursion prevented") self.main_window.set_status(_(u"Drop cancelled: Recursion prevented")) e.ignore() return parent_item_name, index = self.parent_from_ancestry(data[u"ancestry"]) if parent_item_name == None: debug.msg(u"Drop ignored: no parent") e.ignore() return # The logic below is a bit complicated, but works as follows: # - If we're in a move action, remove the dragged item from its parent, # and set need_restore so that we know this happened. # - Try to drop the dragged item onto the target item # - If the drop action was unsuccesful, and if need_restore is set, # re-add the dragged item to its former parent. need_restore = False if not QtCore.Qt.ControlModifier & e.keyboardModifiers() and data[u"application-id"] == self.main_window._id(): if parent_item_name not in self.experiment.items: debug.msg(u"Don't know how to remove item from %s" % parent_item_name) else: self.locked = True need_restore = True self.experiment.items[parent_item_name].remove_child_item(item_name, index) self.locked = False if self.drop_event_item_new(data, e, target_treeitem=target_treeitem): return if need_restore: self.experiment.items[parent_item_name].insert_child_item(item_name, index) self.experiment.build_item_tree()
def dragMoveEvent(self, e): """ desc: Handles drag-move events to see if the item tree can handle incoming drops. arguments: e: desc: A drag-move event. type: QDragMoveEvent """ data = drag_and_drop.receive(e) self.drop_indicator = None if drag_and_drop.matches(data, [u'url-local']): e.accept() self.end_drag() return if not drag_and_drop.matches(data, [u'item-snippet', u'item-existing']): e.accept() self.end_drag() return target = self.itemAt(e.pos()) if not self.droppable(target, data): self.end_drag() e.ignore() return e.accept() # Update the drop indicator index = self.indexFromItem(target) rect = self.visualRect(index) if target.name == u'__unused__' or ( \ target.item.name in self.experiment.items.used() and \ isinstance(target.item, qtstructure_item) and \ target.item.name != self.experiment.var.start and \ target.parent() is not None): self.drop_indicator = rect else: self.drop_indicator = QtCore.QRect(rect.left(), rect.bottom(), rect.width(), 0) self.viewport().update()
def dragMoveEvent(self, e): """ desc: Handles drag-move events to see if the item tree can handle incoming drops. arguments: e: desc: A drag-move event. type: QDragMoveEvent """ data = drag_and_drop.receive(e) self.drop_indicator = None if drag_and_drop.matches(data, [u"url-local"]): e.accept() self.end_drag() return if not drag_and_drop.matches(data, [u"item-snippet", u"item-existing"]): e.accept() self.end_drag() return target = self.itemAt(e.pos()) if not self.droppable(target, data): self.end_drag() e.ignore() return e.accept() # Update the drop indicator index = self.indexFromItem(target) rect = self.visualRect(index) if target.name == u"__unused__" or ( target.item.name in self.experiment.items.used() and isinstance(target.item, qtstructure_item) and target.item.name != self.experiment.var.start and target.parent() is not None ): self.drop_indicator = rect else: self.drop_indicator = QtCore.QRect(rect.left(), rect.bottom(), rect.width(), 0) self.viewport().update()
def dragMoveEvent(self, e): """ desc: Handles drag-move events to see if the item tree can handle incoming drops. arguments: e: desc: A drag-move event. type: QDragMoveEvent """ data = drag_and_drop.receive(e) self.drop_indicator = None if drag_and_drop.matches(data, [u'url-local']): e.accept() self.end_drag() return if not drag_and_drop.matches(data, [u'item-new', u'item-existing']): e.accept() self.end_drag() return target = self.itemAt(e.pos()) if not self.droppable(target, data): self.end_drag() e.ignore() return e.accept() # Update the drop indicator index = self.indexFromItem(target) rect = self.visualRect(index) if target.name == u'__unused__' or ( target.item.item_type in (u'loop', u'sequence') and \ target.item.name != self.experiment.start and \ target.parent() is not None): self.drop_indicator = rect else: self.drop_indicator = QtCore.QRect(rect.left(), rect.bottom(), rect.width(), 0) self.viewport().update()
def drop_event_item_move(self, data, e): """ desc: Handles drop events for item moves. arguments: data: desc: A drop-data dictionary. type: dict: e: desc: A drop event. type: QDropEvent """ if not drag_and_drop.matches(data, [u'item-existing']): e.ignore() return target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): debug.msg(u'Drop ignored: target not droppable') self.main_window.set_status( _(u'Drop cancelled: Target not droppable')) e.ignore() return target_item_name, target_item_ancestry = target_treeitem.ancestry() item_name = data[u'item-name'] item = self.experiment.items[item_name] if target_item_name in item.children(): debug.msg(u'Drop ignored: recursion prevented') self.main_window.set_status( _(u'Drop cancelled: Recursion prevented')) e.ignore() return parent_item_name, index = self.parent_from_ancestry(data[u'ancestry']) if parent_item_name == None: debug.msg(u'Drop ignored: no parent') e.ignore() return if not QtCore.Qt.ControlModifier & e.keyboardModifiers(): if parent_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to remove item from %s' \ % parent_item_name) else: self.locked = True self.experiment.items[parent_item_name].remove_child_item( item_name, index) self.locked = False self.drop_event_item_new(data, e, target_treeitem=target_treeitem)
def drop_event_item_move(self, data, e): """ desc: Handles drop events for item moves. arguments: data: desc: A drop-data dictionary. type: dict: e: desc: A drop event. type: QDropEvent """ if not drag_and_drop.matches(data, [u'item-existing']): e.ignore() return target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): debug.msg(u'Drop ignored: target not droppable') self.main_window.set_status( _(u'Drop cancelled: Target not droppable')) e.ignore() return target_item_name, target_item_ancestry = target_treeitem.ancestry() item_name = data[u'item-name'] if target_item_ancestry.startswith(u'%s:' % item_name) or \ u'.%s:' % item_name in target_item_ancestry: debug.msg(u'Drop ignored: recursion prevented') self.main_window.set_status( _(u'Drop cancelled: Recursion prevented')) e.ignore() return parent_item_name, index = self.parent_from_ancestry(data[u'ancestry']) if parent_item_name == None: debug.msg(u'Drop ignored: no parent') e.ignore() return if not QtCore.Qt.ControlModifier & e.keyboardModifiers(): if parent_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to remove item from %s' \ % parent_item_name) else: self.experiment.items[parent_item_name].remove_child_item( item_name, index) self.drop_event_item_new(data, e)
def dragEnterEvent(self, e): """ desc: Handles drag-enter events to see if the item tree can handle incoming drops. arguments: e: desc: A drag-enter event. type: QDragEnterEvent """ data = drag_and_drop.receive(e) if drag_and_drop.matches( data, [u'item-new', u'item-existing', u'url-local']): e.accept() else: e.ignore()
def dragEnterEvent(self, e): """ desc: Handles drag-enter events to see if the item tree can handle incoming drops. arguments: e: desc: A drag-enter event. type: QDragEnterEvent """ data = drag_and_drop.receive(e) if drag_and_drop.matches(data, [u"item-new", u"item-existing", u"url-local"]): e.accept() else: e.ignore()
def dragEnterEvent(self, e): """ desc: Handles drag-enter events to see if they are supported arguments: e: desc: A drag-enter event. type: QDragEnterEvent """ if not hasattr(self, u'supported_drop_types'): e.ignore() return data = drag_and_drop.receive(e) if drag_and_drop.matches(data, self.supported_drop_types): e.accept() else: e.ignore()
def dropEvent(self, e): """ desc: Handles drop events and accepts them if supported. arguments: e: desc: A drop event. type: QDropEvent """ if not hasattr(self, u'supported_drop_types'): e.ignore() return data = drag_and_drop.receive(e) if drag_and_drop.matches(data, self.supported_drop_types): e.accept() self.accept_drop(data) else: e.ignore()
def clipboard_data(self): """ desc: Gets an item data dictionary from the clipboard. returns: desc: A data dictionary or None if no valid data was found. type: [dict, NoneType] """ import json from libqtopensesame.misc import drag_and_drop text = QtWidgets.QApplication.clipboard().text() try: data = json.loads(text) except: return None if drag_and_drop.matches(data, [u'item-snippet', u'item-existing']): return data return None
def clipboard_data(self): """ desc: Gets an item data dictionary from the clipboard. returns: desc: A data dictionary or None if no valid data was found. type: [dict, NoneType] """ import json from libqtopensesame.misc import drag_and_drop text = unicode(QtGui.QApplication.clipboard().text()) try: data = json.loads(text) except: return None if drag_and_drop.matches(data, [u'item-new']): return data return None
def drop_event_item_existing(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item moves. arguments: data: desc: A drop-data dictionary. type: dict: e: desc: A drop event. type: QDropEvent """ if not drag_and_drop.matches(data, [u'item-existing']): if e is not None: e.ignore() return # Only accept existing-item drops from this application if data[u'application-id'] != self.main_window._id(): debug.msg(u'Drop ignored: from different instance') if e is not None: e.ignore() return if target_treeitem is None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): debug.msg(u'Drop ignored: target not droppable') if e is not None: e.ignore() return # Don't drop on the same item that was the source (if any) if u'QTreeWidgetItem' in data and \ data[u'QTreeWidgetItem'] == str(target_treeitem): debug.msg(u'Drop ignored: dropping on self') if e is not None: e.ignore() return item_name = data[u'item-name'] # Check for recursion when dropping sequences and loops. The target item # may not have the dropped item in its ancestry. However, the target # item may occur multiple times in the experiment, so we need to check # that this constraint holds for all linked copies of the target item. if data.get(u'structure-item', False): for linked_target_treeitem in self.findItems( target_treeitem.name, QtCore.Qt.MatchFixedString | QtCore.Qt.MatchRecursive): target_item_name, target_item_ancestry = \ linked_target_treeitem.ancestry() if target_item_ancestry.startswith(u'%s:' % item_name) or \ u'.%s:' % item_name in target_item_ancestry: debug.msg(u'Drop ignored: recursion prevented') if e is not None: e.ignore() return # Don't drop on undroppable parents parent_item_name, index = self.parent_from_ancestry(data[u'ancestry']) if parent_item_name is None: debug.msg(u'Drop ignored: no parent') if e is not None: e.ignore() return # The logic below is a bit complicated, but works as follows: # - If we're in a move action, remove the dragged item from its parent, # and set need_restore so that we know this happened. # - Try to drop the dragged item onto the target item # - If the drop action was unsuccesful, and if need_restore is set, # re-add the dragged item to its former parent. need_restore = False if data[u'move']: if parent_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to remove item from %s' \ % parent_item_name) else: self.locked = True need_restore = True self.experiment.items[parent_item_name].remove_child_item( item_name, index) self.locked = False if self.drop_event_item_new(data, e, target_treeitem=target_treeitem): return if need_restore: self.experiment.items[parent_item_name].insert_child_item( item_name, index) self.experiment.build_item_tree()
def drop_event_item_existing(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item moves. arguments: data: desc: A drop-data dictionary. type: dict: e: desc: A drop event. type: QDropEvent """ if not drag_and_drop.matches(data, [u'item-existing']): if e is not None: e.ignore() return # Only accept existing-item drops from this application if data[u'application-id'] != self.main_window._id(): debug.msg(u'Drop ignored: from different instance') if e is not None: e.ignore() return if target_treeitem is None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): debug.msg(u'Drop ignored: target not droppable') if e is not None: e.ignore() return # Don't drop on the same item that was the source (if any) if u'QTreeWidgetItem' in data and \ data[u'QTreeWidgetItem'] == str(target_treeitem): debug.msg(u'Drop ignored: dropping on self') if e is not None: e.ignore() return item_name = data[u'item-name'] # Check for recursion when dropping sequences and loops if data[u'item-type'] in [u'sequence', u'loop']: target_item_name, target_item_ancestry = target_treeitem.ancestry() if target_item_ancestry.startswith(u'%s:' % item_name) or \ u'.%s:' % item_name in target_item_ancestry: debug.msg(u'Drop ignored: recursion prevented') if e is not None: e.ignore() return # Don't drop on undroppable parents parent_item_name, index = self.parent_from_ancestry(data[u'ancestry']) if parent_item_name is None: debug.msg(u'Drop ignored: no parent') if e is not None: e.ignore() return # The logic below is a bit complicated, but works as follows: # - If we're in a move action, remove the dragged item from its parent, # and set need_restore so that we know this happened. # - Try to drop the dragged item onto the target item # - If the drop action was unsuccesful, and if need_restore is set, # re-add the dragged item to its former parent. need_restore = False if data[u'move']: if parent_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to remove item from %s' \ % parent_item_name) else: self.locked = True need_restore = True self.experiment.items[parent_item_name].remove_child_item( item_name, index) self.locked = False if self.drop_event_item_new(data, e, target_treeitem=target_treeitem): return if need_restore: self.experiment.items[parent_item_name].insert_child_item( item_name, index) self.experiment.build_item_tree()
def droppable(self, data): return drag_and_drop.matches(data, [u'item-existing']) and \ data[u'application-id'] == self.main_window._id()
def drop_event_item_new(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item creation. arguments: data: desc: A drop-data dictionary. type: dict: keywords: e: desc: A drop event or None if a target treeitem is provided. type: [QDropEvent, NoneType] target_treeitem: desc: A target tree item or None in a drop event is specified. type: [tree_base_item, NoneType] returns: desc: True if the drop was successful, False otherwise. type: bool """ self.main_window.set_busy(True) if not drag_and_drop.matches(data, [u'item-snippet', u'item-existing']): if e is not None: e.ignore() self.main_window.set_busy(False) return False if data[u'type'] == u'item-existing' and \ data[u'item-name'] not in self.experiment.items: self.experiment.notify(_(u'Cannot create linked copy of "%s". Has ' u'the item been permanently deleted?') % data[u'item-name']) if e is not None: e.ignore() self.main_window.set_busy(False) return False # Ignore drops on non-droppable tree items. if target_treeitem is None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): if e is not None: e.ignore() self.main_window.set_busy(False) return False # Accept drops on the unused items bin and unused items (i.e. items # in the bin) if target_treeitem.name == u'__unused__' or \ (target_treeitem.parent() is not None and \ target_treeitem.parent().name == u'__unused__'): e.accept() self.structure_change.emit() self.main_window.set_busy(False) return True # Get the target item, check if it exists, and, if so, drop the source # item on it. target_item_name = target_treeitem.text(0) if target_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to drop on %s' % target_item_name) if e is not None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) return False target_item = self.experiment.items[target_item_name] if data[u'type'] == u'item-existing': item, new_items = self.drop_get_item_existing(data) else: item, new_items = self.drop_get_item_snippet(data) inserted = False # If the item has no parent or if it is the experiment starting point, # we insert into it directly. if target_treeitem.parent() is None or \ target_item.name == self.experiment.var.start: target_item.insert_child_item(item.name) inserted = True else: if target_item.item_type in (u'loop', u'sequence'): self.main_window.set_busy(False) # Choose appropriate option if target_item.item_type == u'loop': question = _('Set as item to run for %s') % target_item.name icon = u'os-loop' else: question = _('Insert into %s') % target_item.name icon = u'os-sequence' resp = popup_menu(self, [(0, question, icon), (1, _('Insert after %s' % target_item.name), 'list-add') ]).show() # Confirmation if resp == 0 and target_item.item_type == u'loop' and \ target_item.var.item in self.experiment.items: resp = popup_menu(self, [(0, _(u'I know, do it!'), icon)], title=_(u'This will replace %s' % (target_item.item)) ).show() # If the popup was cancelled if resp is None: if e is not None: e.accept() self.main_window.set_busy(False) for item in new_items: del self.experiment.items[item] return False # If the user chose to insert into the target item if resp == 0: target_item.insert_child_item(item.name) inserted = True # Otherwise, we find the parent of the target item, and insert the # new item at the correct position. if not inserted: while True: try: parent_treeitem = target_treeitem.parent() except: # A race condition can occur in which the tree_overview has # been rebuild, thus destroying target_treeitem. If this # happens, we re-take target_treeitem based on the mouse # coordinates. target_treeitem = self.itemAt(e.pos()) parent_treeitem = target_treeitem.parent() if parent_treeitem is None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return False parent_item_name = str(parent_treeitem.text(0)) parent_item = self.experiment.items[parent_item_name] if isinstance(parent_item, sequence): break target_treeitem = parent_treeitem index = parent_treeitem.indexOfChild(target_treeitem)+1 parent_item.insert_child_item(item.name, index=index) if e is not None: e.accept() self.structure_change.emit() if self.overview_mode: item.open_tab() self.main_window.set_busy(False) return True
def drop_event_item_new(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item creation. arguments: data: desc: A drop-data dictionary. type: dict: keywords: e: desc: A drop event or None if a target treeitem is provided. type: [QDropEvent, NoneType] target_treeitem: desc: A target tree item or None in a drop event is specified. type: [tree_base_item, NoneType] returns: desc: True if the drop was successful, False otherwise. type: bool """ self.main_window.set_busy(True) if not drag_and_drop.matches(data, [u"item-snippet", u"item-existing"]): if e is not None: e.ignore() self.main_window.set_busy(False) return False if data[u"type"] == u"item-existing" and data[u"item-name"] not in self.experiment.items: self.experiment.notify( _(u'Cannot create linked copy of "%s". Has ' u"the item been permanently deleted?") % data[u"item-name"] ) if e is not None: e.ignore() self.main_window.set_busy(False) return False # Ignore drops on non-droppable tree items. if target_treeitem is None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): if e is not None: e.ignore() self.main_window.set_busy(False) return False # Accept drops on the unused items bin and unused items (i.e. items # in the bin) if target_treeitem.name == u"__unused__" or ( target_treeitem.parent() is not None and target_treeitem.parent().name == u"__unused__" ): e.accept() self.structure_change.emit() self.main_window.set_busy(False) return True # Get the target item, check if it exists, and, if so, drop the source # item on it. target_item_name = target_treeitem.text(0) if target_item_name not in self.experiment.items: debug.msg(u"Don't know how to drop on %s" % target_item_name) if e is not None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) return False target_item = self.experiment.items[target_item_name] if data[u"type"] == u"item-existing": item, new_items = self.drop_get_item_existing(data) else: # Creating an item may fail, and we therefore need to clean up when # this happens. But we don't catch the Exception itself, because it # will be handled with higher up, for example by the bug_report # extension. try: item = None item, new_items = self.drop_get_item_snippet(data) finally: if item is None: if e is not None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) self.end_drag() inserted = False # If the item has no parent or if it is the experiment starting point, # we insert into it directly. if target_treeitem.parent() is None or target_item.name == self.experiment.var.start: target_item.insert_child_item(item.name) inserted = True else: if isinstance(target_item, qtstructure_item): self.main_window.set_busy(False) resp = popup_menu( self, [ (0, _("Insert into %s") % target_item.name, u"go-next"), (1, _("Insert after %s") % target_item.name, u"go-down"), ], ).show() # If the popup was cancelled if resp is None: if e is not None: e.accept() self.main_window.set_busy(False) for item in new_items: del self.experiment.items[item] return False # If the user chose to insert into the target item if resp == 0: target_item.insert_child_item(item.name) inserted = True # Otherwise, we find the parent of the target item, and insert the # new item at the correct position. if not inserted: while True: try: parent_treeitem = target_treeitem.parent() except: # A race condition can occur in which the tree_overview has # been rebuild, thus destroying target_treeitem. If this # happens, we re-take target_treeitem based on the mouse # coordinates. target_treeitem = self.itemAt(e.pos()) parent_treeitem = target_treeitem.parent() if parent_treeitem is None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return False parent_item_name = str(parent_treeitem.text(0)) parent_item = self.experiment.items[parent_item_name] if isinstance(parent_item, sequence): break target_treeitem = parent_treeitem index = parent_treeitem.indexOfChild(target_treeitem) + 1 parent_item.insert_child_item(item.name, index=index) if e is not None: e.accept() self.structure_change.emit() if self.overview_mode: item.open_tab() self.main_window.set_busy(False) return True
def drop_event_item_existing(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item moves. arguments: data: desc: A drop-data dictionary. type: dict: e: desc: A drop event. type: QDropEvent """ if not drag_and_drop.matches(data, [u"item-existing"]): if e is not None: e.ignore() return # Only accept existing-item drops from this application if data[u"application-id"] != self.main_window._id(): debug.msg(u"Drop ignored: from different instance") if e is not None: e.ignore() return if target_treeitem is None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): debug.msg(u"Drop ignored: target not droppable") if e is not None: e.ignore() return # Don't drop on the same item that was the source (if any) if u"QTreeWidgetItem" in data and data[u"QTreeWidgetItem"] == str(target_treeitem): debug.msg(u"Drop ignored: dropping on self") if e is not None: e.ignore() return item_name = data[u"item-name"] # Check for recursion when dropping sequences and loops. The target item # may not have the dropped item in its ancestry. However, the target # item may occur multiple times in the experiment, so we need to check # that this constraint holds for all linked copies of the target item. if data.get(u"structure-item", False): for linked_target_treeitem in self.findItems( target_treeitem.name, QtCore.Qt.MatchFixedString | QtCore.Qt.MatchRecursive ): target_item_name, target_item_ancestry = linked_target_treeitem.ancestry() if target_item_ancestry.startswith(u"%s:" % item_name) or u".%s:" % item_name in target_item_ancestry: debug.msg(u"Drop ignored: recursion prevented") if e is not None: e.ignore() return # Don't drop on undroppable parents parent_item_name, index = self.parent_from_ancestry(data[u"ancestry"]) if parent_item_name is None: debug.msg(u"Drop ignored: no parent") if e is not None: e.ignore() return # The logic below is a bit complicated, but works as follows: # - If we're in a move action, remove the dragged item from its parent, # and set need_restore so that we know this happened. # - Try to drop the dragged item onto the target item # - If the drop action was unsuccesful, and if need_restore is set, # re-add the dragged item to its former parent. need_restore = False if data[u"move"]: if parent_item_name not in self.experiment.items: debug.msg(u"Don't know how to remove item from %s" % parent_item_name) else: self.locked = True need_restore = True self.experiment.items[parent_item_name].remove_child_item(item_name, index) self.locked = False if self.drop_event_item_new(data, e, target_treeitem=target_treeitem): return if need_restore: self.experiment.items[parent_item_name].insert_child_item(item_name, index) self.experiment.build_item_tree()
def droppable(self, data): return drag_and_drop.matches(data, [u'item-existing'])
def drop_event_item_new(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item creation. arguments: data: desc: A drop-data dictionary. type: dict: keywords: e: desc: A drop event or None if a target treeitem is provided. type: [QDropEvent, NoneType] target_treeitem: desc: A target tree item or None in a drop event is specified. type: [tree_base_item, NoneType] returns: desc: True if the drop was successful, False otherwise. type: bool """ self.main_window.set_busy(True) if not drag_and_drop.matches(data, [u"item-existing", u"item-new"]): if e != None: e.ignore() self.main_window.set_busy(False) return False # Ignore drops on non-droppable tree items. if target_treeitem == None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): if e != None: e.ignore() self.main_window.set_busy(False) return False # Accept drops on the unused items bin and unused items (i.e. items # in the bin) if target_treeitem.name == u"__unused__" or ( target_treeitem.parent() is not None and target_treeitem.parent().name == u"__unused__" ): e.accept() self.structure_change.emit() self.main_window.set_busy(False) return True # Get the target item, check if it exists, and, if so, drop the source # item on it. target_item_name = unicode(target_treeitem.text(0)) if target_item_name not in self.experiment.items: debug.msg(u"Don't know how to drop on %s" % target_item_name) if e != None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) return False target_item = self.experiment.items[target_item_name] # Get the item to be inserted. If the drop type is item-new, we need # to create a new item, otherwise we get an existin item. Also, if # the drop doesn't originate from this application, we create a new # item. if data[u"type"] == u"item-new" or data[u"application-id"] != self.main_window._id(): try: item = self.experiment.items.new(data[u"item-type"], data[u"item-name"], data[u"script"]) except Exception as ex: if not isinstance(e, osexception): ex = osexception(msg=u"Plug-in error", exception=ex) self.notify(u"Failed to load plug-in %s (see debug window for stack trace)" % data[u"item-type"]) self.main_window.print_debug_window(ex) e.accept() self.main_window.set_busy(False) return False self.extension_manager.fire(u"new_item", name=data[u"item-name"], _type=data[u"item-type"]) else: item = self.experiment.items[data[u"item-name"]] inserted = False # If the item has no parent or if it is the experiment starting point, # we insert into it directly. if target_treeitem.parent() == None or target_item.name == self.experiment.start: target_item.insert_child_item(item.name) inserted = True else: if target_item.item_type in (u"loop", u"sequence"): self.main_window.set_busy(False) # Choose appropriate option if target_item.item_type == u"loop": question = _("Set as item to run for %s") % target_item.name icon = u"os-loop" else: question = _("Insert into %s") % target_item.name icon = u"os-sequence" resp = popup_menu( self, [(0, question, icon), (1, _("Insert after %s" % target_item.name), "list-add")] ).show() # Confirmation if resp == 0 and target_item.item_type == u"loop" and target_item.item in self.experiment.items: resp = popup_menu( self, [(0, _(u"I know, do it!"), icon)], title=_(u"This will replace %s" % (target_item.item)) ).show() # If the popup was cancelled if resp == None: e.accept() # Delete the item if it was new or didn't originate from # this application. if data[u"type"] == u"item-new" or data[u"application-id"] != self.main_window._id(): del self.experiment.items[item.name] self.main_window.set_busy(False) return False # If the user chose to insert into the target item if resp == 0: target_item.insert_child_item(item.name) inserted = True # Otherwise, we find the parent of the target item, and insert the # new item at the correct position. if not inserted: while True: try: parent_treeitem = target_treeitem.parent() except: # A race condition can occur in which the tree_overview has # been rebuild, thus destroying target_treeitem. If this # happens, we re-take target_treeitem based on the mouse # coordinates. target_treeitem = self.itemAt(e.pos()) parent_treeitem = target_treeitem.parent() if parent_treeitem == None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return False parent_item_name = unicode(parent_treeitem.text(0)) parent_item = self.experiment.items[parent_item_name] if isinstance(parent_item, sequence): break target_treeitem = parent_treeitem index = parent_treeitem.indexOfChild(target_treeitem) + 1 parent_item.insert_child_item(item.name, index=index) if e != None: e.accept() self.structure_change.emit() if self.overview_mode: item.open_tab() self.main_window.set_busy(False) return True
def drop_event_item_new(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item creation. arguments: data: desc: A drop-data dictionary. type: dict: keywords: e: desc: A drop event or None if a target treeitem is provided. type: [QDropEvent, NoneType] target_treeitem: desc: A target tree item or None in a drop event is specified. type: [tree_base_item, NoneType] """ self.main_window.set_busy(True) if not drag_and_drop.matches(data, [u'item-existing', u'item-new']): if e != None: e.ignore() self.main_window.set_busy(False) return # Ignore drops on non-droppable tree items. if target_treeitem == None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): if e != None: e.ignore() self.main_window.set_busy(False) return # Get the target item, check if it exists, and, if so, drop the source # item on it. target_item_name = unicode(target_treeitem.text(0)) if target_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to drop on %s' % target_item_name) if e != None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) return target_item = self.experiment.items[target_item_name] # Get the item to be inserted. If the drop type is item-new, we need # to create a new item, otherwise we get an existin item. Also, if # the drop doesn't originate from this application, we create a new # item. if data[u'type'] == u'item-new' \ or data[u'application-id'] != self.main_window._id(): try: item = self.experiment.items.new(data[u'item-type'], data[u'item-name'], data[u'script']) except Exception as ex: if not isinstance(e, osexception): ex = osexception(msg=u'Plug-in error', exception=ex) self.notify( u'Failed to load plug-in %s (see debug window for stack trace)' \ % data[u'item-type']) self.main_window.print_debug_window(ex) e.accept() self.main_window.set_busy(False) return self.extension_manager.fire(u'new_item', name=data[u'item-name'], _type=data[u'item-type']) else: item = self.experiment.items[data[u'item-name']] inserted = False # If the item has no parent or if it is the experiment starting point, # we insert into it directly. if target_treeitem.parent() == None or \ target_item.name == self.experiment.start: target_item.insert_child_item(item.name) inserted = True else: if target_item.item_type in (u'loop', u'sequence'): self.main_window.set_busy(False) # Choose appropriate option if target_item.item_type == u'loop': question = _('Set as item to run for %s') % target_item.name icon = u'os-loop' else: question = _('Insert into %s') % target_item.name icon = u'os-sequence' resp = popup_menu(self, [(0, question, icon), (1, _('Insert after %s' % target_item.name), 'list-add') ]).show() # If the popup was cancelled if resp == None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return # If the user chose to insert into the target item if resp == 0: target_item.insert_child_item(item.name) inserted = True # Otherwise, we find the parent of the target item, and insert the # new item at the correct position. if not inserted: while True: try: parent_treeitem = target_treeitem.parent() except: # A race condition can occur in which the tree_overview has # been rebuild, thus destroying target_treeitem. If this # happens, we re-take target_treeitem based on the mouse # coordinates. target_treeitem = self.itemAt(e.pos()) parent_treeitem = target_treeitem.parent() if parent_treeitem == None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return parent_item_name = unicode(parent_treeitem.text(0)) parent_item = self.experiment.items[parent_item_name] if isinstance(parent_item, sequence): break target_treeitem = parent_treeitem index = parent_treeitem.indexOfChild(target_treeitem)+1 parent_item.insert_child_item(item.name, index=index) if e != None: e.accept() self.structure_change.emit() if self.overview_mode: item.open_tab() self.main_window.set_busy(False)
def drop_event_item_new(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item creation. arguments: data: desc: A drop-data dictionary. type: dict: keywords: e: desc: A drop event or None if a target treeitem is provided. type: [QDropEvent, NoneType] target_treeitem: desc: A target tree item or None in a drop event is specified. type: [tree_base_item, NoneType] returns: desc: True if the drop was successful, False otherwise. type: bool """ self.main_window.set_busy(True) if not drag_and_drop.matches(data, [u'item-snippet', u'item-existing']): if e is not None: e.ignore() self.main_window.set_busy(False) return False # Ignore drops on non-droppable tree items. if target_treeitem is None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): if e is not None: e.ignore() self.main_window.set_busy(False) return False # Accept drops on the unused items bin and unused items (i.e. items # in the bin) if target_treeitem.name == u'__unused__' or \ (target_treeitem.parent() is not None and \ target_treeitem.parent().name == u'__unused__'): e.accept() self.structure_change.emit() self.main_window.set_busy(False) return True # Get the target item, check if it exists, and, if so, drop the source # item on it. target_item_name = target_treeitem.text(0) if target_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to drop on %s' % target_item_name) if e is not None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) return False target_item = self.experiment.items[target_item_name] if data[u'type'] == u'item-existing': item, new_items = self.drop_get_item_existing(data) else: item, new_items = self.drop_get_item_snippet(data) inserted = False # If the item has no parent or if it is the experiment starting point, # we insert into it directly. if target_treeitem.parent() is None or \ target_item.name == self.experiment.var.start: target_item.insert_child_item(item.name) inserted = True else: if target_item.item_type in (u'loop', u'sequence'): self.main_window.set_busy(False) # Choose appropriate option if target_item.item_type == u'loop': question = _('Set as item to run for %s') % target_item.name icon = u'os-loop' else: question = _('Insert into %s') % target_item.name icon = u'os-sequence' resp = popup_menu(self, [(0, question, icon), (1, _('Insert after %s' % target_item.name), 'list-add') ]).show() # Confirmation if resp == 0 and target_item.item_type == u'loop' and \ target_item.var.item in self.experiment.items: resp = popup_menu(self, [(0, _(u'I know, do it!'), icon)], title=_(u'This will replace %s' % (target_item.item)) ).show() # If the popup was cancelled if resp is None: if e is not None: e.accept() self.main_window.set_busy(False) for item in new_items: del self.experiment.items[item] return False # If the user chose to insert into the target item if resp == 0: target_item.insert_child_item(item.name) inserted = True # Otherwise, we find the parent of the target item, and insert the # new item at the correct position. if not inserted: while True: try: parent_treeitem = target_treeitem.parent() except: # A race condition can occur in which the tree_overview has # been rebuild, thus destroying target_treeitem. If this # happens, we re-take target_treeitem based on the mouse # coordinates. target_treeitem = self.itemAt(e.pos()) parent_treeitem = target_treeitem.parent() if parent_treeitem is None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return False parent_item_name = str(parent_treeitem.text(0)) parent_item = self.experiment.items[parent_item_name] if isinstance(parent_item, sequence): break target_treeitem = parent_treeitem index = parent_treeitem.indexOfChild(target_treeitem)+1 parent_item.insert_child_item(item.name, index=index) if e is not None: e.accept() self.structure_change.emit() if self.overview_mode: item.open_tab() self.main_window.set_busy(False) return True
def drop_event_item_move(self, data, e): """ desc: Handles drop events for item moves. arguments: data: desc: A drop-data dictionary. type: dict: e: desc: A drop event. type: QDropEvent """ if not drag_and_drop.matches(data, [u'item-existing']): e.ignore() return target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): debug.msg(u'Drop ignored: target not droppable') self.main_window.set_status( _(u'Drop cancelled: Target not droppable')) e.ignore() return # If the drop comes from this application, check for recursion etc. if data[u'application-id'] == self.main_window._id(): target_item_name, target_item_ancestry = target_treeitem.ancestry() item_name = data[u'item-name'] item = self.experiment.items[item_name] if target_item_name in item.children(): debug.msg(u'Drop ignored: recursion prevented') self.main_window.set_status( _(u'Drop cancelled: Recursion prevented')) e.ignore() return parent_item_name, index = self.parent_from_ancestry( data[u'ancestry']) if parent_item_name == None: debug.msg(u'Drop ignored: no parent') e.ignore() return # The logic below is a bit complicated, but works as follows: # - If we're in a move action, remove the dragged item from its parent, # and set need_restore so that we know this happened. # - Try to drop the dragged item onto the target item # - If the drop action was unsuccesful, and if need_restore is set, # re-add the dragged item to its former parent. need_restore = False if not QtCore.Qt.ControlModifier & e.keyboardModifiers() and \ data[u'application-id'] == self.main_window._id(): if parent_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to remove item from %s' \ % parent_item_name) else: self.locked = True need_restore = True self.experiment.items[parent_item_name].remove_child_item( item_name, index) self.locked = False if self.drop_event_item_new(data, e, target_treeitem=target_treeitem): return if need_restore: self.experiment.items[parent_item_name].insert_child_item( item_name, index) self.experiment.build_item_tree()
def drop_event_item_new(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item creation. arguments: data: desc: A drop-data dictionary. type: dict: keywords: e: desc: A drop event or None if a target treeitem is provided. type: [QDropEvent, NoneType] target_treeitem: desc: A target tree item or None in a drop event is specified. type: [tree_base_item, NoneType] returns: desc: True if the drop was successful, False otherwise. type: bool """ self.main_window.set_busy(True) if not drag_and_drop.matches(data, [u'item-existing', u'item-new']): if e != None: e.ignore() self.main_window.set_busy(False) return False # Ignore drops on non-droppable tree items. if target_treeitem == None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): if e != None: e.ignore() self.main_window.set_busy(False) return False # Accept drops on the unused items bin and unused items (i.e. items # in the bin) if target_treeitem.name == u'__unused__' or \ (target_treeitem.parent() is not None and \ target_treeitem.parent().name == u'__unused__'): e.accept() self.structure_change.emit() self.main_window.set_busy(False) return True # Get the target item, check if it exists, and, if so, drop the source # item on it. target_item_name = unicode(target_treeitem.text(0)) if target_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to drop on %s' % target_item_name) if e != None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) return False target_item = self.experiment.items[target_item_name] # Get the item to be inserted. If the drop type is item-new, we need # to create a new item, otherwise we get an existin item. Also, if # the drop doesn't originate from this application, we create a new # item. if data[u'type'] == u'item-new' \ or data[u'application-id'] != self.main_window._id(): try: item = self.experiment.items.new(data[u'item-type'], data[u'item-name'], data[u'script']) except Exception as ex: if not isinstance(e, osexception): ex = osexception(msg=u'Plug-in error', exception=ex) self.notify( u'Failed to load plug-in %s (see debug window for stack trace)' \ % data[u'item-type']) self.main_window.print_debug_window(ex) e.accept() self.main_window.set_busy(False) return False self.extension_manager.fire(u'new_item', name=data[u'item-name'], _type=data[u'item-type']) else: item = self.experiment.items[data[u'item-name']] inserted = False # If the item has no parent or if it is the experiment starting point, # we insert into it directly. if target_treeitem.parent() == None or \ target_item.name == self.experiment.start: target_item.insert_child_item(item.name) inserted = True else: if target_item.item_type in (u'loop', u'sequence'): self.main_window.set_busy(False) # Choose appropriate option if target_item.item_type == u'loop': question = _('Set as item to run for %s') % target_item.name icon = u'os-loop' else: question = _('Insert into %s') % target_item.name icon = u'os-sequence' resp = popup_menu(self, [(0, question, icon), (1, _('Insert after %s' % target_item.name), 'list-add') ]).show() # Confirmation if resp == 0 and target_item.item_type == u'loop' and \ target_item.item in self.experiment.items: resp = popup_menu(self, [(0, _(u'I know, do it!'), icon)], title=_(u'This will replace %s' % (target_item.item)) ).show() # If the popup was cancelled if resp == None: e.accept() # Delete the item if it was new or didn't originate from # this application. if data[u'type'] == u'item-new' \ or data[u'application-id'] != self.main_window._id(): del self.experiment.items[item.name] self.main_window.set_busy(False) return False # If the user chose to insert into the target item if resp == 0: target_item.insert_child_item(item.name) inserted = True # Otherwise, we find the parent of the target item, and insert the # new item at the correct position. if not inserted: while True: try: parent_treeitem = target_treeitem.parent() except: # A race condition can occur in which the tree_overview has # been rebuild, thus destroying target_treeitem. If this # happens, we re-take target_treeitem based on the mouse # coordinates. target_treeitem = self.itemAt(e.pos()) parent_treeitem = target_treeitem.parent() if parent_treeitem == None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return False parent_item_name = unicode(parent_treeitem.text(0)) parent_item = self.experiment.items[parent_item_name] if isinstance(parent_item, sequence): break target_treeitem = parent_treeitem index = parent_treeitem.indexOfChild(target_treeitem)+1 parent_item.insert_child_item(item.name, index=index) if e != None: e.accept() self.structure_change.emit() if self.overview_mode: item.open_tab() self.main_window.set_busy(False) return True
def drop_event_item_new(self, data, e=None, target_treeitem=None): """ desc: Handles drop events for item creation. arguments: data: desc: A drop-data dictionary. type: dict: keywords: e: desc: A drop event or None if a target treeitem is provided. type: [QDropEvent, NoneType] target_treeitem: desc: A target tree item or None in a drop event is specified. type: [tree_base_item, NoneType] returns: desc: True if the drop was successful, False otherwise. type: bool """ self.main_window.set_busy(True) if not drag_and_drop.matches(data, [u'item-snippet', u'item-existing']): if e is not None: e.ignore() self.main_window.set_busy(False) return False if data[u'type'] == u'item-existing' and \ data[u'item-name'] not in self.experiment.items: self.experiment.notify( _(u'Cannot create linked copy of "%s". Has ' u'the item been permanently deleted?') % data[u'item-name']) if e is not None: e.ignore() self.main_window.set_busy(False) return False # Ignore drops on non-droppable tree items. if target_treeitem is None: target_treeitem = self.itemAt(e.pos()) if not self.droppable(target_treeitem, data): if e is not None: e.ignore() self.main_window.set_busy(False) return False # Accept drops on the unused items bin and unused items (i.e. items # in the bin) if target_treeitem.name == u'__unused__' or \ (target_treeitem.parent() is not None and \ target_treeitem.parent().name == u'__unused__'): e.accept() self.structure_change.emit() self.main_window.set_busy(False) return True # Get the target item, check if it exists, and, if so, drop the source # item on it. target_item_name = target_treeitem.text(0) if target_item_name not in self.experiment.items: debug.msg(u'Don\'t know how to drop on %s' % target_item_name) if e is not None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) return False target_item = self.experiment.items[target_item_name] if data[u'type'] == u'item-existing': item, new_items = self.drop_get_item_existing(data) else: # Creating an item may fail, and we therefore need to clean up when # this happens. But we don't catch the Exception itself, because it # will be handled with higher up, for example by the bug_report # extension. try: item = None item, new_items = self.drop_get_item_snippet(data) finally: if item is None: if e is not None: e.ignore() self.structure_change.emit() self.main_window.set_busy(False) self.end_drag() inserted = False # If the item has no parent or if it is the experiment starting point, # we insert into it directly. if target_treeitem.parent() is None or \ target_item.name == self.experiment.var.start: target_item.insert_child_item(item.name) inserted = True else: if isinstance(target_item, qtstructure_item): self.main_window.set_busy(False) resp = popup_menu(self, [ (0, _('Insert into %s') % target_item.name, u'go-next'), (1, _('Insert after %s') % target_item.name, u'go-down') ]).show() # If the popup was cancelled if resp is None: if e is not None: e.accept() self.main_window.set_busy(False) for item in new_items: del self.experiment.items[item] return False # If the user chose to insert into the target item if resp == 0: target_item.insert_child_item(item.name) inserted = True # Otherwise, we find the parent of the target item, and insert the # new item at the correct position. if not inserted: while True: try: parent_treeitem = target_treeitem.parent() except: # A race condition can occur in which the tree_overview has # been rebuild, thus destroying target_treeitem. If this # happens, we re-take target_treeitem based on the mouse # coordinates. target_treeitem = self.itemAt(e.pos()) parent_treeitem = target_treeitem.parent() if parent_treeitem is None: e.accept() del self.experiment.items[item.name] self.main_window.set_busy(False) return False parent_item_name = str(parent_treeitem.text(0)) parent_item = self.experiment.items[parent_item_name] if isinstance(parent_item, sequence): break target_treeitem = parent_treeitem index = parent_treeitem.indexOfChild(target_treeitem) + 1 parent_item.insert_child_item(item.name, index=index) if e is not None: e.accept() self.structure_change.emit() if self.overview_mode: item.open_tab() self.main_window.set_busy(False) return True