use a dialog to rename a contact or a group. fixes #2200
This commit is contained in:
parent
0e1a0c66ee
commit
4fdd526a06
|
@ -17,7 +17,9 @@
|
||||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
<property name="focus_on_map">True</property>
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
<property name="has_separator">False</property>
|
<property name="has_separator">False</property>
|
||||||
|
<signal name="destroy" handler="on_input_dialog_destroy" last_modification_time="Sat, 18 Nov 2006 20:23:21 GMT"/>
|
||||||
|
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<widget class="GtkVBox" id="dialog-vbox10">
|
<widget class="GtkVBox" id="dialog-vbox10">
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ class FTOverwriteConfirmationDialog(ConfirmationDialog):
|
||||||
class InputDialog:
|
class InputDialog:
|
||||||
'''Class for Input dialog'''
|
'''Class for Input dialog'''
|
||||||
def __init__(self, title, label_str, input_str = None, is_modal = True,
|
def __init__(self, title, label_str, input_str = None, is_modal = True,
|
||||||
ok_handler = None):
|
ok_handler = None, cancel_handler = None):
|
||||||
# if modal is True you also need to call get_response()
|
# if modal is True you also need to call get_response()
|
||||||
# and ok_handler won't be used
|
# and ok_handler won't be used
|
||||||
self.xml = gtkgui_helpers.get_glade('input_dialog.glade')
|
self.xml = gtkgui_helpers.get_glade('input_dialog.glade')
|
||||||
|
@ -1011,6 +1011,7 @@ ok_handler = None):
|
||||||
self.input_entry = self.xml.get_widget('input_entry')
|
self.input_entry = self.xml.get_widget('input_entry')
|
||||||
self.dialog.set_title(title)
|
self.dialog.set_title(title)
|
||||||
label.set_markup(label_str)
|
label.set_markup(label_str)
|
||||||
|
self.cancel_handler = cancel_handler
|
||||||
if input_str:
|
if input_str:
|
||||||
self.input_entry.set_text(input_str)
|
self.input_entry.set_text(input_str)
|
||||||
self.input_entry.select_region(0, -1) # select all
|
self.input_entry.select_region(0, -1) # select all
|
||||||
|
@ -1022,11 +1023,19 @@ ok_handler = None):
|
||||||
okbutton.connect('clicked', self.on_okbutton_clicked)
|
okbutton.connect('clicked', self.on_okbutton_clicked)
|
||||||
cancelbutton = self.xml.get_widget('cancelbutton')
|
cancelbutton = self.xml.get_widget('cancelbutton')
|
||||||
cancelbutton.connect('clicked', self.on_cancelbutton_clicked)
|
cancelbutton.connect('clicked', self.on_cancelbutton_clicked)
|
||||||
|
self.xml.signal_autoconnect(self)
|
||||||
self.dialog.show_all()
|
self.dialog.show_all()
|
||||||
|
|
||||||
|
def on_input_dialog_destroy(self, widget):
|
||||||
|
if self.cancel_handler:
|
||||||
|
self.cancel_handler()
|
||||||
|
|
||||||
def on_okbutton_clicked(self, widget):
|
def on_okbutton_clicked(self, widget):
|
||||||
user_input = self.input_entry.get_text().decode('utf-8')
|
user_input = self.input_entry.get_text().decode('utf-8')
|
||||||
self.dialog.destroy()
|
self.dialog.destroy()
|
||||||
|
if isinstance(self.ok_handler, tuple):
|
||||||
|
self.ok_handler[0](user_input, *self.ok_handler[1:])
|
||||||
|
else:
|
||||||
self.ok_handler(user_input)
|
self.ok_handler(user_input)
|
||||||
|
|
||||||
def on_cancelbutton_clicked(self, widget):
|
def on_cancelbutton_clicked(self, widget):
|
||||||
|
|
|
@ -54,9 +54,8 @@ C_NAME, # cellrenderer text that holds contact nickame
|
||||||
C_TYPE, # account, group or contact?
|
C_TYPE, # account, group or contact?
|
||||||
C_JID, # the jid of the row
|
C_JID, # the jid of the row
|
||||||
C_ACCOUNT, # cellrenderer text that holds account name
|
C_ACCOUNT, # cellrenderer text that holds account name
|
||||||
C_EDITABLE, # cellrenderer text that holds name editable or not?
|
|
||||||
C_SECPIXBUF, # secondary_pixbuf (holds avatar or padlock)
|
C_SECPIXBUF, # secondary_pixbuf (holds avatar or padlock)
|
||||||
) = range(7)
|
) = range(6)
|
||||||
|
|
||||||
class RosterWindow:
|
class RosterWindow:
|
||||||
'''Class for main window of the GTK+ interface'''
|
'''Class for main window of the GTK+ interface'''
|
||||||
|
@ -165,7 +164,7 @@ class RosterWindow:
|
||||||
if self.regroup:
|
if self.regroup:
|
||||||
show = helpers.get_global_show()
|
show = helpers.get_global_show()
|
||||||
model.append(None, [self.jabber_state_images['16'][show],
|
model.append(None, [self.jabber_state_images['16'][show],
|
||||||
_('Merged accounts'), 'account', '', 'all', False, None])
|
_('Merged accounts'), 'account', '', 'all', None])
|
||||||
self.draw_account(account)
|
self.draw_account(account)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -180,7 +179,7 @@ class RosterWindow:
|
||||||
|
|
||||||
model.append(None, [self.jabber_state_images['16'][show],
|
model.append(None, [self.jabber_state_images['16'][show],
|
||||||
gtkgui_helpers.escape_for_pango_markup(account),
|
gtkgui_helpers.escape_for_pango_markup(account),
|
||||||
'account', our_jid, account, False, tls_pixbuf])
|
'account', our_jid, account, tls_pixbuf])
|
||||||
|
|
||||||
def draw_account(self, account):
|
def draw_account(self, account):
|
||||||
model = self.tree.get_model()
|
model = self.tree.get_model()
|
||||||
|
@ -313,8 +312,7 @@ class RosterWindow:
|
||||||
name = contact.get_shown_name()
|
name = contact.get_shown_name()
|
||||||
for i in parent_iters:
|
for i in parent_iters:
|
||||||
# we add some values here. see draw_contact for more
|
# we add some values here. see draw_contact for more
|
||||||
model.append(i, (None, name, 'contact', jid, account,
|
model.append(i, (None, name, 'contact', jid, account, None))
|
||||||
False, None))
|
|
||||||
self.draw_contact(jid, account)
|
self.draw_contact(jid, account)
|
||||||
self.draw_avatar(jid, account)
|
self.draw_avatar(jid, account)
|
||||||
# Redraw parent to change icon
|
# Redraw parent to change icon
|
||||||
|
@ -347,7 +345,7 @@ class RosterWindow:
|
||||||
iterG = model.append(IterAcct, [
|
iterG = model.append(IterAcct, [
|
||||||
self.jabber_state_images['16']['closed'],
|
self.jabber_state_images['16']['closed'],
|
||||||
gtkgui_helpers.escape_for_pango_markup(group), 'group',
|
gtkgui_helpers.escape_for_pango_markup(group), 'group',
|
||||||
group, account, False, None])
|
group, account, None])
|
||||||
self.draw_group(group, account)
|
self.draw_group(group, account)
|
||||||
if model.iter_n_children(IterAcct) == 1: # We added the first one
|
if model.iter_n_children(IterAcct) == 1: # We added the first one
|
||||||
self.draw_account(account)
|
self.draw_account(account)
|
||||||
|
@ -366,8 +364,7 @@ class RosterWindow:
|
||||||
|
|
||||||
name = contact.get_shown_name()
|
name = contact.get_shown_name()
|
||||||
# we add some values here. see draw_contact for more
|
# we add some values here. see draw_contact for more
|
||||||
model.append(iterG, (None, name, typestr, contact.jid, account,
|
model.append(iterG, (None, name, typestr, contact.jid, account, None))
|
||||||
False, None))
|
|
||||||
|
|
||||||
if gajim.groups[account][group]['expand']:
|
if gajim.groups[account][group]['expand']:
|
||||||
self.tree.expand_row(model.get_path(iterG), False)
|
self.tree.expand_row(model.get_path(iterG), False)
|
||||||
|
@ -437,7 +434,7 @@ class RosterWindow:
|
||||||
model = self.tree.get_model()
|
model = self.tree.get_model()
|
||||||
iterAcct = self.get_account_iter(account)
|
iterAcct = self.get_account_iter(account)
|
||||||
model.append(iterAcct, (None, gajim.nicks[account], 'self_contact', jid,
|
model.append(iterAcct, (None, gajim.nicks[account], 'self_contact', jid,
|
||||||
account, False, None))
|
account, None))
|
||||||
self.draw_contact(jid, account)
|
self.draw_contact(jid, account)
|
||||||
self.draw_avatar(jid, account)
|
self.draw_avatar(jid, account)
|
||||||
|
|
||||||
|
@ -1397,12 +1394,9 @@ class RosterWindow:
|
||||||
|
|
||||||
def on_rename(self, widget, iter, path):
|
def on_rename(self, widget, iter, path):
|
||||||
# this function is called either by F2 or by Rename menuitem
|
# this function is called either by F2 or by Rename menuitem
|
||||||
# to display that menuitem we show a menu, that does focus-out
|
if gajim.interface.instances.has_key('rename'):
|
||||||
# we then select Rename and focus-in
|
gajim.interface.instances['rename'].dialog.window.present()
|
||||||
# focus-in callback checks on this var and if is NOT None
|
return
|
||||||
# it redraws the selected contact resulting in stopping our rename
|
|
||||||
# procedure. So set this to None to stop that
|
|
||||||
self._last_selected_contact = []
|
|
||||||
model = self.tree.get_model()
|
model = self.tree.get_model()
|
||||||
|
|
||||||
row_type = model[iter][C_TYPE]
|
row_type = model[iter][C_TYPE]
|
||||||
|
@ -1413,16 +1407,66 @@ class RosterWindow:
|
||||||
return
|
return
|
||||||
if row_type in ('contact', 'agent'):
|
if row_type in ('contact', 'agent'):
|
||||||
# it's jid
|
# it's jid
|
||||||
# Remove possible resource indicator (Name (2))
|
title = _('Rename Contact')
|
||||||
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
|
message = _('Enter a new nickname for contact %s') % jid
|
||||||
name = contact.name
|
old_text = gajim.contacts.get_contact_with_highest_priority(account,
|
||||||
model[iter][C_NAME] = gtkgui_helpers.escape_for_pango_markup(name)
|
jid).name
|
||||||
elif row_type == 'group':
|
elif row_type == 'group':
|
||||||
if jid in helpers.special_groups + (_('General'),):
|
if jid in helpers.special_groups + (_('General'),):
|
||||||
return
|
return
|
||||||
|
old_text = model[iter][C_JID].decode('utf-8')
|
||||||
|
title = _('Rename Group')
|
||||||
|
message = _('Enter a new name for group %s') % old_text
|
||||||
|
|
||||||
model[iter][C_EDITABLE] = True # set 'editable' to True
|
def on_renamed(new_text, account, row_type, jid, old_text):
|
||||||
self.tree.set_cursor(path, self.tree.get_column(0), True)
|
if gajim.interface.instances.has_key('rename'):
|
||||||
|
del gajim.interface.instances['rename']
|
||||||
|
if row_type in ('contact', 'agent'):
|
||||||
|
if old_text == new_text:
|
||||||
|
return
|
||||||
|
for u in gajim.contacts.get_contact(account, jid):
|
||||||
|
u.name = new_text
|
||||||
|
gajim.connections[account].update_contact(jid, new_text, u.groups)
|
||||||
|
self.draw_contact(jid, account)
|
||||||
|
# Update opened chat
|
||||||
|
ctrl = gajim.interface.msg_win_mgr.get_control(jid, account)
|
||||||
|
if ctrl:
|
||||||
|
ctrl.update_ui()
|
||||||
|
win = gajim.interface.msg_win_mgr.get_window(jid, account)
|
||||||
|
win.redraw_tab(ctrl)
|
||||||
|
win.show_title()
|
||||||
|
elif row_type == 'group':
|
||||||
|
# in C_JID column, we hold the group name (which is not escaped)
|
||||||
|
if old_text == new_text:
|
||||||
|
return
|
||||||
|
# Groups may not change name from or to a special groups
|
||||||
|
for g in helpers.special_groups:
|
||||||
|
if g in (new_text, old_text):
|
||||||
|
return
|
||||||
|
# get all contacts in that group
|
||||||
|
for jid in gajim.contacts.get_jid_list(account):
|
||||||
|
contact = gajim.contacts.get_contact_with_highest_priority(
|
||||||
|
account, jid)
|
||||||
|
if old_text in contact.groups:
|
||||||
|
# set them in the new one and remove it from the old
|
||||||
|
contact.groups.remove(old_text)
|
||||||
|
self.remove_contact(contact, account)
|
||||||
|
if new_text not in contact.groups:
|
||||||
|
contact.groups.append(new_text)
|
||||||
|
self.add_contact_to_roster(contact.jid, account)
|
||||||
|
gajim.connections[account].update_contact(contact.jid,
|
||||||
|
contact.name, contact.groups)
|
||||||
|
# If last removed iter was not visible, gajim.groups is not cleaned
|
||||||
|
if gajim.groups[account].has_key(old_text):
|
||||||
|
del gajim.groups[account][old_text]
|
||||||
|
|
||||||
|
def on_canceled():
|
||||||
|
if gajim.interface.instances.has_key('rename'):
|
||||||
|
del gajim.interface.instances['rename']
|
||||||
|
|
||||||
|
gajim.interface.instances['rename'] = dialogs.InputDialog(title, message,
|
||||||
|
old_text, False, (on_renamed, account, row_type, jid, old_text),
|
||||||
|
on_canceled)
|
||||||
|
|
||||||
def on_remove_group_item_activated(self, widget, group, account):
|
def on_remove_group_item_activated(self, widget, group, account):
|
||||||
dlg = dialogs.ConfirmationDialogCheck(_('Remove Group'),
|
dlg = dialogs.ConfirmationDialogCheck(_('Remove Group'),
|
||||||
|
@ -2327,10 +2371,8 @@ _('If "%s" accepts this request you will know his or her status.') % jid)
|
||||||
if len(list_of_paths) != 1:
|
if len(list_of_paths) != 1:
|
||||||
return
|
return
|
||||||
path = list_of_paths[0]
|
path = list_of_paths[0]
|
||||||
type = model[path][C_TYPE]
|
type_ = model[path][C_TYPE]
|
||||||
if type in ('contact', 'group', 'agent'):
|
if type_ in ('contact', 'group', 'agent'):
|
||||||
if not model[path][C_EDITABLE]:
|
|
||||||
# we are NOT already renaming it
|
|
||||||
iter = model.get_iter(path)
|
iter = model.get_iter(path)
|
||||||
self.on_rename(widget, iter, path)
|
self.on_rename(widget, iter, path)
|
||||||
|
|
||||||
|
@ -3377,91 +3419,6 @@ _('If "%s" accepts this request you will know his or her status.') % jid)
|
||||||
account = model[iter][C_ACCOUNT].decode('utf-8')
|
account = model[iter][C_ACCOUNT].decode('utf-8')
|
||||||
self.draw_contact(jid, account)
|
self.draw_contact(jid, account)
|
||||||
|
|
||||||
def on_editing_started(self, cell, event, row):
|
|
||||||
''' start editing a cell in the tree'''
|
|
||||||
path = self.tree.get_cursor()[0]
|
|
||||||
self.editing_path = path
|
|
||||||
|
|
||||||
def on_editing_canceled(self, cell):
|
|
||||||
'''editing has been canceled'''
|
|
||||||
path = self.tree.get_cursor()[0]
|
|
||||||
# do not set new name if row order has changed
|
|
||||||
if path != self.editing_path:
|
|
||||||
self.editing_path = None
|
|
||||||
return
|
|
||||||
self.editing_path = None
|
|
||||||
model = self.tree.get_model()
|
|
||||||
iter = model.get_iter(path)
|
|
||||||
account = model[iter][C_ACCOUNT].decode('utf-8')
|
|
||||||
jid = model[iter][C_JID].decode('utf-8')
|
|
||||||
type = model[iter][C_TYPE]
|
|
||||||
# restore the number of resources string at the end of contact name
|
|
||||||
contacts = gajim.contacts.get_contact(account, jid)
|
|
||||||
if type in ('contact', 'agent'):
|
|
||||||
self.draw_contact(jid, account)
|
|
||||||
# reset editable to False
|
|
||||||
model[iter][C_EDITABLE] = False
|
|
||||||
|
|
||||||
def on_cell_edited(self, cell, row, new_text):
|
|
||||||
'''When an iter is edited:
|
|
||||||
if text has changed, rename the contact'''
|
|
||||||
model = self.tree.get_model()
|
|
||||||
# if this is a last item in the group, row is invalid
|
|
||||||
try:
|
|
||||||
iter = model.get_iter_from_string(row)
|
|
||||||
except:
|
|
||||||
self.editing_path = None
|
|
||||||
return
|
|
||||||
path = model.get_path(iter)
|
|
||||||
# do not set new name if row order has changed
|
|
||||||
if path != self.editing_path:
|
|
||||||
self.editing_path = None
|
|
||||||
return
|
|
||||||
self.editing_path = None
|
|
||||||
new_text = new_text.decode('utf-8')
|
|
||||||
account = model[iter][C_ACCOUNT].decode('utf-8')
|
|
||||||
jid = model[iter][C_JID].decode('utf-8')
|
|
||||||
type = model[iter][C_TYPE]
|
|
||||||
model[iter][C_EDITABLE] = False
|
|
||||||
if type in ('contact', 'agent'):
|
|
||||||
old_text = gajim.contacts.get_contact_with_highest_priority(account,
|
|
||||||
jid).name
|
|
||||||
if old_text != new_text:
|
|
||||||
for u in gajim.contacts.get_contact(account, jid):
|
|
||||||
u.name = new_text
|
|
||||||
gajim.connections[account].update_contact(jid, new_text, u.groups)
|
|
||||||
self.draw_contact(jid, account)
|
|
||||||
# Update opened chat
|
|
||||||
ctrl = gajim.interface.msg_win_mgr.get_control(jid, account)
|
|
||||||
if ctrl:
|
|
||||||
ctrl.update_ui()
|
|
||||||
win = gajim.interface.msg_win_mgr.get_window(jid, account)
|
|
||||||
win.redraw_tab(ctrl)
|
|
||||||
win.show_title()
|
|
||||||
elif type == 'group':
|
|
||||||
# in C_JID column, we hold the group name (which is not escaped)
|
|
||||||
old_name = model[iter][C_JID].decode('utf-8')
|
|
||||||
# Groups may not change name from or to a special groups
|
|
||||||
for g in helpers.special_groups:
|
|
||||||
if g in (new_text, old_name):
|
|
||||||
return
|
|
||||||
# get all contacts in that group
|
|
||||||
for jid in gajim.contacts.get_jid_list(account):
|
|
||||||
contact = gajim.contacts.get_contact_with_highest_priority(account,
|
|
||||||
jid)
|
|
||||||
if old_name in contact.groups:
|
|
||||||
# set them in the new one and remove it from the old
|
|
||||||
contact.groups.remove(old_name)
|
|
||||||
self.remove_contact(contact, account)
|
|
||||||
if not new_text in contact.groups:
|
|
||||||
contact.groups.append(new_text)
|
|
||||||
self.add_contact_to_roster(contact.jid, account)
|
|
||||||
gajim.connections[account].update_contact(contact.jid,
|
|
||||||
contact.name, contact.groups)
|
|
||||||
# If last removed iter was not visible, gajim.groups is not cleaned
|
|
||||||
if gajim.groups[account].has_key(old_name):
|
|
||||||
del gajim.groups[account][old_name]
|
|
||||||
|
|
||||||
def on_service_disco_menuitem_activate(self, widget, account):
|
def on_service_disco_menuitem_activate(self, widget, account):
|
||||||
server_jid = gajim.config.get_per('accounts', account, 'hostname')
|
server_jid = gajim.config.get_per('accounts', account, 'hostname')
|
||||||
if gajim.interface.instances[account]['disco'].has_key(server_jid):
|
if gajim.interface.instances[account]['disco'].has_key(server_jid):
|
||||||
|
@ -4128,10 +4085,6 @@ _('If "%s" accepts this request you will know his or her status.') % jid)
|
||||||
|
|
||||||
def _on_treeview_selection_changed(self, selection):
|
def _on_treeview_selection_changed(self, selection):
|
||||||
model, list_of_paths = selection.get_selected_rows()
|
model, list_of_paths = selection.get_selected_rows()
|
||||||
if len(list_of_paths) == 1 and model[list_of_paths[0]][C_EDITABLE]:
|
|
||||||
# We are editing this row, do not modify self._last_selected_contact
|
|
||||||
# Cause that cancel editing
|
|
||||||
return
|
|
||||||
if len(self._last_selected_contact):
|
if len(self._last_selected_contact):
|
||||||
# update unselected rows
|
# update unselected rows
|
||||||
for (jid, account) in self._last_selected_contact:
|
for (jid, account) in self._last_selected_contact:
|
||||||
|
@ -4200,7 +4153,7 @@ _('If "%s" accepts this request you will know his or her status.') % jid)
|
||||||
self.gpg_passphrase = {}
|
self.gpg_passphrase = {}
|
||||||
|
|
||||||
#(icon, name, type, jid, account, editable, secondary_pixbuf)
|
#(icon, name, type, jid, account, editable, secondary_pixbuf)
|
||||||
model = gtk.TreeStore(gtk.Image, str, str, str, str, bool, gtk.gdk.Pixbuf)
|
model = gtk.TreeStore(gtk.Image, str, str, str, str, gtk.gdk.Pixbuf)
|
||||||
|
|
||||||
model.set_sort_func(1, self.compareIters)
|
model.set_sort_func(1, self.compareIters)
|
||||||
model.set_sort_column_id(1, gtk.SORT_ASCENDING)
|
model.set_sort_column_id(1, gtk.SORT_ASCENDING)
|
||||||
|
@ -4297,12 +4250,8 @@ _('If "%s" accepts this request you will know his or her status.') % jid)
|
||||||
col.set_cell_data_func(render_image, self.iconCellDataFunc, None)
|
col.set_cell_data_func(render_image, self.iconCellDataFunc, None)
|
||||||
|
|
||||||
render_text = gtk.CellRendererText() # contact or group or account name
|
render_text = gtk.CellRendererText() # contact or group or account name
|
||||||
render_text.connect('edited', self.on_cell_edited)
|
|
||||||
render_text.connect('editing-canceled', self.on_editing_canceled)
|
|
||||||
render_text.connect('editing-started', self.on_editing_started)
|
|
||||||
col.pack_start(render_text, expand = True)
|
col.pack_start(render_text, expand = True)
|
||||||
col.add_attribute(render_text, 'markup', C_NAME) # where we hold the name
|
col.add_attribute(render_text, 'markup', C_NAME) # where we hold the name
|
||||||
col.add_attribute(render_text, 'editable', C_EDITABLE) # where we hold if the row is editable
|
|
||||||
col.set_cell_data_func(render_text, self.nameCellDataFunc, None)
|
col.set_cell_data_func(render_text, self.nameCellDataFunc, None)
|
||||||
|
|
||||||
render_pixbuf = gtk.CellRendererPixbuf() # tls or avatar img
|
render_pixbuf = gtk.CellRendererPixbuf() # tls or avatar img
|
||||||
|
|
Loading…
Reference in New Issue