Rework roster dnd behaviour. See #3325
This commit is contained in:
parent
c71eed99b8
commit
f974a71b42
|
@ -4750,13 +4750,24 @@ class RosterWindow:
|
||||||
if not confirm_metacontacts: # First time we see this window
|
if not confirm_metacontacts: # First time we see this window
|
||||||
dlg.checkbutton.set_active(True)
|
dlg.checkbutton.set_active(True)
|
||||||
|
|
||||||
def on_drop_in_group(self, widget, account, c_source, grp_dest, context,
|
def on_drop_in_group(self, widget, account, c_source, grp_dest, is_big_brother,
|
||||||
etime, grp_source = None):
|
context, etime, grp_source = None):
|
||||||
if grp_source:
|
if grp_source:
|
||||||
self.remove_contact_from_group(account, c_source, grp_source)
|
self.remove_contact_from_group(account, c_source, grp_source)
|
||||||
# remove tag
|
if not is_big_brother:
|
||||||
gajim.contacts.remove_metacontact(account, c_source.jid)
|
# remove tag before readding
|
||||||
|
gajim.contacts.remove_metacontact(account, c_source.jid)
|
||||||
self.add_contact_to_group(account, c_source, grp_dest)
|
self.add_contact_to_group(account, c_source, grp_dest)
|
||||||
|
if is_big_brother:
|
||||||
|
# add whole metacontact to new group
|
||||||
|
tag = gajim.contacts.get_metacontacts_tag(account, c_source.jid)
|
||||||
|
all_jid = gajim.contacts.get_metacontacts_jids(tag)
|
||||||
|
for _account in all_jid:
|
||||||
|
for _jid in all_jid[_account]:
|
||||||
|
_c = gajim.contacts.get_first_contact_from_jid(_account, _jid)
|
||||||
|
if grp_source:
|
||||||
|
self.remove_contact_from_group(_account, _c, grp_source)
|
||||||
|
self.add_contact_to_group(_account, _c, grp_dest)
|
||||||
if context.action in (gtk.gdk.ACTION_MOVE, gtk.gdk.ACTION_COPY):
|
if context.action in (gtk.gdk.ACTION_MOVE, gtk.gdk.ACTION_COPY):
|
||||||
context.finish(True, True, etime)
|
context.finish(True, True, etime)
|
||||||
|
|
||||||
|
@ -4780,36 +4791,36 @@ class RosterWindow:
|
||||||
|
|
||||||
def drag_data_received_data(self, treeview, context, x, y, selection, info,
|
def drag_data_received_data(self, treeview, context, x, y, selection, info,
|
||||||
etime):
|
etime):
|
||||||
model = treeview.get_model()
|
|
||||||
if not selection.data:
|
|
||||||
return
|
|
||||||
data = selection.data
|
|
||||||
drop_info = treeview.get_dest_row_at_pos(x, y)
|
drop_info = treeview.get_dest_row_at_pos(x, y)
|
||||||
if not drop_info:
|
if not drop_info:
|
||||||
return
|
return
|
||||||
|
if not selection.data:
|
||||||
|
return # prevents tb when several entrys are dragged
|
||||||
|
model = treeview.get_model()
|
||||||
|
data = selection.data
|
||||||
path_dest, position = drop_info
|
path_dest, position = drop_info
|
||||||
|
|
||||||
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2 \
|
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2 \
|
||||||
and path_dest[1] == 0: # dropped before the first group
|
and path_dest[1] == 0: # dropped before the first group
|
||||||
return
|
return
|
||||||
|
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2:
|
||||||
|
# dropped before a group: we drop it in the previous group every time
|
||||||
|
path_dest = (path_dest[0], path_dest[1]-1)
|
||||||
|
# destination: the row something got dropped on
|
||||||
iter_dest = model.get_iter(path_dest)
|
iter_dest = model.get_iter(path_dest)
|
||||||
type_dest = model[iter_dest][C_TYPE].decode('utf-8')
|
type_dest = model[iter_dest][C_TYPE].decode('utf-8')
|
||||||
jid_dest = model[iter_dest][C_JID].decode('utf-8')
|
jid_dest = model[iter_dest][C_JID].decode('utf-8')
|
||||||
account_dest = model[iter_dest][C_ACCOUNT].decode('utf-8')
|
account_dest = model[iter_dest][C_ACCOUNT].decode('utf-8')
|
||||||
|
|
||||||
|
# drop on account row in merged mode, we cannot know the desired account
|
||||||
if account_dest == 'all':
|
if account_dest == 'all':
|
||||||
# drop on account row in merged mode: we can't know which account it is
|
|
||||||
return
|
return
|
||||||
|
# nothing can be done, if destination account is offline
|
||||||
# if account is not connected, do nothing
|
|
||||||
if gajim.connections[account_dest].connected < 2:
|
if gajim.connections[account_dest].connected < 2:
|
||||||
return
|
return
|
||||||
|
|
||||||
# drop on self contact row
|
# A file got dropped on the roster
|
||||||
if type_dest == 'self_contact':
|
|
||||||
return
|
|
||||||
|
|
||||||
if info == self.TARGET_TYPE_URI_LIST:
|
if info == self.TARGET_TYPE_URI_LIST:
|
||||||
# User dropped a file on the roster
|
|
||||||
if len(path_dest) < 3:
|
if len(path_dest) < 3:
|
||||||
return
|
return
|
||||||
if type_dest != 'contact':
|
if type_dest != 'contact':
|
||||||
|
@ -4819,13 +4830,6 @@ class RosterWindow:
|
||||||
uri = data.strip()
|
uri = data.strip()
|
||||||
uri_splitted = uri.split() # we may have more than one file dropped
|
uri_splitted = uri.split() # we may have more than one file dropped
|
||||||
nb_uri = len(uri_splitted)
|
nb_uri = len(uri_splitted)
|
||||||
prim_text = 'Send file?'
|
|
||||||
sec_text = i18n.ngettext('Do you want to send that file to %s:',
|
|
||||||
'Do you want to send those files to %s:', nb_uri) %\
|
|
||||||
c_dest.get_shown_name()
|
|
||||||
for uri in uri_splitted:
|
|
||||||
path = helpers.get_file_path_from_dnd_dropped_uri(uri)
|
|
||||||
sec_text += '\n' + os.path.basename(path)
|
|
||||||
def _on_send_files(widget, account, jid, uris):
|
def _on_send_files(widget, account, jid, uris):
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
c = gajim.contacts.get_contact_with_highest_priority(account, jid)
|
c = gajim.contacts.get_contact_with_highest_priority(account, jid)
|
||||||
|
@ -4834,40 +4838,64 @@ class RosterWindow:
|
||||||
if os.path.isfile(path): # is it file?
|
if os.path.isfile(path): # is it file?
|
||||||
gajim.interface.instances['file_transfers'].send_file(
|
gajim.interface.instances['file_transfers'].send_file(
|
||||||
account, c, path)
|
account, c, path)
|
||||||
|
# Popup dialog to confirm sending
|
||||||
|
prim_text = 'Send file?'
|
||||||
|
sec_text = i18n.ngettext('Do you want to send that file to %s:',
|
||||||
|
'Do you want to send those files to %s:', nb_uri) %\
|
||||||
|
c_dest.get_shown_name()
|
||||||
|
for uri in uri_splitted:
|
||||||
|
path = helpers.get_file_path_from_dnd_dropped_uri(uri)
|
||||||
|
sec_text += '\n' + os.path.basename(path)
|
||||||
dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text,
|
dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text,
|
||||||
on_response_ok = (_on_send_files, account_dest, jid_dest,
|
on_response_ok = (_on_send_files, account_dest, jid_dest,
|
||||||
uri_splitted))
|
uri_splitted))
|
||||||
dialog.popup()
|
dialog.popup()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# a roster entry was dragged and dropped somewhere in the roster
|
||||||
|
|
||||||
if gajim.config.get_per('accounts', account_dest, 'is_zeroconf'):
|
# source: the row that was dragged
|
||||||
# drop on zeroconf account, no contact adds possible
|
|
||||||
return
|
|
||||||
|
|
||||||
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2:
|
|
||||||
# dropped before a group : we drop it in the previous group
|
|
||||||
path_dest = (path_dest[0], path_dest[1]-1)
|
|
||||||
path_source = treeview.get_selection().get_selected_rows()[1][0]
|
path_source = treeview.get_selection().get_selected_rows()[1][0]
|
||||||
iter_source = model.get_iter(path_source)
|
iter_source = model.get_iter(path_source)
|
||||||
type_source = model[iter_source][C_TYPE]
|
type_source = model[iter_source][C_TYPE]
|
||||||
account_source = model[iter_source][C_ACCOUNT].decode('utf-8')
|
account_source = model[iter_source][C_ACCOUNT].decode('utf-8')
|
||||||
if type_source != 'contact': # source is not a contact
|
|
||||||
return
|
# Only normal contacts can be dragged
|
||||||
if type_dest == 'account' and account_source == account_dest:
|
if type_source != 'contact':
|
||||||
return
|
return
|
||||||
if gajim.config.get_per('accounts', account_source, 'is_zeroconf'):
|
if gajim.config.get_per('accounts', account_source, 'is_zeroconf'):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# A contact was dropped
|
||||||
|
if gajim.config.get_per('accounts', account_dest, 'is_zeroconf'):
|
||||||
|
# drop on zeroconf account, adding not possible
|
||||||
|
return
|
||||||
|
if type_dest == 'self_contact':
|
||||||
|
# drop on self contact row
|
||||||
|
return
|
||||||
|
if type_dest == 'account' and account_source == account_dest:
|
||||||
|
# drop on the account it was dragged from
|
||||||
|
return
|
||||||
|
if type_dest == 'groupchat':
|
||||||
|
# drop on a minimized groupchat
|
||||||
|
# TODO: Invite to groupchat
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get valid source group, jid and contact
|
||||||
it = iter_source
|
it = iter_source
|
||||||
while model[it][C_TYPE] == 'contact':
|
while model[it][C_TYPE] == 'contact':
|
||||||
it = model.iter_parent(it)
|
it = model.iter_parent(it)
|
||||||
grp_source = model[it][C_JID].decode('utf-8')
|
grp_source = model[it][C_JID].decode('utf-8')
|
||||||
if grp_source in helpers.special_groups:
|
if grp_source in helpers.special_groups and \
|
||||||
|
grp_source not in ('Not in Roster', 'Observers'):
|
||||||
|
# a transport or a minimized groupchat was dragged
|
||||||
|
# we can add it to other accounts but not move it to another group, see below
|
||||||
return
|
return
|
||||||
jid_source = data.decode('utf-8')
|
jid_source = data.decode('utf-8')
|
||||||
c_source = gajim.contacts.get_contact_with_highest_priority(
|
c_source = gajim.contacts.get_contact_with_highest_priority(
|
||||||
account_source, jid_source)
|
account_source, jid_source)
|
||||||
|
|
||||||
|
# Get destination group
|
||||||
grp_dest = None
|
grp_dest = None
|
||||||
if type_dest == 'group':
|
if type_dest == 'group':
|
||||||
grp_dest = model[iter_dest][C_JID].decode('utf-8')
|
grp_dest = model[iter_dest][C_JID].decode('utf-8')
|
||||||
|
@ -4876,79 +4904,53 @@ class RosterWindow:
|
||||||
while model[it][C_TYPE] != 'group':
|
while model[it][C_TYPE] != 'group':
|
||||||
it = model.iter_parent(it)
|
it = model.iter_parent(it)
|
||||||
grp_dest = model[it][C_JID].decode('utf-8')
|
grp_dest = model[it][C_JID].decode('utf-8')
|
||||||
|
if grp_dest in helpers.special_groups:
|
||||||
if type_dest == 'groupchat':
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if jid_source == jid_dest:
|
||||||
|
if grp_source == grp_dest and account_source == account_dest:
|
||||||
|
# Drop on self
|
||||||
|
return
|
||||||
|
|
||||||
|
# contact drop somewhere in or on a foreign account
|
||||||
if (type_dest == 'account' or not self.regroup) and \
|
if (type_dest == 'account' or not self.regroup) and \
|
||||||
account_source != account_dest:
|
account_source != account_dest:
|
||||||
# add contact to this account in that group
|
# add to account in specified group
|
||||||
dialogs.AddNewContactWindow(account = account_dest, jid = jid_source,
|
dialogs.AddNewContactWindow(account = account_dest, jid = jid_source,
|
||||||
user_nick = c_source.name, group = grp_dest)
|
user_nick = c_source.name, group = grp_dest)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# we may not add contacts from special_groups
|
||||||
|
if grp_source in helpers.special_groups :
|
||||||
|
return
|
||||||
|
|
||||||
# Get destination group
|
# Is the contact we drag a meta contact?
|
||||||
if type_dest == 'group':
|
is_meta_contact = False
|
||||||
if grp_dest in helpers.special_groups:
|
is_big_brother = False
|
||||||
return
|
tag = gajim.contacts.get_metacontacts_tag(account_source, jid_source)
|
||||||
if context.action == gtk.gdk.ACTION_COPY:
|
if tag:
|
||||||
self.on_drop_in_group(None, account_source, c_source, grp_dest,
|
is_meta_contact = True
|
||||||
context, etime)
|
|
||||||
return
|
|
||||||
self.on_drop_in_group(None, account_source, c_source, grp_dest,
|
|
||||||
context, etime, grp_source)
|
|
||||||
return
|
|
||||||
if grp_dest in helpers.special_groups:
|
|
||||||
return
|
|
||||||
if jid_source == jid_dest:
|
|
||||||
if grp_source == grp_dest and account_source == account_dest:
|
|
||||||
return
|
|
||||||
if grp_source == grp_dest:
|
|
||||||
# Add meta contact
|
|
||||||
#FIXME: doesn't work under windows:
|
|
||||||
# http://bugzilla.gnome.org/show_bug.cgi?id=329797
|
|
||||||
# if context.action == gtk.gdk.ACTION_COPY:
|
|
||||||
# # Keep only MOVE
|
|
||||||
# return
|
|
||||||
c_dest = gajim.contacts.get_contact_with_highest_priority(account_dest,
|
|
||||||
jid_dest)
|
|
||||||
is_big_brother = False
|
|
||||||
if model.iter_has_child(iter_source):
|
if model.iter_has_child(iter_source):
|
||||||
is_big_brother = True
|
is_big_brother = True
|
||||||
|
|
||||||
|
# Contact drop on group row or between two contacts
|
||||||
|
if type_dest == 'group' or position == gtk.TREE_VIEW_DROP_BEFORE or \
|
||||||
|
position == gtk.TREE_VIEW_DROP_AFTER:
|
||||||
|
self.on_drop_in_group(None, account_source, c_source, grp_dest,
|
||||||
|
is_big_brother, context, etime, grp_source)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Contact drop on another contact, make meta contacts
|
||||||
|
if position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER or \
|
||||||
|
position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE:
|
||||||
|
c_dest = gajim.contacts.get_contact_with_highest_priority(account_dest,
|
||||||
|
jid_dest)
|
||||||
if not c_dest:
|
if not c_dest:
|
||||||
# c_dest is None if jid_dest doesn't belong to account
|
# c_dest is None if jid_dest doesn't belong to account
|
||||||
return
|
return
|
||||||
self.on_drop_in_contact(treeview, account_source, c_source,
|
self.on_drop_in_contact(treeview, account_source, c_source,
|
||||||
account_dest, c_dest, is_big_brother, context, etime)
|
account_dest, c_dest, is_big_brother, context, etime)
|
||||||
return
|
return
|
||||||
# We upgrade only the first user because user2.groups is a pointer to
|
|
||||||
# user1.groups
|
|
||||||
if context.action == gtk.gdk.ACTION_COPY:
|
|
||||||
self.on_drop_in_group(None, account_source, c_source, grp_dest,
|
|
||||||
context, etime)
|
|
||||||
else:
|
|
||||||
menu = gtk.Menu()
|
|
||||||
item = gtk.MenuItem(_('Drop %s in group %s') % (c_source.name,
|
|
||||||
grp_dest))
|
|
||||||
item.connect('activate', self.on_drop_in_group, account_source,
|
|
||||||
c_source, grp_dest, context, etime, grp_source)
|
|
||||||
menu.append(item)
|
|
||||||
c_dest = gajim.contacts.get_contact_with_highest_priority(
|
|
||||||
account_dest, jid_dest)
|
|
||||||
item = gtk.MenuItem(_('Make %s and %s metacontacts') %
|
|
||||||
(c_source.get_shown_name(), c_dest.get_shown_name()))
|
|
||||||
is_big_brother = False
|
|
||||||
if model.iter_has_child(iter_source):
|
|
||||||
is_big_brother = True
|
|
||||||
item.connect('activate', self.on_drop_in_contact, account_source,
|
|
||||||
c_source, account_dest, c_dest, is_big_brother, context, etime)
|
|
||||||
|
|
||||||
menu.append(item)
|
|
||||||
|
|
||||||
menu.attach_to_widget(self.tree, None)
|
|
||||||
menu.connect('selection-done', gtkgui_helpers.destroy_widget)
|
|
||||||
menu.show_all()
|
|
||||||
menu.popup(None, None, None, 1, etime)
|
|
||||||
|
|
||||||
def show_title(self):
|
def show_title(self):
|
||||||
change_title_allowed = gajim.config.get('change_roster_title')
|
change_title_allowed = gajim.config.get('change_roster_title')
|
||||||
|
|
Loading…
Reference in New Issue