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