Working drag and drop from listviews to clipboard
svn: r20087
This commit is contained in:
parent
bd15d69989
commit
d9710bdcc2
@ -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,
|
||||
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.
|
||||
@ -1333,7 +1343,6 @@ class ClipboardWindow(ManagedWindow):
|
||||
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
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user