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