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