From 9fa3a1b5580d3e7598f1b0a0664a1c0d79a85c0f Mon Sep 17 00:00:00 2001 From: GRiker Date: Sun, 3 Mar 2013 05:28:29 -0800 Subject: [PATCH] Revisions enabling a plugin to receive drag/drop events - take 2 --- src/calibre/gui2/actions/__init__.py | 15 ++++++++ src/calibre/gui2/bars.py | 55 +++++++++++++++------------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index fa67130a1c..ef731ed0b1 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -101,6 +101,11 @@ class InterfaceAction(QObject): #: on calibre as a whole action_type = 'global' + #: If True, the action may inspect the event at accept_enter_event() and + #: accept_drag_move_event(), returning True or False if it wants to handle the event. + #: drop_event() will be called in the subclass from calibre.gui2.bars + accepts_drops = False + def __init__(self, parent, site_customization): QObject.__init__(self, parent) self.setObjectName(self.name) @@ -108,6 +113,15 @@ class InterfaceAction(QObject): self.site_customization = site_customization self.interface_action_base_plugin = None + def accept_enter_event(self, mime_data): + return False + + def accept_drag_move_event(self, mime_data): + return False + + def drop_event(self, event): + pass + def do_genesis(self): self.Dispatcher = partial(Dispatcher, parent=self) self.create_action() @@ -131,6 +145,7 @@ class InterfaceAction(QObject): else: action = QAction(text, self.gui) if attr == 'qaction': + action.associated_interface_action = self mt = (action.text() if self.action_menu_clone_qaction is True else unicode(self.action_menu_clone_qaction)) self.menuless_qaction = ma = QAction(action.icon(), mt, self.gui) diff --git a/src/calibre/gui2/bars.py b/src/calibre/gui2/bars.py index 38643fb40f..8267eca430 100644 --- a/src/calibre/gui2/bars.py +++ b/src/calibre/gui2/bars.py @@ -8,8 +8,8 @@ __copyright__ = '2011, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from PyQt4.Qt import (QObject, QToolBar, Qt, QSize, QToolButton, QVBoxLayout, - QLabel, QWidget, QAction, QMenuBar, QMenu) +from PyQt4.Qt import (Qt, QAction, QLabel, QMenu, QMenuBar, QObject, + QToolBar, QToolButton, QSize, QVBoxLayout, QWidget) from calibre.constants import isosx from calibre.gui2 import gprefs @@ -116,29 +116,29 @@ class ToolBar(QToolBar): # {{{ ch.setPopupMode(menu_mode) return ch - #support drag&drop from/to library from/to reader/card + # support drag&drop from/to library, from/to reader/card, enabled plugins def dragEnterEvent(self, event): md = event.mimeData() if md.hasFormat("application/calibre+from_library") or \ md.hasFormat("application/calibre+from_device"): event.setDropAction(Qt.CopyAction) event.accept() - elif self.added_actions: - # Give added_actions an opportunity to process the drag&drop event - # This calls the first QMenu object that accepts drops, rather than the - # specific one that was dropped on for aa in self.added_actions: - if aa.menu() is not None and aa.menu().acceptDrops(): - aa.menu().dragEnterEvent(event) - break + if (getattr(aa.associated_interface_action, 'accepts_drops', False) and + aa.menu().geometry().contains(event.pos())): + if aa.associated_interface_action.accept_enter_event(md): + event.accept() + break + else: + event.ignore() else: event.ignore() def dragMoveEvent(self, event): allowed = False md = event.mimeData() - #Drop is only allowed in the location manager widget's different from the selected one + # Drop is only allowed in the location manager widget's different from the selected one for ac in self.location_manager.available_actions: w = self.widgetForAction(ac) if w is not None: @@ -150,21 +150,22 @@ class ToolBar(QToolBar): # {{{ break if allowed: event.acceptProposedAction() + return - elif self.added_actions: - # Give added_actions an opportunity to process the drag&drop event - # This calls the first QMenu object that accepts drops, rather than the - # specific one that was dropped on + if self.added_actions: for aa in self.added_actions: - if aa.menu() is not None and aa.menu().acceptDrops(): - aa.menu().dragMoveEvent(event) - break + if (getattr(aa.associated_interface_action, 'accepts_drops', False) and + aa.menu().geometry().contains(event.pos())): + if aa.associated_interface_action.accept_drag_move_event(md): + event.acceptProposedAction() + break + else: + event.ignore() else: event.ignore() def dropEvent(self, event): data = event.mimeData() - mime = 'application/calibre+from_library' if data.hasFormat(mime): ids = list(map(int, str(data.data(mime)).split())) @@ -178,6 +179,7 @@ class ToolBar(QToolBar): # {{{ tgt = None self.gui.sync_to_device(tgt, False, send_ids=ids) event.accept() + return mime = 'application/calibre+from_device' if data.hasFormat(mime): @@ -186,15 +188,16 @@ class ToolBar(QToolBar): # {{{ self.gui.iactions['Add Books'].add_books_from_device( self.gui.current_view(), paths=paths) event.accept() + return # Give added_actions an opportunity to process the drag&drop event - # This calls the first QMenu object that accepts drops, rather than the - # specific one that was dropped on - if self.added_actions: - for aa in self.added_actions: - if aa.menu() is not None and aa.menu().acceptDrops(): - aa.menu().dropEvent(event) - break + for aa in self.added_actions: + if (getattr(aa.associated_interface_action, 'accepts_drops', False) and + aa.menu().geometry().contains(event.pos())): + aa.associated_interface_action.drop_event(event) + event.accept() + else: + event.ignore() # }}}