]> git.0d.be Git - empathy.git/blob - src/empathy-accounts-dialog.c
Merge branch 'master'; commit 'jtellier/set-account-name'
[empathy.git] / src / empathy-accounts-dialog.c
1 /*
2  * Copyright (C) 2005-2007 Imendio AB
3  * Copyright (C) 2007-2009 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Martyn Russell <martyn@imendio.com>
21  *          Xavier Claessens <xclaesse@gmail.com>
22  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
23  *          Jonathan Tellier <jonathan.tellier@gmail.com>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include <gtk/gtk.h>
32 #include <glib/gi18n.h>
33 #include <dbus/dbus-glib.h>
34
35 #include <telepathy-glib/util.h>
36
37 #include <libempathy/empathy-utils.h>
38 #include <libempathy/empathy-account-manager.h>
39 #include <libempathy/empathy-connection-managers.h>
40 #include <libempathy-gtk/empathy-ui-utils.h>
41
42 #include <libempathy-gtk/empathy-protocol-chooser.h>
43 #include <libempathy-gtk/empathy-account-widget.h>
44 #include <libempathy-gtk/empathy-account-widget-irc.h>
45 #include <libempathy-gtk/empathy-account-widget-sip.h>
46 #include <libempathy-gtk/empathy-cell-renderer-activatable.h>
47 #include <libempathy-gtk/empathy-conf.h>
48 #include <libempathy-gtk/empathy-images.h>
49
50 #include "empathy-accounts-dialog.h"
51 #include "empathy-import-dialog.h"
52 #include "empathy-import-utils.h"
53
54 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
55 #include <libempathy/empathy-debug.h>
56
57 /* Flashing delay for icons (milliseconds). */
58 #define FLASH_TIMEOUT 500
59
60 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountsDialog)
61 G_DEFINE_TYPE (EmpathyAccountsDialog, empathy_accounts_dialog, G_TYPE_OBJECT);
62
63 static EmpathyAccountsDialog *dialog_singleton = NULL;
64
65 typedef struct {
66   GtkWidget *window;
67
68   GtkWidget *alignment_settings;
69
70   GtkWidget *vbox_details;
71   GtkWidget *frame_no_protocol;
72
73   GtkWidget *treeview;
74
75   GtkWidget *button_add;
76
77   GtkWidget *frame_new_account;
78   GtkWidget *combobox_protocol;
79   GtkWidget *hbox_type;
80   GtkWidget *button_create;
81   GtkWidget *button_back;
82   GtkWidget *radiobutton_reuse;
83   GtkWidget *radiobutton_register;
84
85   GtkWidget *image_type;
86   GtkWidget *label_name;
87   GtkWidget *label_type;
88   GtkWidget *settings_widget;
89
90   gboolean  connecting_show;
91   guint connecting_id;
92
93   gulong  settings_ready_id;
94   EmpathyAccountSettings *settings_ready;
95
96   EmpathyAccountManager *account_manager;
97   EmpathyConnectionManagers *cms;
98
99   GtkWindow *parent_window;
100   EmpathyAccount *initial_selection;
101 } EmpathyAccountsDialogPriv;
102
103 enum {
104   COL_NAME,
105   COL_STATUS,
106   COL_ACCOUNT_POINTER,
107   COL_ACCOUNT_SETTINGS_POINTER,
108   COL_COUNT
109 };
110
111 enum {
112   PROP_PARENT = 1
113 };
114
115 static void accounts_dialog_account_display_name_changed_cb (
116     EmpathyAccount *account,
117     GParamSpec *pspec,
118     gpointer user_data);
119
120 static EmpathyAccountSettings * accounts_dialog_model_get_selected_settings (
121     EmpathyAccountsDialog *dialog);
122
123 static void accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog);
124
125 static void accounts_dialog_update (EmpathyAccountsDialog *dialog,
126     EmpathyAccountSettings *settings);
127
128 static void accounts_dialog_update_settings (EmpathyAccountsDialog *dialog,
129     EmpathyAccountSettings *settings);
130
131 static void
132 accounts_dialog_update_name_label (EmpathyAccountsDialog *dialog,
133     const gchar *display_name)
134 {
135   gchar *text;
136   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
137
138   text = g_markup_printf_escaped ("<big><b>%s</b></big>", display_name);
139   gtk_label_set_markup (GTK_LABEL (priv->label_name), text);
140
141   g_free (text);
142 }
143
144 static void
145 empathy_account_dialog_widget_cancelled_cb (EmpathyAccountWidget *widget_object,
146     EmpathyAccountsDialog *dialog)
147 {
148   GtkTreeView *view;
149   GtkTreeModel *model;
150   GtkTreeSelection *selection;
151   GtkTreeIter iter;
152   EmpathyAccountSettings *settings;
153   EmpathyAccount *account;
154   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
155
156   view = GTK_TREE_VIEW (priv->treeview);
157   selection = gtk_tree_view_get_selection (view);
158
159   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
160     return;
161
162   gtk_tree_model_get (model, &iter,
163       COL_ACCOUNT_SETTINGS_POINTER, &settings,
164       COL_ACCOUNT_POINTER, &account, -1);
165
166   empathy_account_settings_discard_changes (settings);
167
168   if (account == NULL)
169     {
170       /* We were creating an account. We remove the selected row */
171       gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
172     }
173   else
174     {
175       /* We were modifying an account. We discard the changes by reloading the
176        * settings and the UI. */
177       accounts_dialog_update_settings (dialog, settings);
178       g_object_unref (account);
179     }
180
181   if (settings != NULL)
182     g_object_unref (settings);
183 }
184
185 static gchar *
186 get_default_display_name (EmpathyAccountSettings *settings)
187 {
188   const gchar *login_id;
189   const gchar *protocol;
190   gchar *default_display_name;
191
192   login_id = empathy_account_settings_get_string (settings, "account");
193   protocol = empathy_account_settings_get_protocol (settings);
194
195   if (login_id != NULL)
196     {
197       if (!tp_strdiff(protocol, "irc"))
198         {
199           const gchar* server;
200           server = empathy_account_settings_get_string (settings, "server");
201
202           /* To translators: The first parameter is the login id and the
203            * second one is the server. The resulting string will be something
204            * like: "MyUserName on chat.freenode.net" */
205           default_display_name =
206               g_strdup_printf (_("%s on %s"), login_id, server);
207         }
208       else
209         {
210           default_display_name = g_strdup (login_id);
211         }
212     }
213   else if (protocol != NULL)
214     {
215       /* To translators: The parameter is the protocol name. The resulting
216        * string will be something like: "Jabber Account" */
217       default_display_name = g_strdup_printf (_("%s Account"), protocol);
218     }
219   else
220     {
221       default_display_name = g_strdup (_("New account"));
222     }
223
224   return default_display_name;
225 }
226
227 static void
228 empathy_account_dialog_account_created_cb (EmpathyAccountWidget *widget_object,
229     EmpathyAccountsDialog *dialog)
230 {
231   gchar *display_name;
232   EmpathyAccountSettings *settings =
233       accounts_dialog_model_get_selected_settings (dialog);
234
235   display_name = get_default_display_name (settings);
236
237   empathy_account_settings_set_display_name_async (settings,
238       display_name, NULL, NULL);
239
240   g_free (display_name);
241
242   accounts_dialog_update_settings (dialog, settings);
243
244   if (settings)
245     g_object_unref (settings);
246 }
247
248 static GtkWidget *
249 get_account_setup_widget (EmpathyAccountSettings *settings,
250     EmpathyAccountWidget **widget_object)
251 {
252   const gchar *proto = empathy_account_settings_get_protocol (settings);
253   EmpathyConnectionManagers *cm =
254       empathy_connection_managers_dup_singleton ();
255   GList *cms = empathy_connection_managers_get_cms (cm);
256   GList *l;
257
258   for (l = cms; l; l = l->next)
259     {
260       TpConnectionManager *tp_cm = l->data;
261       if (tp_connection_manager_has_protocol (tp_cm, proto))
262         {
263           g_object_unref (cm);
264           *widget_object = empathy_account_widget_new_for_protocol (proto,
265               settings, FALSE);
266           return empathy_account_widget_get_widget (*widget_object);
267         }
268     }
269
270   g_object_unref (cm);
271   *widget_object = empathy_account_widget_new_for_protocol ("generic", settings,
272       FALSE);
273   return empathy_account_widget_get_widget (*widget_object);
274 }
275
276 static void
277 account_dialog_create_settings_widget (EmpathyAccountsDialog *dialog,
278     EmpathyAccountSettings *settings)
279 {
280   EmpathyAccountWidget *widget_object = NULL;
281   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
282   gchar *icon_name;
283
284   priv->settings_widget = get_account_setup_widget (settings, &widget_object);
285   g_signal_connect (widget_object, "account-created",
286         G_CALLBACK (empathy_account_dialog_account_created_cb), dialog);
287   g_signal_connect (widget_object, "cancelled",
288           G_CALLBACK (empathy_account_dialog_widget_cancelled_cb), dialog);
289
290   gtk_container_add (GTK_CONTAINER (priv->alignment_settings),
291       priv->settings_widget);
292   gtk_widget_show (priv->settings_widget);
293
294   icon_name = empathy_account_settings_get_icon_name (settings);
295
296   gtk_image_set_from_icon_name (GTK_IMAGE (priv->image_type),
297       icon_name, GTK_ICON_SIZE_DIALOG);
298   gtk_widget_set_tooltip_text (priv->image_type,
299       empathy_protocol_name_to_display_name
300       (empathy_account_settings_get_protocol (settings)));
301
302   accounts_dialog_update_name_label (dialog,
303       empathy_account_settings_get_display_name (settings));
304 }
305
306 static void
307 account_dialog_settings_ready_cb (EmpathyAccountSettings *settings,
308     GParamSpec *spec,
309     EmpathyAccountsDialog *dialog)
310 {
311   if (empathy_account_settings_is_ready (settings))
312     account_dialog_create_settings_widget (dialog, settings);
313 }
314
315 static void
316 accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog)
317 {
318   GtkTreeView      *view;
319   GtkTreeModel     *model;
320   GtkTreeSelection *selection;
321   GtkTreeIter       iter;
322   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
323
324   /* select first */
325   view = GTK_TREE_VIEW (priv->treeview);
326   model = gtk_tree_view_get_model (view);
327
328   if (gtk_tree_model_get_iter_first (model, &iter))
329     {
330       selection = gtk_tree_view_get_selection (view);
331       gtk_tree_selection_select_iter (selection, &iter);
332     }
333   else
334     {
335       accounts_dialog_update_settings (dialog, NULL);
336     }
337 }
338
339 static void
340 accounts_dialog_protocol_changed_cb (GtkWidget *widget,
341     EmpathyAccountsDialog *dialog)
342 {
343   TpConnectionManager *cm;
344   TpConnectionManagerProtocol *proto;
345   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
346
347   cm = empathy_protocol_chooser_dup_selected (
348       EMPATHY_PROTOCOL_CHOOSER (priv->combobox_protocol), &proto);
349
350   if (cm == NULL)
351     return;
352
353   if (proto == NULL)
354     {
355       g_object_unref (cm);
356       return;
357     }
358
359   if (tp_connection_manager_protocol_can_register (proto))
360     {
361       gtk_widget_show (priv->radiobutton_register);
362       gtk_widget_show (priv->radiobutton_reuse);
363     }
364   else
365     {
366       gtk_widget_hide (priv->radiobutton_register);
367       gtk_widget_hide (priv->radiobutton_reuse);
368     }
369   g_object_unref (cm);
370 }
371
372 static void
373 accounts_dialog_button_add_clicked_cb (GtkWidget *button,
374     EmpathyAccountsDialog *dialog)
375 {
376   GtkTreeView      *view;
377   GtkTreeModel     *model;
378   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
379
380   view = GTK_TREE_VIEW (priv->treeview);
381   model = gtk_tree_view_get_model (view);
382
383   gtk_widget_set_sensitive (priv->button_add, FALSE);
384   gtk_widget_hide (priv->vbox_details);
385   gtk_widget_hide (priv->frame_no_protocol);
386   gtk_widget_show (priv->frame_new_account);
387
388   /* If we have no account, no need of a back button */
389   if (gtk_tree_model_iter_n_children (model, NULL) > 0)
390     gtk_widget_show (priv->button_back);
391   else
392     gtk_widget_hide (priv->button_back);
393
394   accounts_dialog_protocol_changed_cb (priv->radiobutton_register, dialog);
395   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->radiobutton_reuse),
396       TRUE);
397   gtk_combo_box_set_active (GTK_COMBO_BOX (priv->combobox_protocol), 0);
398   gtk_widget_grab_focus (priv->combobox_protocol);
399 }
400
401 static void
402 accounts_dialog_update_settings (EmpathyAccountsDialog *dialog,
403     EmpathyAccountSettings *settings)
404 {
405   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
406
407   if (priv->settings_ready != NULL)
408     {
409       g_signal_handler_disconnect (priv->settings_ready,
410           priv->settings_ready_id);
411       priv->settings_ready = NULL;
412       priv->settings_ready_id = 0;
413     }
414
415   if (!settings)
416     {
417       GtkTreeView  *view;
418       GtkTreeModel *model;
419
420       view = GTK_TREE_VIEW (priv->treeview);
421       model = gtk_tree_view_get_model (view);
422
423       if (gtk_tree_model_iter_n_children (model, NULL) > 0)
424         {
425           /* We have configured accounts, select the first one */
426           accounts_dialog_model_select_first (dialog);
427           return;
428         }
429       if (empathy_connection_managers_get_cms_num (priv->cms) > 0)
430         {
431           /* We have no account configured but we have some
432            * profiles installed. The user obviously wants to add
433            * an account. Click on the Add button for him. */
434           accounts_dialog_button_add_clicked_cb (priv->button_add,
435               dialog);
436           return;
437         }
438
439       /* No account and no profile, warn the user */
440       gtk_widget_hide (priv->vbox_details);
441       gtk_widget_hide (priv->frame_new_account);
442       gtk_widget_show (priv->frame_no_protocol);
443       gtk_widget_set_sensitive (priv->button_add, FALSE);
444       return;
445     }
446
447   /* We have an account selected, destroy old settings and create a new
448    * one for the account selected */
449   gtk_widget_hide (priv->frame_new_account);
450   gtk_widget_hide (priv->frame_no_protocol);
451   gtk_widget_show (priv->vbox_details);
452   gtk_widget_set_sensitive (priv->button_add, TRUE);
453
454   if (priv->settings_widget)
455     {
456       gtk_widget_destroy (priv->settings_widget);
457       priv->settings_widget = NULL;
458     }
459
460   if (empathy_account_settings_is_ready (settings))
461     {
462       account_dialog_create_settings_widget (dialog, settings);
463     }
464   else
465     {
466       priv->settings_ready = settings;
467       priv->settings_ready_id =
468         g_signal_connect (settings, "notify::ready",
469             G_CALLBACK (account_dialog_settings_ready_cb), dialog);
470     }
471
472 }
473
474 static void
475 accounts_dialog_name_editing_started_cb (GtkCellRenderer *renderer,
476     GtkCellEditable *editable,
477     gchar *path,
478     EmpathyAccountsDialog *dialog)
479 {
480   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
481
482   if (priv->connecting_id)
483     g_source_remove (priv->connecting_id);
484
485   DEBUG ("Editing account name started; stopping flashing");
486 }
487
488 static void
489 accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn *tree_column,
490     GtkCellRenderer *cell,
491     GtkTreeModel *model,
492     GtkTreeIter *iter,
493     EmpathyAccountsDialog *dialog)
494 {
495   EmpathyAccountSettings  *settings;
496   gchar              *icon_name;
497   GdkPixbuf          *pixbuf;
498   TpConnectionStatus  status;
499   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
500
501   gtk_tree_model_get (model, iter,
502       COL_STATUS, &status,
503       COL_ACCOUNT_SETTINGS_POINTER, &settings,
504       -1);
505
506   icon_name = empathy_account_settings_get_icon_name (settings);
507   pixbuf = empathy_pixbuf_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
508
509   if (pixbuf)
510     {
511       if (status == TP_CONNECTION_STATUS_DISCONNECTED ||
512           (status == TP_CONNECTION_STATUS_CONNECTING &&
513               !priv->connecting_show))
514         {
515           GdkPixbuf *modded_pixbuf;
516
517           modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
518               TRUE,
519               8,
520               gdk_pixbuf_get_width (pixbuf),
521               gdk_pixbuf_get_height (pixbuf));
522
523           gdk_pixbuf_saturate_and_pixelate (pixbuf,
524               modded_pixbuf,
525               1.0,
526               TRUE);
527           g_object_unref (pixbuf);
528           pixbuf = modded_pixbuf;
529         }
530     }
531
532   g_object_set (cell,
533       "visible", TRUE,
534       "pixbuf", pixbuf,
535       NULL);
536
537   g_object_unref (settings);
538
539   if (pixbuf)
540     g_object_unref (pixbuf);
541 }
542
543 static gboolean
544 accounts_dialog_row_changed_foreach (GtkTreeModel *model,
545     GtkTreePath *path,
546     GtkTreeIter *iter,
547     gpointer user_data)
548 {
549   gtk_tree_model_row_changed (model, path, iter);
550
551   return FALSE;
552 }
553
554 static gboolean
555 accounts_dialog_flash_connecting_cb (EmpathyAccountsDialog *dialog)
556 {
557   GtkTreeView  *view;
558   GtkTreeModel *model;
559   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
560
561   priv->connecting_show = !priv->connecting_show;
562
563   view = GTK_TREE_VIEW (priv->treeview);
564   model = gtk_tree_view_get_model (view);
565
566   gtk_tree_model_foreach (model, accounts_dialog_row_changed_foreach, NULL);
567
568   return TRUE;
569 }
570
571 static void
572 accounts_dialog_name_edited_cb (GtkCellRendererText *renderer,
573     gchar *path,
574     gchar *new_text,
575     EmpathyAccountsDialog *dialog)
576 {
577   EmpathyAccountSettings    *settings;
578   GtkTreeModel *model;
579   GtkTreePath  *treepath;
580   GtkTreeIter   iter;
581   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
582
583   if (empathy_account_manager_get_connecting_accounts
584       (priv->account_manager) > 0)
585     {
586       priv->connecting_id = g_timeout_add (FLASH_TIMEOUT,
587           (GSourceFunc) accounts_dialog_flash_connecting_cb,
588           dialog);
589     }
590
591   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
592   treepath = gtk_tree_path_new_from_string (path);
593   gtk_tree_model_get_iter (model, &iter, treepath);
594   gtk_tree_model_get (model, &iter,
595       COL_ACCOUNT_SETTINGS_POINTER, &settings,
596       -1);
597   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
598       COL_NAME, new_text,
599       -1);
600   gtk_tree_path_free (treepath);
601
602   empathy_account_settings_set_display_name_async (settings, new_text,
603       NULL, NULL);
604   g_object_set (settings, "display-name-overridden", TRUE, NULL);
605   g_object_unref (settings);
606 }
607
608 static void
609 accounts_dialog_delete_account_response_cb (GtkDialog *message_dialog,
610   gint response_id,
611   gpointer user_data)
612 {
613   EmpathyAccount *account;
614   GtkTreeModel *model;
615   GtkTreeIter iter;
616   GtkTreeSelection *selection;
617   EmpathyAccountsDialog *account_dialog = EMPATHY_ACCOUNTS_DIALOG (user_data);
618   EmpathyAccountsDialogPriv *priv = GET_PRIV (account_dialog);
619
620   if (response_id == GTK_RESPONSE_YES)
621     {
622       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
623
624       if (!gtk_tree_selection_get_selected (selection, &model, &iter))
625         return;
626
627       gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
628
629       if (account != NULL)
630         {
631           g_signal_handlers_disconnect_by_func (account,
632               accounts_dialog_account_display_name_changed_cb, account_dialog);
633           empathy_account_remove_async (account, NULL, NULL);
634           g_object_unref (account);
635         }
636
637       gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
638       accounts_dialog_model_select_first (account_dialog);
639     }
640
641   gtk_widget_destroy (GTK_WIDGET (message_dialog));
642 }
643
644 static void
645 accounts_dialog_view_delete_activated_cb (EmpathyCellRendererActivatable *cell,
646     const gchar *path_string,
647     EmpathyAccountsDialog *dialog)
648 {
649   EmpathyAccount *account;
650   GtkTreeModel *model;
651   GtkTreeIter iter;
652   GtkWidget *message_dialog;
653   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
654
655   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
656
657   if (!gtk_tree_model_get_iter_from_string (model, &iter, path_string))
658     return;
659
660   gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
661
662   if (account == NULL || !empathy_account_is_valid (account))
663     {
664       gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
665       accounts_dialog_model_select_first (dialog);
666       return;
667     }
668
669   message_dialog = gtk_message_dialog_new
670       (GTK_WINDOW (priv->window),
671           GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
672           GTK_MESSAGE_QUESTION,
673           GTK_BUTTONS_NONE,
674           _("You are about to remove your %s account!\n"
675               "Are you sure you want to proceed?"),
676               empathy_account_get_display_name (account));
677
678   gtk_message_dialog_format_secondary_text
679   (GTK_MESSAGE_DIALOG (message_dialog),
680       _("Any associated conversations and chat rooms will NOT be "
681           "removed if you decide to proceed.\n"
682           "\n"
683           "Should you decide to add the account back at a later time, "
684           "they will still be available."));
685
686   gtk_dialog_add_button (GTK_DIALOG (message_dialog),
687       GTK_STOCK_CANCEL,
688       GTK_RESPONSE_NO);
689   gtk_dialog_add_button (GTK_DIALOG (message_dialog),
690       GTK_STOCK_REMOVE,
691       GTK_RESPONSE_YES);
692
693   g_signal_connect (message_dialog, "response",
694       G_CALLBACK (accounts_dialog_delete_account_response_cb), dialog);
695
696   gtk_widget_show (message_dialog);
697
698   if (account != NULL)
699     g_object_unref (account);
700 }
701
702 static void
703 accounts_dialog_model_add_columns (EmpathyAccountsDialog *dialog)
704 {
705   GtkTreeView       *view;
706   GtkTreeViewColumn *column;
707   GtkCellRenderer   *cell;
708   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
709
710   view = GTK_TREE_VIEW (priv->treeview);
711   gtk_tree_view_set_headers_visible (view, FALSE);
712
713   /* Account column */
714   column = gtk_tree_view_column_new ();
715   gtk_tree_view_column_set_expand (column, TRUE);
716   gtk_tree_view_append_column (view, column);
717
718   /* Icon renderer */
719   cell = gtk_cell_renderer_pixbuf_new ();
720   gtk_tree_view_column_pack_start (column, cell, FALSE);
721   gtk_tree_view_column_set_cell_data_func (column, cell,
722       (GtkTreeCellDataFunc)
723       accounts_dialog_model_pixbuf_data_func,
724       dialog,
725       NULL);
726
727   /* Name renderer */
728   cell = gtk_cell_renderer_text_new ();
729   g_object_set (cell,
730       "ellipsize", PANGO_ELLIPSIZE_END,
731       "width-chars", 25,
732       "editable", TRUE,
733       NULL);
734   gtk_tree_view_column_pack_start (column, cell, TRUE);
735   gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME);
736   g_signal_connect (cell, "edited",
737       G_CALLBACK (accounts_dialog_name_edited_cb),
738       dialog);
739   g_signal_connect (cell, "editing-started",
740       G_CALLBACK (accounts_dialog_name_editing_started_cb),
741       dialog);
742
743   /* Delete column */
744   cell = empathy_cell_renderer_activatable_new ();
745   gtk_tree_view_column_pack_start (column, cell, FALSE);
746   g_object_set (cell,
747         "icon-name", GTK_STOCK_DELETE,
748         NULL);
749
750   g_signal_connect (cell, "path-activated",
751       G_CALLBACK (accounts_dialog_view_delete_activated_cb),
752       dialog);
753 }
754
755 static EmpathyAccountSettings *
756 accounts_dialog_model_get_selected_settings (EmpathyAccountsDialog *dialog)
757 {
758   GtkTreeView      *view;
759   GtkTreeModel     *model;
760   GtkTreeSelection *selection;
761   GtkTreeIter       iter;
762   EmpathyAccountSettings   *settings;
763   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
764
765   view = GTK_TREE_VIEW (priv->treeview);
766   selection = gtk_tree_view_get_selection (view);
767
768   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
769     return NULL;
770
771   gtk_tree_model_get (model, &iter,
772       COL_ACCOUNT_SETTINGS_POINTER, &settings, -1);
773
774   return settings;
775 }
776
777 static void
778 accounts_dialog_model_selection_changed (GtkTreeSelection *selection,
779     EmpathyAccountsDialog *dialog)
780 {
781   EmpathyAccountSettings *settings;
782   GtkTreeModel *model;
783   GtkTreeIter   iter;
784   gboolean      is_selection;
785
786   is_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
787
788   settings = accounts_dialog_model_get_selected_settings (dialog);
789
790   if (settings != NULL)
791     empathy_account_settings_discard_changes (settings);
792
793   accounts_dialog_update_settings (dialog, settings);
794
795   if (settings != NULL)
796     g_object_unref (settings);
797 }
798
799 static void
800 accounts_dialog_model_setup (EmpathyAccountsDialog *dialog)
801 {
802   GtkListStore     *store;
803   GtkTreeSelection *selection;
804   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
805
806   store = gtk_list_store_new (COL_COUNT,
807       G_TYPE_STRING,         /* name */
808       G_TYPE_UINT,           /* status */
809       EMPATHY_TYPE_ACCOUNT,   /* account */
810       EMPATHY_TYPE_ACCOUNT_SETTINGS); /* settings */
811
812   gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeview),
813       GTK_TREE_MODEL (store));
814
815   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
816   gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
817
818   g_signal_connect (selection, "changed",
819       G_CALLBACK (accounts_dialog_model_selection_changed),
820       dialog);
821
822   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
823       COL_NAME, GTK_SORT_ASCENDING);
824
825   accounts_dialog_model_add_columns (dialog);
826
827   g_object_unref (store);
828 }
829
830 static gboolean
831 accounts_dialog_get_settings_iter (EmpathyAccountsDialog *dialog,
832     EmpathyAccountSettings *settings,
833     GtkTreeIter *iter)
834 {
835   GtkTreeView      *view;
836   GtkTreeSelection *selection;
837   GtkTreeModel     *model;
838   gboolean          ok;
839   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
840
841   /* Update the status in the model */
842   view = GTK_TREE_VIEW (priv->treeview);
843   selection = gtk_tree_view_get_selection (view);
844   model = gtk_tree_view_get_model (view);
845
846   for (ok = gtk_tree_model_get_iter_first (model, iter);
847        ok;
848        ok = gtk_tree_model_iter_next (model, iter))
849     {
850       EmpathyAccountSettings *this_settings;
851       gboolean   equal;
852
853       gtk_tree_model_get (model, iter,
854           COL_ACCOUNT_SETTINGS_POINTER, &this_settings,
855           -1);
856
857       equal = (this_settings == settings);
858       g_object_unref (this_settings);
859
860       if (equal)
861         return TRUE;
862     }
863
864   return FALSE;
865 }
866
867 static gboolean
868 accounts_dialog_get_account_iter (EmpathyAccountsDialog *dialog,
869     EmpathyAccount *account,
870     GtkTreeIter *iter)
871 {
872   GtkTreeView      *view;
873   GtkTreeSelection *selection;
874   GtkTreeModel     *model;
875   gboolean          ok;
876   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
877
878   /* Update the status in the model */
879   view = GTK_TREE_VIEW (priv->treeview);
880   selection = gtk_tree_view_get_selection (view);
881   model = gtk_tree_view_get_model (view);
882
883   for (ok = gtk_tree_model_get_iter_first (model, iter);
884        ok;
885        ok = gtk_tree_model_iter_next (model, iter))
886     {
887       EmpathyAccountSettings *settings;
888       gboolean   equal;
889
890       gtk_tree_model_get (model, iter,
891           COL_ACCOUNT_SETTINGS_POINTER, &settings,
892           -1);
893
894       equal = empathy_account_settings_has_account (settings, account);
895       g_object_unref (settings);
896
897       if (equal)
898         return TRUE;
899     }
900
901   return FALSE;
902 }
903
904 static void
905 accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog,
906     EmpathyAccountSettings *settings)
907 {
908   GtkTreeSelection *selection;
909   GtkTreeIter       iter;
910   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
911
912   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
913   if (accounts_dialog_get_settings_iter (dialog, settings, &iter))
914     gtk_tree_selection_select_iter (selection, &iter);
915 }
916 static void
917 accounts_dialog_add (EmpathyAccountsDialog *dialog,
918     EmpathyAccountSettings *settings)
919 {
920   GtkTreeModel       *model;
921   GtkTreeIter         iter;
922   const gchar        *name;
923   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
924
925   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
926   name = empathy_account_settings_get_display_name (settings);
927
928   gtk_list_store_append (GTK_LIST_STORE (model), &iter);
929
930   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
931       COL_NAME, name,
932       COL_STATUS, TP_CONNECTION_STATUS_DISCONNECTED,
933       COL_ACCOUNT_SETTINGS_POINTER, settings,
934       -1);
935 }
936
937 static void
938 accounts_dialog_connection_changed_cb     (EmpathyAccountManager *manager,
939     EmpathyAccount *account,
940     TpConnectionStatusReason reason,
941     TpConnectionStatus current,
942     TpConnectionStatus previous,
943     EmpathyAccountsDialog *dialog)
944 {
945   GtkTreeModel *model;
946   GtkTreeIter   iter;
947   gboolean      found;
948   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
949
950   /* Update the status in the model */
951   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
952
953   if (accounts_dialog_get_account_iter (dialog, account, &iter))
954     {
955       GtkTreePath *path;
956
957       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
958           COL_STATUS, current,
959           -1);
960
961       path = gtk_tree_model_get_path (model, &iter);
962       gtk_tree_model_row_changed (model, path, &iter);
963       gtk_tree_path_free (path);
964     }
965
966   found = (empathy_account_manager_get_connecting_accounts (manager) > 0);
967
968   if (!found && priv->connecting_id)
969     {
970       g_source_remove (priv->connecting_id);
971       priv->connecting_id = 0;
972     }
973
974   if (found && !priv->connecting_id)
975     priv->connecting_id = g_timeout_add (FLASH_TIMEOUT,
976         (GSourceFunc) accounts_dialog_flash_connecting_cb,
977         dialog);
978 }
979
980 static void
981 accounts_dialog_account_display_name_changed_cb (EmpathyAccount *account,
982   GParamSpec *pspec,
983   gpointer user_data)
984 {
985   const gchar *display_name;
986   GtkTreeIter iter;
987   GtkTreeModel *model;
988   EmpathyAccountSettings *settings;
989   EmpathyAccount *selected_account;
990   EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (user_data);
991   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
992
993   display_name = empathy_account_get_display_name (account);
994   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
995   settings = accounts_dialog_model_get_selected_settings (dialog);
996   selected_account = empathy_account_settings_get_account (settings);
997
998   if (accounts_dialog_get_account_iter (dialog, account, &iter))
999     {
1000       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1001           COL_NAME, display_name,
1002           -1);
1003     }
1004
1005   if (selected_account == account)
1006     accounts_dialog_update_name_label (dialog, display_name);
1007
1008   g_object_unref (settings);
1009 }
1010
1011 static void
1012 accounts_dialog_add_account (EmpathyAccountsDialog *dialog,
1013     EmpathyAccount *account)
1014 {
1015   EmpathyAccountSettings *settings;
1016   GtkTreeModel       *model;
1017   GtkTreeIter         iter;
1018   TpConnectionStatus  status;
1019   const gchar        *name;
1020   gboolean            enabled;
1021   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1022
1023   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
1024   g_object_get (account, "connection-status", &status, NULL);
1025   name = empathy_account_get_display_name (account);
1026   enabled = empathy_account_is_enabled (account);
1027
1028   if (!accounts_dialog_get_account_iter (dialog, account, &iter))
1029     gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1030
1031   settings = empathy_account_settings_new_for_account (account);
1032
1033   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1034       COL_NAME, name,
1035       COL_STATUS, status,
1036       COL_ACCOUNT_POINTER, account,
1037       COL_ACCOUNT_SETTINGS_POINTER, settings,
1038       -1);
1039
1040   accounts_dialog_connection_changed_cb (priv->account_manager,
1041       account,
1042       TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
1043       status,
1044       TP_CONNECTION_STATUS_DISCONNECTED,
1045       dialog);
1046
1047   g_signal_connect (account, "notify::display-name",
1048       G_CALLBACK (accounts_dialog_account_display_name_changed_cb), dialog);
1049
1050   g_object_unref (settings);
1051 }
1052
1053 static void
1054 accounts_dialog_update (EmpathyAccountsDialog *dialog,
1055     EmpathyAccountSettings *settings)
1056 {
1057   GtkTreeModel       *model;
1058   GtkTreeIter         iter;
1059   TpConnectionStatus  status = TP_CONNECTION_STATUS_DISCONNECTED;
1060   const gchar        *name;
1061   gboolean            enabled = FALSE;
1062   EmpathyAccount     *account;
1063   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1064
1065   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
1066   name = empathy_account_settings_get_display_name (settings);
1067
1068   account = empathy_account_settings_get_account (settings);
1069   if (account != NULL)
1070     {
1071       enabled = empathy_account_is_enabled (account);
1072       g_object_get (account, "connection-status", &status, NULL);
1073     }
1074
1075   accounts_dialog_get_settings_iter (dialog, settings, &iter);
1076   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1077       COL_NAME, name,
1078       COL_STATUS, status,
1079       COL_ACCOUNT_POINTER, account,
1080       COL_ACCOUNT_SETTINGS_POINTER, settings,
1081       -1);
1082 }
1083
1084 static void
1085 accounts_dialog_account_added_cb (EmpathyAccountManager *manager,
1086     EmpathyAccount *account,
1087     EmpathyAccountsDialog *dialog)
1088 {
1089   accounts_dialog_add_account (dialog, account);
1090 }
1091
1092
1093 static void
1094 accounts_dialog_account_removed_cb (EmpathyAccountManager *manager,
1095     EmpathyAccount *account,
1096     EmpathyAccountsDialog *dialog)
1097 {
1098   GtkTreeIter iter;
1099   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1100
1101   if (accounts_dialog_get_account_iter (dialog, account, &iter))
1102     {
1103       g_signal_handlers_disconnect_by_func (account,
1104           accounts_dialog_account_display_name_changed_cb, dialog);
1105       gtk_list_store_remove (GTK_LIST_STORE (
1106             gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview))), &iter);
1107     }
1108 }
1109
1110 static void
1111 enable_or_disable_account (EmpathyAccountsDialog *dialog,
1112     EmpathyAccount *account,
1113     gboolean enabled)
1114 {
1115   GtkTreeModel *model;
1116   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1117
1118   /* Update the status in the model */
1119   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
1120
1121   DEBUG ("Account %s is now %s",
1122       empathy_account_get_display_name (account),
1123       enabled ? "enabled" : "disabled");
1124 }
1125
1126 static void
1127 accounts_dialog_account_disabled_cb (EmpathyAccountManager *manager,
1128     EmpathyAccount *account,
1129     EmpathyAccountsDialog *dialog)
1130 {
1131   enable_or_disable_account (dialog, account, FALSE);
1132 }
1133
1134 static void
1135 accounts_dialog_account_enabled_cb (EmpathyAccountManager *manager,
1136     EmpathyAccount *account,
1137     EmpathyAccountsDialog *dialog)
1138 {
1139   enable_or_disable_account (dialog, account, TRUE);
1140 }
1141
1142 static void
1143 accounts_dialog_account_changed_cb (EmpathyAccountManager *manager,
1144     EmpathyAccount *account,
1145     EmpathyAccountsDialog  *dialog)
1146 {
1147   EmpathyAccountSettings *settings, *selected_settings;
1148   GtkTreeModel *model;
1149   GtkTreeIter iter;
1150   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1151
1152   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
1153
1154   if (!accounts_dialog_get_account_iter (dialog, account, &iter))
1155     return;
1156
1157   gtk_tree_model_get (model, &iter,
1158       COL_ACCOUNT_SETTINGS_POINTER, &settings,
1159       -1);
1160
1161   accounts_dialog_update (dialog, settings);
1162   selected_settings = accounts_dialog_model_get_selected_settings (dialog);
1163
1164   if (settings == selected_settings)
1165     accounts_dialog_update_name_label (dialog,
1166         empathy_account_settings_get_display_name (settings));
1167
1168   if (settings)
1169     g_object_unref (settings);
1170
1171   if (selected_settings)
1172     g_object_unref (selected_settings);
1173 }
1174
1175 static void
1176 accounts_dialog_button_create_clicked_cb (GtkWidget *button,
1177     EmpathyAccountsDialog *dialog)
1178 {
1179   EmpathyAccountSettings *settings;
1180   gchar *str;
1181   const gchar *display_name;
1182   TpConnectionManager *cm;
1183   TpConnectionManagerProtocol *proto;
1184   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1185
1186   cm = empathy_protocol_chooser_dup_selected (
1187       EMPATHY_PROTOCOL_CHOOSER (priv->combobox_protocol), &proto);
1188   display_name = empathy_protocol_name_to_display_name (proto->name);
1189
1190   if (display_name == NULL)
1191     display_name = proto->name;
1192
1193   /* Create account */
1194   /* To translator: %s is the name of the protocol, such as "Google Talk" or
1195    * "Yahoo!"
1196    */
1197   str = g_strdup_printf (_("New %s account"), display_name);
1198   settings = empathy_account_settings_new (cm->name, proto->name, str);
1199
1200   g_free (str);
1201
1202   if (tp_connection_manager_protocol_can_register (proto))
1203     {
1204       gboolean active;
1205
1206       active = gtk_toggle_button_get_active
1207           (GTK_TOGGLE_BUTTON (priv->radiobutton_register));
1208       if (active)
1209         empathy_account_settings_set_boolean (settings, "register", TRUE);
1210     }
1211
1212   accounts_dialog_add (dialog, settings);
1213   accounts_dialog_model_set_selected (dialog, settings);
1214
1215   g_object_unref (settings);
1216   g_object_unref (cm);
1217 }
1218
1219 static void
1220 accounts_dialog_button_back_clicked_cb (GtkWidget *button,
1221     EmpathyAccountsDialog *dialog)
1222 {
1223   EmpathyAccountSettings *settings;
1224
1225   settings = accounts_dialog_model_get_selected_settings (dialog);
1226   accounts_dialog_update_settings (dialog, settings);
1227
1228   if (settings)
1229     g_object_unref (settings);
1230 }
1231
1232 static void
1233 accounts_dialog_button_help_clicked_cb (GtkWidget *button,
1234     EmpathyAccountsDialog *dialog)
1235 {
1236   empathy_url_show (button, "ghelp:empathy?empathy-create-account");
1237 }
1238
1239 static void
1240 accounts_dialog_response_cb (GtkWidget *widget,
1241     gint response,
1242     EmpathyAccountsDialog *dialog)
1243 {
1244   if (response == GTK_RESPONSE_CLOSE)
1245     gtk_widget_destroy (widget);
1246 }
1247
1248 static void
1249 accounts_dialog_destroy_cb (GtkObject *obj,
1250     EmpathyAccountsDialog *dialog)
1251 {
1252   DEBUG ("%p", obj);
1253
1254   g_object_unref (dialog);
1255 }
1256
1257 static void
1258 accounts_dialog_set_selected_account (EmpathyAccountsDialog *dialog,
1259     EmpathyAccount *account)
1260 {
1261   GtkTreeSelection *selection;
1262   GtkTreeIter       iter;
1263   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1264
1265   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
1266   if (accounts_dialog_get_account_iter (dialog, account, &iter))
1267     gtk_tree_selection_select_iter (selection, &iter);
1268 }
1269
1270 static void
1271 accounts_dialog_cms_ready_cb (EmpathyConnectionManagers *cms,
1272     GParamSpec *pspec,
1273     EmpathyAccountsDialog *dialog)
1274 {
1275   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1276
1277   if (empathy_connection_managers_is_ready (cms))
1278     {
1279       accounts_dialog_update_settings (dialog, NULL);
1280
1281       if (priv->initial_selection != NULL)
1282         {
1283           accounts_dialog_set_selected_account
1284               (dialog, priv->initial_selection);
1285           g_object_unref (priv->initial_selection);
1286           priv->initial_selection = NULL;
1287         }
1288     }
1289 }
1290
1291 static void
1292 accounts_dialog_build_ui (EmpathyAccountsDialog *dialog)
1293 {
1294   GtkBuilder                   *gui;
1295   gchar                        *filename;
1296   EmpathyAccountsDialogPriv    *priv = GET_PRIV (dialog);
1297
1298   filename = empathy_file_lookup ("empathy-accounts-dialog.ui", "src");
1299
1300   gui = empathy_builder_get_file (filename,
1301       "accounts_dialog", &priv->window,
1302       "vbox_details", &priv->vbox_details,
1303       "frame_no_protocol", &priv->frame_no_protocol,
1304       "alignment_settings", &priv->alignment_settings,
1305       "treeview", &priv->treeview,
1306       "frame_new_account", &priv->frame_new_account,
1307       "hbox_type", &priv->hbox_type,
1308       "button_create", &priv->button_create,
1309       "button_back", &priv->button_back,
1310       "radiobutton_reuse", &priv->radiobutton_reuse,
1311       "radiobutton_register", &priv->radiobutton_register,
1312       "image_type", &priv->image_type,
1313       "label_name", &priv->label_name,
1314       "button_add", &priv->button_add,
1315       NULL);
1316   g_free (filename);
1317
1318   empathy_builder_connect (gui, dialog,
1319       "accounts_dialog", "response", accounts_dialog_response_cb,
1320       "accounts_dialog", "destroy", accounts_dialog_destroy_cb,
1321       "button_create", "clicked", accounts_dialog_button_create_clicked_cb,
1322       "button_back", "clicked", accounts_dialog_button_back_clicked_cb,
1323       "button_add", "clicked", accounts_dialog_button_add_clicked_cb,
1324       "button_help", "clicked", accounts_dialog_button_help_clicked_cb,
1325       NULL);
1326
1327   g_object_unref (gui);
1328
1329   priv->combobox_protocol = empathy_protocol_chooser_new ();
1330   gtk_box_pack_start (GTK_BOX (priv->hbox_type),
1331       priv->combobox_protocol,
1332       TRUE, TRUE, 0);
1333   gtk_widget_show (priv->combobox_protocol);
1334   g_signal_connect (priv->combobox_protocol, "changed",
1335       G_CALLBACK (accounts_dialog_protocol_changed_cb),
1336       dialog);
1337
1338   if (priv->parent_window)
1339     gtk_window_set_transient_for (GTK_WINDOW (priv->window),
1340         priv->parent_window);
1341 }
1342
1343 static void
1344 do_dispose (GObject *obj)
1345 {
1346   EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (obj);
1347   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1348
1349   /* Disconnect signals */
1350   g_signal_handlers_disconnect_by_func (priv->account_manager,
1351       accounts_dialog_account_added_cb,
1352       dialog);
1353   g_signal_handlers_disconnect_by_func (priv->account_manager,
1354       accounts_dialog_account_removed_cb,
1355       dialog);
1356   g_signal_handlers_disconnect_by_func (priv->account_manager,
1357       accounts_dialog_account_enabled_cb,
1358       dialog);
1359   g_signal_handlers_disconnect_by_func (priv->account_manager,
1360       accounts_dialog_account_disabled_cb,
1361       dialog);
1362   g_signal_handlers_disconnect_by_func (priv->account_manager,
1363       accounts_dialog_account_changed_cb,
1364       dialog);
1365   g_signal_handlers_disconnect_by_func (priv->account_manager,
1366       accounts_dialog_connection_changed_cb,
1367       dialog);
1368
1369   if (priv->connecting_id)
1370     g_source_remove (priv->connecting_id);
1371
1372   if (priv->account_manager != NULL)
1373     {
1374       g_object_unref (priv->account_manager);
1375       priv->account_manager = NULL;
1376     }
1377
1378   if (priv->cms != NULL)
1379     {
1380       g_object_unref (priv->cms);
1381       priv->cms = NULL;
1382     }
1383
1384   if (priv->initial_selection != NULL)
1385     g_object_unref (priv->initial_selection);
1386   priv->initial_selection = NULL;
1387
1388   G_OBJECT_CLASS (empathy_accounts_dialog_parent_class)->dispose (obj);
1389 }
1390
1391 static GObject *
1392 do_constructor (GType type,
1393     guint n_props,
1394     GObjectConstructParam *props)
1395 {
1396   GObject *retval;
1397
1398   if (dialog_singleton)
1399     {
1400       retval = G_OBJECT (dialog_singleton);
1401       g_object_ref (retval);
1402     }
1403   else
1404     {
1405       retval =
1406         G_OBJECT_CLASS (empathy_accounts_dialog_parent_class)->constructor
1407             (type, n_props, props);
1408
1409       dialog_singleton = EMPATHY_ACCOUNTS_DIALOG (retval);
1410       g_object_add_weak_pointer (retval, (gpointer) &dialog_singleton);
1411     }
1412
1413   return retval;
1414 }
1415
1416 static void
1417 do_get_property (GObject *object,
1418     guint property_id,
1419     GValue *value,
1420     GParamSpec *pspec)
1421 {
1422   EmpathyAccountsDialogPriv *priv = GET_PRIV (object);
1423
1424   switch (property_id)
1425     {
1426     case PROP_PARENT:
1427       g_value_set_object (value, priv->parent_window);
1428       break;
1429     default:
1430       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1431     }
1432 }
1433
1434 static void
1435 do_set_property (GObject *object,
1436     guint property_id,
1437     const GValue *value,
1438     GParamSpec *pspec)
1439 {
1440   EmpathyAccountsDialogPriv *priv = GET_PRIV (object);
1441
1442   switch (property_id)
1443     {
1444     case PROP_PARENT:
1445       priv->parent_window = g_value_get_object (value);
1446       break;
1447     default:
1448       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1449     }
1450 }
1451
1452 static void
1453 do_constructed (GObject *object)
1454 {
1455   EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (object);
1456   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
1457   GList *accounts, *l;
1458   gboolean import_asked;
1459
1460   accounts_dialog_build_ui (dialog);
1461
1462   /* Set up signalling */
1463   priv->account_manager = empathy_account_manager_dup_singleton ();
1464
1465   g_signal_connect (priv->account_manager, "account-created",
1466       G_CALLBACK (accounts_dialog_account_added_cb),
1467       dialog);
1468   g_signal_connect (priv->account_manager, "account-deleted",
1469       G_CALLBACK (accounts_dialog_account_removed_cb),
1470       dialog);
1471   g_signal_connect (priv->account_manager, "account-enabled",
1472       G_CALLBACK (accounts_dialog_account_enabled_cb),
1473       dialog);
1474   g_signal_connect (priv->account_manager, "account-disabled",
1475       G_CALLBACK (accounts_dialog_account_disabled_cb),
1476       dialog);
1477   g_signal_connect (priv->account_manager, "account-changed",
1478       G_CALLBACK (accounts_dialog_account_changed_cb),
1479       dialog);
1480   g_signal_connect (priv->account_manager, "account-connection-changed",
1481       G_CALLBACK (accounts_dialog_connection_changed_cb),
1482       dialog);
1483
1484   accounts_dialog_model_setup (dialog);
1485
1486   /* Add existing accounts */
1487   accounts = empathy_account_manager_dup_accounts (priv->account_manager);
1488   for (l = accounts; l; l = l->next)
1489     {
1490       accounts_dialog_add_account (dialog, l->data);
1491       g_object_unref (l->data);
1492     }
1493   g_list_free (accounts);
1494
1495   priv->cms = empathy_connection_managers_dup_singleton ();
1496   if (!empathy_connection_managers_is_ready (priv->cms))
1497     g_signal_connect (priv->cms, "notify::ready",
1498         G_CALLBACK (accounts_dialog_cms_ready_cb), dialog);
1499
1500   accounts_dialog_model_select_first (dialog);
1501
1502   empathy_conf_get_bool (empathy_conf_get (),
1503       EMPATHY_PREFS_IMPORT_ASKED, &import_asked);
1504
1505
1506   if (empathy_import_accounts_to_import ())
1507     {
1508
1509       if (!import_asked)
1510         {
1511           GtkWidget *import_dialog;
1512
1513           empathy_conf_set_bool (empathy_conf_get (),
1514               EMPATHY_PREFS_IMPORT_ASKED, TRUE);
1515           import_dialog = empathy_import_dialog_new (GTK_WINDOW (priv->window),
1516               FALSE);
1517           gtk_widget_show (import_dialog);
1518         }
1519     }
1520 }
1521
1522 static void
1523 empathy_accounts_dialog_class_init (EmpathyAccountsDialogClass *klass)
1524 {
1525   GObjectClass *oclass = G_OBJECT_CLASS (klass);
1526   GParamSpec *param_spec;
1527
1528   oclass->constructor = do_constructor;
1529   oclass->dispose = do_dispose;
1530   oclass->constructed = do_constructed;
1531   oclass->set_property = do_set_property;
1532   oclass->get_property = do_get_property;
1533
1534   param_spec = g_param_spec_object ("parent",
1535       "parent", "The parent window",
1536       GTK_TYPE_WINDOW,
1537       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1538   g_object_class_install_property (oclass, PROP_PARENT, param_spec);
1539
1540   g_type_class_add_private (klass, sizeof (EmpathyAccountsDialogPriv));
1541 }
1542
1543 static void
1544 empathy_accounts_dialog_init (EmpathyAccountsDialog *dialog)
1545 {
1546   EmpathyAccountsDialogPriv *priv;
1547
1548   priv = G_TYPE_INSTANCE_GET_PRIVATE ((dialog),
1549       EMPATHY_TYPE_ACCOUNTS_DIALOG,
1550       EmpathyAccountsDialogPriv);
1551   dialog->priv = priv;
1552 }
1553
1554 /* public methods */
1555
1556 GtkWidget *
1557 empathy_accounts_dialog_show (GtkWindow *parent,
1558     EmpathyAccount *selected_account)
1559 {
1560   EmpathyAccountsDialog *dialog;
1561   EmpathyAccountsDialogPriv *priv;
1562
1563   dialog = g_object_new (EMPATHY_TYPE_ACCOUNTS_DIALOG,
1564       "parent", parent, NULL);
1565
1566   priv = GET_PRIV (dialog);
1567
1568   if (selected_account)
1569     {
1570       if (empathy_connection_managers_is_ready (priv->cms))
1571         accounts_dialog_set_selected_account (dialog, selected_account);
1572       else
1573         /* save the selection to set it later when the cms
1574          * becomes ready.
1575          */
1576         priv->initial_selection = g_object_ref (selected_account);
1577     }
1578
1579   gtk_window_present (GTK_WINDOW (priv->window));
1580
1581   return priv->window;
1582 }