From d9710bdcc25ce4e4d3f7497b414bea7c371785c9 Mon Sep 17 00:00:00 2001 From: Benny Malengier Date: Thu, 26 Jul 2012 13:42:10 +0000 Subject: [PATCH] Working drag and drop from listviews to clipboard svn: r20087 --- src/gui/clipboard.py | 61 ++++++++++++++++++++++----------------- src/gui/ddtargets.py | 27 ++++++++++------- src/gui/views/listview.py | 26 ++++++++++++----- 3 files changed, 71 insertions(+), 43 deletions(-) diff --git a/src/gui/clipboard.py b/src/gui/clipboard.py index c11a15621..7bea1c2fe 100644 --- a/src/gui/clipboard.py +++ b/src/gui/clipboard.py @@ -893,9 +893,9 @@ class ClipboardListModel(Gtk.ListStore): #------------------------------------------------------------------------- class ClipboardListView(object): - LOCAL_DRAG_TARGET = Gtk.TargetEntry.new('MY_TREE_MODEL_ROW', - Gtk.TargetFlags.SAME_WIDGET, 0) LOCAL_DRAG_TYPE = 'MY_TREE_MODEL_ROW' + LOCAL_DRAG_ATOM_TYPE = Gdk.atom_intern(LOCAL_DRAG_TYPE, False) + LOCAL_DRAG_TARGET = (LOCAL_DRAG_TYPE, Gtk.TargetFlags.SAME_WIDGET, 0) def __init__(self, dbstate, widget): @@ -952,16 +952,25 @@ class ClipboardListView(object): self._widget.set_enable_search(True) #self._widget.set_search_column(3) - targ_data = (ClipboardListView.LOCAL_DRAG_TARGET,) + \ - DdTargets.all_targets() - self._widget.drag_dest_set(Gtk.DestDefaults.ALL, targ_data, + targ_data = DdTargets.all_dtype() + tglist = Gtk.TargetList.new([]) + tglist.add(ClipboardListView.LOCAL_DRAG_ATOM_TYPE, + ClipboardListView.LOCAL_DRAG_TARGET[1], + ClipboardListView.LOCAL_DRAG_TARGET[2]) + for tg in targ_data: + tglist.add(tg.atom_drag_type, tg.target_flags, tg.app_id) + self._widget.enable_model_drag_dest([], Gdk.DragAction.COPY) + #TODO GTK3: wourkaround here for bug https://bugzilla.gnome.org/show_bug.cgi?id=680638 + self._widget.drag_dest_set_target_list(tglist) + #self._widget.drag_dest_set(Gtk.DestDefaults.ALL, targ_data, + # Gdk.DragAction.COPY) - self._widget.connect('drag_data_get', self.object_drag_data_get) - self._widget.connect('drag_begin', self.object_drag_begin) - self._widget.connect('drag_data_received', + self._widget.connect('drag-data-get', self.object_drag_data_get) + self._widget.connect('drag-begin', self.object_drag_begin) + self._widget.connect('drag-data-received', self.object_drag_data_received) - self._widget.connect('drag_end', self.object_drag_end) + self._widget.connect('drag-end', self.object_drag_end) self.register_wrapper_classes() @@ -1127,12 +1136,13 @@ class ClipboardListView(object): node = model.get_iter(path) if node is not None: o = model.get_value(node,1) - targets += [target.target() for target in o.__class__.DROP_TARGETS] + targets += [target.target_data() for target in o.__class__.DROP_TARGETS] - self._widget.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, targets, - Gdk.DragAction.COPY | Gdk.DragAction.MOVE) + self._widget.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, + targets, + Gdk.DragAction.COPY | Gdk.DragAction.MOVE) - def object_drag_begin(self, context, a): + def object_drag_begin(self, widget, drag_context): """ Handle the beginning of a drag operation. """ pass @@ -1155,13 +1165,12 @@ class ClipboardListView(object): o = model.get_value(node,1) raw_list.append(o.pack()) sel_data.set(sel_data.target, 8, pickle.dumps(raw_list)) - return True - def object_drag_data_received(self,widget,context,x,y,selection,info,time, - title=None, value=None, dbid=None, + def object_drag_data_received(self, widget, context, x, y, selection, info, + time, title=None, value=None, dbid=None, dbname=None): model = widget.get_model() - sel_data = selection.data + sel_data = selection.get_data() # In Windows time is always zero. Until that is fixed, use the seconds # of the local time to filter out double drops. realTime = strftime("%S") @@ -1192,7 +1201,8 @@ class ClipboardListView(object): if dragtype in self._target_type_to_wrapper_class_map: possible_wrappers = [dragtype] else: - possible_wrappers = [target for target in context.targets + tgs = [atm.name() for atm in context.list_targets()] + possible_wrappers = [target for target in tgs if target in self._target_type_to_wrapper_class_map] if len(possible_wrappers) == 0: @@ -1225,7 +1235,7 @@ class ClipboardListView(object): data = [o.__class__.DRAG_TARGET.drag_type, o, None, o._type, o._value, o._dbid, o._dbname] contains = model_contains(model, data) - if context.action != Gdk.DragAction.MOVE and contains: + if context.get_actions() != Gdk.DragAction.MOVE and contains: continue drop_info = widget.get_dest_row_at_pos(x, y) if drop_info: @@ -1242,7 +1252,7 @@ class ClipboardListView(object): # FIXME: there is one bug here: if you multi-select and drop # on self, then it moves the first, and copies the rest. - if context.action == Gdk.DragAction.MOVE: + if context.get_actions() == Gdk.DragAction.MOVE: context.finish(True, True, time) # remember time for double drop workaround. @@ -1332,8 +1342,7 @@ class ClipboardWindow(ManagedWindow): self.set_clear_all_btn_sensitivity) ClipboardWindow.otree.connect('row-inserted', self.set_clear_all_btn_sensitivity) - - + self.object_list.set_model(ClipboardWindow.otree) #Database might have changed, objects might have been removed, @@ -1398,7 +1407,7 @@ class MultiTreeView(Gtk.TreeView): self.dbstate = dbstate self.uistate = uistate self.title = title if title else _("Clipboard") - super(MultiTreeView, self).__init__() + Gtk.TreeView.__init__(self) self.connect('button_press_event', self.on_button_press) self.connect('button_release_event', self.on_button_release) self.connect('key_press_event', self.key_press_event) @@ -1486,12 +1495,12 @@ class MultiTreeView(Gtk.TreeView): and not (event.get_state() & (Gdk.ModifierType.CONTROL_MASK|Gdk.ModifierType.SHIFT_MASK)) and self.get_selection().path_is_selected(target[0])): # disable selection - self.get_selection().set_select_function(lambda *ignore: False) + self.get_selection().set_select_function(lambda *ignore: False, None) self.defer_select = target[0] - + def on_button_release(self, widget, event): # re-enable selection - self.get_selection().set_select_function(lambda *ignore: True) + self.get_selection().set_select_function(lambda *ignore: True, None) target = self.get_path_at_pos(int(event.x), int(event.y)) if (self.defer_select and target diff --git a/src/gui/ddtargets.py b/src/gui/ddtargets.py index 4359a6eee..a79086553 100644 --- a/src/gui/ddtargets.py +++ b/src/gui/ddtargets.py @@ -55,14 +55,16 @@ import logging log = logging.getLogger(".DdTargets") +from gi.repository import Gdk from gi.repository import Gtk class _DdType: """Represents the fields needed by a drag and drop target.""" - _APP_ID_OFFSET = 40 # Starting value of app_ids + _APP_ID_OFFSET = 40L # Starting value of app_ids - def __init__(self, container, drag_type, target_flags=0, app_id=None): + def __init__(self, container, drag_type, + target_flags=0L, app_id=None): """Create a new DdType: drag_type: string holding the name of the type. @@ -71,6 +73,7 @@ class _DdType: """ self.drag_type = drag_type + self.atom_drag_type = Gdk.atom_intern(drag_type, False) self.target_flags = target_flags self.app_id = app_id or self._calculate_id() container.insert(self) @@ -176,13 +179,13 @@ class _DdTargets(object): self.CHILD = _DdType(self, 'child') self.SPOUSE = _DdType(self, 'spouse') - self.TEXT_MIME = _DdType(self, 'text/plain', 0, 0) - self.TEXT = _DdType(self, 'TEXT', 0, 1) - self.STRING = _DdType(self, 'STRING', 0, 2) - self.COMPOUND_TEXT = _DdType(self, 'COMPOUND_TEXT', 0, 3) - self.UTF8_STRING = _DdType(self, 'UTF8_STRING', 0, 4) - self.URI_LIST = _DdType(self, 'text/uri-list', 0, 5) - self.APP_ROOT = _DdType(self, 'application/x-rootwin-drop', 0, 6) + self.TEXT_MIME = _DdType(self, 'text/plain', 0L, 0L) + self.TEXT = _DdType(self, 'TEXT', 0L, 1L) + self.STRING = _DdType(self, 'STRING', 0L, 2L) + self.COMPOUND_TEXT = _DdType(self, 'COMPOUND_TEXT', 0L, 3L) + self.UTF8_STRING = _DdType(self, 'UTF8_STRING', 0L, 4L) + self.URI_LIST = _DdType(self, 'text/uri-list', 0L, 5L) + self.APP_ROOT = _DdType(self, 'application/x-rootwin-drop', 0L, 6L) # List of all the text types. These are types # that can be interpreted as text. @@ -234,7 +237,6 @@ class _DdTargets(object): return tuple([t.target() for t in self._all_text_types]) - def all_gramps_targets(self): """Return a list off the internal gramps targets.""" @@ -244,6 +246,11 @@ class _DdTargets(object): """Return a list of all the known targets.""" return self.all_gramps_targets() + self.all_text_targets() + def all_dtype(self): + """Return all known Ddtype""" + return [x for x in self._all_gramps_types] + \ + [x for x in self._all_text_types] + # Create the singleton instance. DdTargets = _DdTargets() diff --git a/src/gui/views/listview.py b/src/gui/views/listview.py index f6da5309a..a77cc5d4b 100644 --- a/src/gui/views/listview.py +++ b/src/gui/views/listview.py @@ -446,21 +446,23 @@ class ListView(NavigationView): def drag_begin(self, widget, context): widget.drag_source_set_icon_stock(self.get_stock()) - return True def drag_data_get(self, widget, context, sel_data, info, time): selected_ids = self.selected_handles() + #Gtk.selection_add_target(widget, sel_data.get_selection(), + # Gdk.atom_intern(self.drag_info().drag_type, False), + # self.drag_info().app_id) + if len(selected_ids) == 1: data = (self.drag_info().drag_type, id(self), selected_ids[0], 0) - sel_data.set(sel_data.target, 8, pickle.dumps(data)) + sel_data.set(self.drag_info().atom_drag_type, 8, pickle.dumps(data)) elif len(selected_ids) > 1: data = (self.drag_list_info().drag_type, id(self), - [(self.drag_info().drag_type, handle) + [(self.drag_list_info().drag_type, handle) for handle in selected_ids], 0) - sel_data.set(sel_data.target, 8, pickle.dumps(data)) - return True + sel_data.set(self.drag_list_info().atom_drag_type, 8, pickle.dumps(data)) def set_column_order(self): """ @@ -665,13 +667,23 @@ class ListView(NavigationView): if len(selected_ids) == 1: if self.drag_info(): self.list.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, - [self.drag_info().target()], + [], Gdk.DragAction.COPY) + #TODO GTK3: wourkaround here for bug https://bugzilla.gnome.org/show_bug.cgi?id=680638 + tglist = Gtk.TargetList.new([]) + dtype = self.drag_info() + tglist.add(dtype.atom_drag_type, dtype.target_flags, dtype.app_id) + self.list.drag_source_set_target_list(tglist) elif len(selected_ids) > 1: if self.drag_list_info(): self.list.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, - [self.drag_list_info().target()], + [], Gdk.DragAction.COPY) + #TODO GTK3: wourkaround here for bug https://bugzilla.gnome.org/show_bug.cgi?id=680638 + tglist = Gtk.TargetList.new([]) + dtype = self.drag_list_info() + tglist.add(dtype.atom_drag_type, dtype.target_flags, dtype.app_id) + self.list.drag_source_set_target_list(tglist) self.uistate.modify_statusbar(self.dbstate)