diff --git a/data/glade/input_dialog.glade b/data/glade/input_dialog.glade index 141127c11..77b17f1f2 100644 --- a/data/glade/input_dialog.glade +++ b/data/glade/input_dialog.glade @@ -17,7 +17,9 @@ GDK_WINDOW_TYPE_HINT_DIALOG GDK_GRAVITY_NORTH_WEST True + False False + diff --git a/src/dialogs.py b/src/dialogs.py index afb53b83a..a49a60dc2 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -1002,7 +1002,7 @@ class FTOverwriteConfirmationDialog(ConfirmationDialog): class InputDialog: '''Class for Input dialog''' 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() # and ok_handler won't be used 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.dialog.set_title(title) label.set_markup(label_str) + self.cancel_handler = cancel_handler if input_str: self.input_entry.set_text(input_str) self.input_entry.select_region(0, -1) # select all @@ -1022,14 +1023,22 @@ ok_handler = None): okbutton.connect('clicked', self.on_okbutton_clicked) cancelbutton = self.xml.get_widget('cancelbutton') cancelbutton.connect('clicked', self.on_cancelbutton_clicked) + self.xml.signal_autoconnect(self) self.dialog.show_all() - def on_okbutton_clicked(self, widget): + def on_input_dialog_destroy(self, widget): + if self.cancel_handler: + self.cancel_handler() + + def on_okbutton_clicked(self, widget): user_input = self.input_entry.get_text().decode('utf-8') self.dialog.destroy() - self.ok_handler(user_input) + if isinstance(self.ok_handler, tuple): + self.ok_handler[0](user_input, *self.ok_handler[1:]) + else: + self.ok_handler(user_input) - def on_cancelbutton_clicked(self, widget): + def on_cancelbutton_clicked(self, widget): self.dialog.destroy() def get_response(self): diff --git a/src/roster_window.py b/src/roster_window.py index 1d44460a5..4ecaabfea 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -54,9 +54,8 @@ C_NAME, # cellrenderer text that holds contact nickame C_TYPE, # account, group or contact? C_JID, # the jid of the row 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) -) = range(7) +) = range(6) class RosterWindow: '''Class for main window of the GTK+ interface''' @@ -165,7 +164,7 @@ class RosterWindow: if self.regroup: show = helpers.get_global_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) return @@ -180,7 +179,7 @@ class RosterWindow: model.append(None, [self.jabber_state_images['16'][show], 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): model = self.tree.get_model() @@ -313,8 +312,7 @@ class RosterWindow: name = contact.get_shown_name() for i in parent_iters: # we add some values here. see draw_contact for more - model.append(i, (None, name, 'contact', jid, account, - False, None)) + model.append(i, (None, name, 'contact', jid, account, None)) self.draw_contact(jid, account) self.draw_avatar(jid, account) # Redraw parent to change icon @@ -347,7 +345,7 @@ class RosterWindow: iterG = model.append(IterAcct, [ self.jabber_state_images['16']['closed'], gtkgui_helpers.escape_for_pango_markup(group), 'group', - group, account, False, None]) + group, account, None]) self.draw_group(group, account) if model.iter_n_children(IterAcct) == 1: # We added the first one self.draw_account(account) @@ -366,8 +364,7 @@ class RosterWindow: name = contact.get_shown_name() # we add some values here. see draw_contact for more - model.append(iterG, (None, name, typestr, contact.jid, account, - False, None)) + model.append(iterG, (None, name, typestr, contact.jid, account, None)) if gajim.groups[account][group]['expand']: self.tree.expand_row(model.get_path(iterG), False) @@ -437,7 +434,7 @@ class RosterWindow: model = self.tree.get_model() iterAcct = self.get_account_iter(account) model.append(iterAcct, (None, gajim.nicks[account], 'self_contact', jid, - account, False, None)) + account, None)) self.draw_contact(jid, account) self.draw_avatar(jid, account) @@ -1397,12 +1394,9 @@ class RosterWindow: def on_rename(self, widget, iter, path): # this function is called either by F2 or by Rename menuitem - # to display that menuitem we show a menu, that does focus-out - # we then select Rename and focus-in - # focus-in callback checks on this var and if is NOT None - # it redraws the selected contact resulting in stopping our rename - # procedure. So set this to None to stop that - self._last_selected_contact = [] + if gajim.interface.instances.has_key('rename'): + gajim.interface.instances['rename'].dialog.window.present() + return model = self.tree.get_model() row_type = model[iter][C_TYPE] @@ -1413,16 +1407,66 @@ class RosterWindow: return if row_type in ('contact', 'agent'): # it's jid - # Remove possible resource indicator (Name (2)) - contact = gajim.contacts.get_first_contact_from_jid(account, jid) - name = contact.name - model[iter][C_NAME] = gtkgui_helpers.escape_for_pango_markup(name) + title = _('Rename Contact') + message = _('Enter a new nickname for contact %s') % jid + old_text = gajim.contacts.get_contact_with_highest_priority(account, + jid).name elif row_type == 'group': if jid in helpers.special_groups + (_('General'),): 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 - self.tree.set_cursor(path, self.tree.get_column(0), True) + def on_renamed(new_text, account, row_type, jid, old_text): + 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): dlg = dialogs.ConfirmationDialogCheck(_('Remove Group'), @@ -2327,12 +2371,10 @@ _('If "%s" accepts this request you will know his or her status.') % jid) if len(list_of_paths) != 1: return path = list_of_paths[0] - type = model[path][C_TYPE] - if type in ('contact', 'group', 'agent'): - if not model[path][C_EDITABLE]: - # we are NOT already renaming it - iter = model.get_iter(path) - self.on_rename(widget, iter, path) + type_ = model[path][C_TYPE] + if type_ in ('contact', 'group', 'agent'): + iter = model.get_iter(path) + self.on_rename(widget, iter, path) elif event.keyval == gtk.keysyms.Delete: treeselection = self.tree.get_selection() @@ -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') 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): server_jid = gajim.config.get_per('accounts', account, 'hostname') 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): 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): # update unselected rows 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 = {} #(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_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) 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.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) render_pixbuf = gtk.CellRendererPixbuf() # tls or avatar img