]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-accounts-dialog.c
1be402a245cb7e2b6007c703ddab2f6297646b82
[empathy.git] / libempathy-gtk / empathy-accounts-dialog.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2005-2007 Imendio AB
4  * Copyright (C) 2007 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  * 
21  * Authors: Martyn Russell <martyn@imendio.com>
22  *          Xavier Claessens <xclaesse@gmail.com>
23  */
24
25 #include <config.h>
26
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include <gtk/gtk.h>
31 #include <glade/glade.h>
32 #include <glib/gi18n.h>
33 #include <dbus/dbus-glib.h>
34
35 #include <libmissioncontrol/mc-account.h>
36 #include <libmissioncontrol/mc-profile.h>
37 #include <libmissioncontrol/mission-control.h>
38 #include <libmissioncontrol/mc-account-monitor.h>
39 #include <telepathy-glib/util.h>
40 #include <libtelepathy/tp-constants.h>
41
42 #include <libempathy/empathy-debug.h>
43 #include <libempathy/empathy-utils.h>
44 #include <libempathy-gtk/empathy-ui-utils.h>
45
46 #include "empathy-accounts-dialog.h"
47 #include "empathy-profile-chooser.h"
48 #include "empathy-account-widget-generic.h"
49 #include "empathy-account-widget-jabber.h"
50 #include "empathy-account-widget-msn.h"
51 #include "empathy-account-widget-salut.h"
52
53 #define DEBUG_DOMAIN "AccountDialog"
54
55 /* Flashing delay for icons (milliseconds). */
56 #define FLASH_TIMEOUT 500
57
58 typedef struct {
59         GtkWidget        *window;
60
61         GtkWidget        *alignment_settings;
62
63         GtkWidget        *vbox_details;
64         GtkWidget        *frame_no_account;
65         GtkWidget        *label_no_account;
66         GtkWidget        *label_no_account_blurb;
67
68         GtkWidget        *treeview;
69
70         GtkWidget        *button_add;
71         GtkWidget        *button_remove;
72
73         GtkWidget        *frame_new_account;
74         GtkWidget        *combobox_profile;
75         GtkWidget        *hbox_type;
76         GtkWidget        *button_create;
77         GtkWidget        *button_back;
78
79         GtkWidget        *image_type;
80         GtkWidget        *label_name;
81         GtkWidget        *label_type;
82         GtkWidget        *settings_widget;
83
84         gboolean          connecting_show;
85         guint             connecting_id;
86         gboolean          account_changed;
87
88         MissionControl   *mc;
89         McAccountMonitor *monitor;
90 } EmpathyAccountsDialog;
91
92 enum {
93         COL_ENABLED,
94         COL_NAME,
95         COL_STATUS,
96         COL_ACCOUNT_POINTER,
97         COL_COUNT
98 };
99
100 static void       accounts_dialog_setup                     (EmpathyAccountsDialog    *dialog);
101 static void       accounts_dialog_update_account            (EmpathyAccountsDialog    *dialog,
102                                                              McAccount                *account);
103 static void       accounts_dialog_model_setup               (EmpathyAccountsDialog    *dialog);
104 static void       accounts_dialog_model_add_columns         (EmpathyAccountsDialog    *dialog);
105 static void       accounts_dialog_model_select_first        (EmpathyAccountsDialog    *dialog);
106 static void       accounts_dialog_model_pixbuf_data_func    (GtkTreeViewColumn        *tree_column,
107                                                              GtkCellRenderer          *cell,
108                                                              GtkTreeModel             *model,
109                                                              GtkTreeIter              *iter,
110                                                              EmpathyAccountsDialog    *dialog);
111 static McAccount *accounts_dialog_model_get_selected        (EmpathyAccountsDialog    *dialog);
112 static void       accounts_dialog_model_set_selected        (EmpathyAccountsDialog    *dialog,
113                                                              McAccount                *account);
114 static gboolean   accounts_dialog_model_remove_selected     (EmpathyAccountsDialog    *dialog);
115 static void       accounts_dialog_model_selection_changed   (GtkTreeSelection         *selection,
116                                                              EmpathyAccountsDialog    *dialog);
117 static void       accounts_dialog_add_account               (EmpathyAccountsDialog    *dialog,
118                                                              McAccount                *account);
119 static void       accounts_dialog_account_added_cb          (McAccountMonitor         *monitor,
120                                                              gchar                    *unique_name,
121                                                              EmpathyAccountsDialog    *dialog);
122 static void       accounts_dialog_account_removed_cb        (McAccountMonitor         *monitor,
123                                                              gchar                    *unique_name,
124                                                              EmpathyAccountsDialog    *dialog);
125 static gboolean   accounts_dialog_row_changed_foreach       (GtkTreeModel             *model,
126                                                              GtkTreePath              *path,
127                                                              GtkTreeIter              *iter,
128                                                              gpointer                  user_data);
129 static gboolean   accounts_dialog_flash_connecting_cb       (EmpathyAccountsDialog    *dialog);
130 static void       accounts_dialog_status_changed_cb         (MissionControl           *mc,
131                                                              TpConnectionStatus        status,
132                                                              McPresence                presence,
133                                                              TpConnectionStatusReason  reason,
134                                                              const gchar              *unique_name,
135                                                              EmpathyAccountsDialog    *dialog);
136 static void       accounts_dialog_button_create_clicked_cb  (GtkWidget                *button,
137                                                              EmpathyAccountsDialog    *dialog);
138 static void       accounts_dialog_button_back_clicked_cb    (GtkWidget                *button,
139                                                              EmpathyAccountsDialog    *dialog);
140 static void       accounts_dialog_button_add_clicked_cb     (GtkWidget                *button,
141                                                              EmpathyAccountsDialog    *dialog);
142 static void       accounts_dialog_remove_response_cb        (GtkWidget                *dialog,
143                                                              gint                      response,
144                                                              McAccount                *account);
145 static void       accounts_dialog_button_remove_clicked_cb  (GtkWidget                *button,
146                                                              EmpathyAccountsDialog    *dialog);
147 static void       accounts_dialog_response_cb               (GtkWidget                *widget,
148                                                              gint                      response,
149                                                              EmpathyAccountsDialog    *dialog);
150 static void       accounts_dialog_destroy_cb                (GtkWidget                *widget,
151                                                              EmpathyAccountsDialog    *dialog);
152
153 static void
154 accounts_dialog_setup (EmpathyAccountsDialog *dialog)
155 {
156         GtkTreeView  *view;
157         GtkListStore *store;
158         GtkTreeIter   iter;
159         GList        *accounts, *l;
160
161         view = GTK_TREE_VIEW (dialog->treeview);
162         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
163
164         accounts = mc_accounts_list ();
165
166         for (l = accounts; l; l = l->next) {
167                 McAccount          *account;
168                 const gchar        *name;
169                 TpConnectionStatus  status;
170                 gboolean            enabled;
171
172                 account = l->data;
173
174                 name = mc_account_get_display_name (account);
175                 if (!name) {
176                         continue;
177                 }
178
179                 status = mission_control_get_connection_status (dialog->mc, account, NULL);
180                 enabled = mc_account_is_enabled (account);
181
182                 gtk_list_store_insert_with_values (store, &iter,
183                                                    -1,
184                                                    COL_ENABLED, enabled,
185                                                    COL_NAME, name,
186                                                    COL_STATUS, status,
187                                                    COL_ACCOUNT_POINTER, account,
188                                                    -1);
189
190                 accounts_dialog_status_changed_cb (dialog->mc,
191                                                    status,
192                                                    MC_PRESENCE_UNSET,
193                                                    TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
194                                                    mc_account_get_unique_name (account),
195                                                    dialog);
196
197                 g_object_unref (account);
198         }
199
200         g_list_free (accounts);
201 }
202
203 static void
204 accounts_dialog_update_account (EmpathyAccountsDialog *dialog,
205                                 McAccount            *account)
206 {
207         if (dialog->settings_widget) {
208                 gtk_widget_destroy (dialog->settings_widget);
209                 dialog->settings_widget = NULL;
210         }
211
212         if (!account) {
213                 GtkTreeView  *view;
214                 GtkTreeModel *model;
215                 GString      *string;
216                 gchar        *str;
217
218                 gtk_widget_show (dialog->frame_no_account);
219                 gtk_widget_hide (dialog->vbox_details);
220
221                 gtk_widget_set_sensitive (dialog->button_remove, FALSE);
222
223                 view = GTK_TREE_VIEW (dialog->treeview);
224                 model = gtk_tree_view_get_model (view);
225
226                 if (empathy_profile_chooser_n_profiles (dialog->combobox_profile) > 0) {
227                         string = g_string_new (_("To add a new account, you can click on the "
228                                                  "'Add' button and a new entry will be created "
229                                                  "for you to start configuring."));
230                 } else {
231                         string = g_string_new (_("To add a new account, you first have to "
232                                                  "install a backend for each protocol "
233                                                  "you want to use."));
234                 }
235
236                 if (gtk_tree_model_iter_n_children (model, NULL) > 0) {
237                         gtk_label_set_markup (GTK_LABEL (dialog->label_no_account),
238                                               _("<b>No Account Selected</b>"));
239                         g_string_append (string, _("\n\n"
240                                         "If you do not want to add an account, simply "
241                                         "click on the account you want to configure in "
242                                         "the list on the left."));
243                 } else {
244                         gtk_label_set_markup (GTK_LABEL (dialog->label_no_account),
245                                               _("<b>No Accounts Configured</b>"));
246                 }
247
248                 str = g_string_free (string, FALSE);
249                 gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb),
250                                       str);
251                 g_free (str);
252         } else {
253                 McProfile *profile;
254                 const gchar *config_ui;
255
256                 gtk_widget_hide (dialog->frame_no_account);
257                 gtk_widget_show (dialog->vbox_details);
258
259                 profile = mc_account_get_profile (account);
260                 config_ui = mc_profile_get_configuration_ui (profile);
261                 g_object_unref (profile);
262
263                 if (!tp_strdiff (config_ui, "jabber")) {
264                         dialog->settings_widget = 
265                                 empathy_account_widget_jabber_new (account);
266                 } 
267                 else if (!tp_strdiff (config_ui, "msn")) {
268                         dialog ->settings_widget =
269                                 empathy_account_widget_msn_new (account);
270                 }
271                 else if (!tp_strdiff (config_ui, "local-xmpp")) {
272                         dialog->settings_widget =
273                                 empathy_account_widget_salut_new (account);
274                 }
275                 else {
276                         dialog->settings_widget = 
277                                 empathy_account_widget_generic_new (account);
278                 }
279         }
280
281         if (dialog->settings_widget) {
282                 gtk_container_add (GTK_CONTAINER (dialog->alignment_settings),
283                                    dialog->settings_widget);
284         }
285
286         if (account) {
287                 McProfile *profile;
288                 gchar     *text;
289
290                 profile = mc_account_get_profile (account);
291                 gtk_image_set_from_icon_name (GTK_IMAGE (dialog->image_type),
292                                               mc_profile_get_icon_name (profile),
293                                               GTK_ICON_SIZE_DIALOG);
294                 gtk_widget_set_tooltip_text (dialog->image_type,
295                                              mc_profile_get_display_name (profile));
296
297                 text = g_strdup_printf ("<big><b>%s</b></big>", mc_account_get_display_name (account));
298                 gtk_label_set_markup (GTK_LABEL (dialog->label_name), text);
299                 g_free (text);
300         }
301 }
302
303 static void
304 accounts_dialog_model_setup (EmpathyAccountsDialog *dialog)
305 {
306         GtkListStore     *store;
307         GtkTreeSelection *selection;
308
309         store = gtk_list_store_new (COL_COUNT,
310                                     G_TYPE_BOOLEAN,    /* enabled */
311                                     G_TYPE_STRING,     /* name */
312                                     G_TYPE_UINT,       /* status */
313                                     MC_TYPE_ACCOUNT);  /* account */
314
315         gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview),
316                                  GTK_TREE_MODEL (store));
317
318         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview));
319         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
320
321         g_signal_connect (selection, "changed",
322                           G_CALLBACK (accounts_dialog_model_selection_changed),
323                           dialog);
324
325         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
326                                               COL_NAME, GTK_SORT_ASCENDING);
327
328         accounts_dialog_model_add_columns (dialog);
329
330         g_object_unref (store);
331 }
332
333 static void
334 accounts_dialog_name_edited_cb (GtkCellRendererText   *renderer,
335                                 gchar                 *path,
336                                 gchar                 *new_text,
337                                 EmpathyAccountsDialog *dialog)
338 {
339         McAccount    *account;
340         GtkTreeModel *model;
341         GtkTreePath  *treepath;
342         GtkTreeIter   iter;
343
344         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
345         treepath = gtk_tree_path_new_from_string (path);
346         gtk_tree_model_get_iter (model, &iter, treepath);
347         gtk_tree_model_get (model, &iter,
348                             COL_ACCOUNT_POINTER, &account,
349                             -1);
350         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
351                             COL_NAME, new_text,
352                             -1);
353         gtk_tree_path_free (treepath);
354
355         mc_account_set_display_name (account, new_text);
356         g_object_unref (account);
357 }
358
359 static void
360 accounts_dialog_enable_toggled_cb (GtkCellRendererToggle *cell_renderer,
361                                    gchar                 *path,
362                                    EmpathyAccountsDialog *dialog)
363 {
364         McAccount    *account;
365         GtkTreeModel *model;
366         GtkTreePath  *treepath;
367         GtkTreeIter   iter;
368         gboolean      enabled;
369
370         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
371         treepath = gtk_tree_path_new_from_string (path);
372         gtk_tree_model_get_iter (model, &iter, treepath);
373         gtk_tree_model_get (model, &iter,
374                             COL_ACCOUNT_POINTER, &account,
375                             -1);
376         gtk_tree_path_free (treepath);
377
378         enabled = mc_account_is_enabled (account);
379         mc_account_set_enabled (account, !enabled);
380
381         empathy_debug (DEBUG_DOMAIN, "%s account %s",
382                        enabled ? "Disabled" : "Enable",
383                        mc_account_get_display_name(account));
384
385         g_object_unref (account);
386 }
387
388 static void
389 accounts_dialog_model_add_columns (EmpathyAccountsDialog *dialog)
390 {
391         GtkTreeView       *view;
392         GtkTreeViewColumn *column;
393         GtkCellRenderer   *cell;
394
395         view = GTK_TREE_VIEW (dialog->treeview);
396         gtk_tree_view_set_headers_visible (view, TRUE);
397
398         /* Enabled column */
399         cell = gtk_cell_renderer_toggle_new ();
400         gtk_tree_view_insert_column_with_attributes (view, -1,
401                                                      _("Enabled"),
402                                                      cell,
403                                                      "active", COL_ENABLED,
404                                                      NULL);
405         g_signal_connect (cell, "toggled",
406                           G_CALLBACK (accounts_dialog_enable_toggled_cb),
407                           dialog);
408         
409         /* Account column */
410         column = gtk_tree_view_column_new ();
411         gtk_tree_view_column_set_title (column, _("Accounts"));
412         gtk_tree_view_column_set_expand (column, TRUE);
413         gtk_tree_view_append_column (view, column);
414
415         /* Icon renderer */
416         cell = gtk_cell_renderer_pixbuf_new ();
417         gtk_tree_view_column_pack_start (column, cell, FALSE);
418         gtk_tree_view_column_set_cell_data_func (column, cell,
419                                                  (GtkTreeCellDataFunc)
420                                                  accounts_dialog_model_pixbuf_data_func,
421                                                  dialog,
422                                                  NULL);
423
424         /* Name renderer */
425         cell = gtk_cell_renderer_text_new ();
426         g_object_set (cell,
427                       "ellipsize", PANGO_ELLIPSIZE_END,
428                       "editable", TRUE,
429                       NULL);
430         gtk_tree_view_column_pack_start (column, cell, TRUE);
431         gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME);
432         g_signal_connect (cell, "edited",
433                           G_CALLBACK (accounts_dialog_name_edited_cb),
434                           dialog);
435 }
436
437 static void
438 accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog)
439 {
440         GtkTreeView      *view;
441         GtkTreeModel     *model;
442         GtkTreeSelection *selection;
443         GtkTreeIter       iter;
444
445         /* select first */
446         view = GTK_TREE_VIEW (dialog->treeview);
447         model = gtk_tree_view_get_model (view);
448         
449         if (gtk_tree_model_get_iter_first (model, &iter)) {
450                 selection = gtk_tree_view_get_selection (view);
451                 gtk_tree_selection_select_iter (selection, &iter);
452         } else {
453                 accounts_dialog_update_account (dialog, NULL);
454         }
455 }
456
457 static void
458 accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn    *tree_column,
459                                         GtkCellRenderer      *cell,
460                                         GtkTreeModel         *model,
461                                         GtkTreeIter          *iter,
462                                         EmpathyAccountsDialog *dialog)
463 {
464         McAccount          *account;
465         const gchar        *icon_name;
466         GdkPixbuf          *pixbuf;
467         TpConnectionStatus  status;
468
469         gtk_tree_model_get (model, iter,
470                             COL_STATUS, &status,
471                             COL_ACCOUNT_POINTER, &account,
472                             -1);
473
474         icon_name = empathy_icon_name_from_account (account);
475         pixbuf = empathy_pixbuf_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
476
477         if (pixbuf) {
478                 if (status == TP_CONNECTION_STATUS_DISCONNECTED ||
479                     (status == TP_CONNECTION_STATUS_CONNECTING && 
480                      !dialog->connecting_show)) {
481                         GdkPixbuf *modded_pixbuf;
482
483                         modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
484                                                         TRUE,
485                                                         8,
486                                                         gdk_pixbuf_get_width (pixbuf),
487                                                         gdk_pixbuf_get_height (pixbuf));
488
489                         gdk_pixbuf_saturate_and_pixelate (pixbuf,
490                                                           modded_pixbuf,
491                                                           1.0,
492                                                           TRUE);
493                         g_object_unref (pixbuf);
494                         pixbuf = modded_pixbuf;
495                 }
496         }
497
498         g_object_set (cell,
499                       "visible", TRUE,
500                       "pixbuf", pixbuf,
501                       NULL);
502
503         g_object_unref (account);
504         if (pixbuf) {
505                 g_object_unref (pixbuf);
506         }
507 }
508
509 static gboolean
510 accounts_dialog_get_account_iter (EmpathyAccountsDialog *dialog,
511                                  McAccount             *account,
512                                  GtkTreeIter           *iter)
513 {
514         GtkTreeView      *view;
515         GtkTreeSelection *selection;
516         GtkTreeModel     *model;
517         gboolean          ok;
518         
519         /* Update the status in the model */
520         view = GTK_TREE_VIEW (dialog->treeview);
521         selection = gtk_tree_view_get_selection (view);
522         model = gtk_tree_view_get_model (view);
523
524         for (ok = gtk_tree_model_get_iter_first (model, iter);
525              ok;
526              ok = gtk_tree_model_iter_next (model, iter)) {
527                 McAccount *this_account;
528                 gboolean   equal;
529
530                 gtk_tree_model_get (model, iter,
531                                     COL_ACCOUNT_POINTER, &this_account,
532                                     -1);
533
534                 equal = empathy_account_equal (this_account, account);
535                 g_object_unref (this_account);
536
537                 if (equal) {
538                         return TRUE;
539                 }
540         }
541
542         return FALSE;
543 }
544
545 static McAccount *
546 accounts_dialog_model_get_selected (EmpathyAccountsDialog *dialog)
547 {
548         GtkTreeView      *view;
549         GtkTreeModel     *model;
550         GtkTreeSelection *selection;
551         GtkTreeIter       iter;
552         McAccount        *account;
553
554         view = GTK_TREE_VIEW (dialog->treeview);
555         selection = gtk_tree_view_get_selection (view);
556
557         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
558                 return NULL;
559         }
560
561         gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
562
563         return account;
564 }
565
566 static void
567 accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog,
568                                     McAccount             *account)
569 {
570         GtkTreeSelection *selection;
571         GtkTreeIter       iter;
572
573         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview));
574         if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
575                 gtk_tree_selection_select_iter (selection, &iter);
576         }
577 }
578
579 static gboolean
580 accounts_dialog_model_remove_selected (EmpathyAccountsDialog *dialog)
581 {
582         GtkTreeView      *view;
583         GtkTreeModel     *model;
584         GtkTreeSelection *selection;
585         GtkTreeIter       iter;
586
587         view = GTK_TREE_VIEW (dialog->treeview);
588         selection = gtk_tree_view_get_selection (view);
589
590         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
591                 return FALSE;
592         }
593
594         return gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
595 }
596
597 static void
598 accounts_dialog_model_selection_changed (GtkTreeSelection     *selection,
599                                          EmpathyAccountsDialog *dialog)
600 {
601         McAccount    *account;
602         GtkTreeModel *model;
603         GtkTreeIter   iter;
604         gboolean      is_selection;
605
606         is_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
607
608         gtk_widget_set_sensitive (dialog->button_add, TRUE);
609         gtk_widget_set_sensitive (dialog->button_remove, is_selection);
610
611         account = accounts_dialog_model_get_selected (dialog);
612         accounts_dialog_update_account (dialog, account);
613
614         if (account) {
615                 g_object_unref (account);
616         }
617
618         /* insure new account frame is hidden when a row is selected*/
619         gtk_widget_hide (dialog->frame_new_account);
620 }
621
622 static void
623 accounts_dialog_add_account (EmpathyAccountsDialog *dialog,
624                              McAccount             *account)
625 {
626         GtkTreeModel       *model;
627         GtkTreeIter         iter;
628         TpConnectionStatus  status;
629         const gchar        *name;
630         gboolean            enabled;
631
632         if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
633                 return;
634         }
635
636         status = mission_control_get_connection_status (dialog->mc, account, NULL);
637         name = mc_account_get_display_name (account);
638         enabled = mc_account_is_enabled (account);
639
640         g_return_if_fail (name != NULL);
641
642         empathy_debug (DEBUG_DOMAIN, "Adding new account: %s", name);
643
644         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
645         gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter,
646                                            -1,
647                                            COL_ENABLED, enabled,
648                                            COL_NAME, name,
649                                            COL_STATUS, status,
650                                            COL_ACCOUNT_POINTER, account,
651                                            -1);
652 }
653
654 static void
655 accounts_dialog_account_added_cb (McAccountMonitor     *monitor,
656                                   gchar                *unique_name,
657                                   EmpathyAccountsDialog *dialog)
658 {
659         McAccount *account;
660
661         account = mc_account_lookup (unique_name);
662         accounts_dialog_add_account (dialog, account);
663         g_object_unref (account);
664 }
665
666 static void
667 accounts_dialog_account_removed_cb (McAccountMonitor     *monitor,
668                                     gchar                *unique_name,
669                                     EmpathyAccountsDialog *dialog)
670 {
671         McAccount *account;
672
673         account = mc_account_lookup (unique_name);
674
675         accounts_dialog_model_set_selected (dialog, account);
676         accounts_dialog_model_remove_selected (dialog);
677
678         g_object_unref (account);
679 }
680
681 static gboolean
682 accounts_dialog_row_changed_foreach (GtkTreeModel *model,
683                                      GtkTreePath  *path,
684                                      GtkTreeIter  *iter,
685                                      gpointer      user_data)
686 {
687         gtk_tree_model_row_changed (model, path, iter);
688
689         return FALSE;
690 }
691
692 static gboolean
693 accounts_dialog_flash_connecting_cb (EmpathyAccountsDialog *dialog)
694 {
695         GtkTreeView  *view;
696         GtkTreeModel *model;
697
698         dialog->connecting_show = !dialog->connecting_show;
699
700         view = GTK_TREE_VIEW (dialog->treeview);
701         model = gtk_tree_view_get_model (view);
702
703         gtk_tree_model_foreach (model, accounts_dialog_row_changed_foreach, NULL);
704
705         return TRUE;
706 }
707
708 static void
709 accounts_dialog_status_changed_cb (MissionControl           *mc,
710                                    TpConnectionStatus        status,
711                                    McPresence                presence,
712                                    TpConnectionStatusReason  reason,
713                                    const gchar              *unique_name,
714                                    EmpathyAccountsDialog    *dialog)
715 {
716         GtkTreeModel *model;
717         GtkTreeIter   iter;
718         McAccount    *account;
719         GList        *accounts, *l;
720         gboolean      found = FALSE;
721         
722         /* Update the status in the model */
723         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
724         account = mc_account_lookup (unique_name);
725
726         empathy_debug (DEBUG_DOMAIN, "Status changed for account %s: "
727                       "status=%d presence=%d",
728                       unique_name, status, presence);
729
730         if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
731                 GtkTreePath *path;
732
733                 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
734                                     COL_STATUS, status,
735                                     -1);
736
737                 path = gtk_tree_model_get_path (model, &iter);
738                 gtk_tree_model_row_changed (model, path, &iter);
739                 gtk_tree_path_free (path);
740         }
741         g_object_unref (account);
742
743         /* Check if there is still accounts in CONNECTING state */
744         accounts = mc_accounts_list ();
745         for (l = accounts; l; l = l->next) {
746                 McAccount          *this_account;
747                 TpConnectionStatus  status;
748
749                 this_account = l->data;
750
751                 status = mission_control_get_connection_status (mc, this_account, NULL);
752                 if (status == TP_CONNECTION_STATUS_CONNECTING) {
753                         found = TRUE;
754                         break;
755                 }
756
757                 g_object_unref (this_account);
758         }
759         g_list_free (accounts);
760
761         if (!found && dialog->connecting_id) {
762                 g_source_remove (dialog->connecting_id);
763                 dialog->connecting_id = 0;
764         }
765         if (found && !dialog->connecting_id) {
766                 dialog->connecting_id = g_timeout_add (FLASH_TIMEOUT,
767                                                        (GSourceFunc) accounts_dialog_flash_connecting_cb,
768                                                        dialog);
769         }
770 }
771
772 static void
773 accounts_dialog_account_enabled_cb (McAccountMonitor      *monitor,
774                                     gchar                 *unique_name,
775                                     EmpathyAccountsDialog *dialog)
776 {
777         GtkTreeModel *model;
778         GtkTreeIter   iter;
779         McAccount    *account;
780         gboolean      enabled;
781
782         /* Update the status in the model */
783         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
784         account = mc_account_lookup (unique_name);
785         enabled = mc_account_is_enabled (account);
786
787         empathy_debug (DEBUG_DOMAIN, "Account %s is now %s",
788                        mc_account_get_display_name (account),
789                        enabled ? "enabled" : "disabled");
790
791         if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
792                 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
793                                     COL_ENABLED, enabled,
794                                     -1);
795         }
796
797         g_object_unref (account);
798 }
799
800 static void
801 accounts_dialog_button_create_clicked_cb (GtkWidget             *button,
802                                           EmpathyAccountsDialog  *dialog)
803 {
804         McProfile   *profile;
805         McAccount   *account;
806         const gchar *str;
807
808         /* Update widgets */
809         gtk_widget_show (dialog->vbox_details);
810         gtk_widget_hide (dialog->frame_no_account);
811         gtk_widget_hide (dialog->frame_new_account);
812
813         profile = empathy_profile_chooser_get_selected (dialog->combobox_profile);
814
815         /* Create account */
816         account = mc_account_create (profile);
817
818         str = mc_account_get_unique_name (account);
819         mc_account_set_display_name (account, str);
820
821         accounts_dialog_add_account (dialog, account);
822         accounts_dialog_model_set_selected (dialog, account);
823
824         g_object_unref (account);
825         g_object_unref (profile);
826 }
827
828 static void
829 accounts_dialog_button_back_clicked_cb (GtkWidget             *button,
830                                         EmpathyAccountsDialog  *dialog)
831 {
832         McAccount *account;
833
834         gtk_widget_hide (dialog->vbox_details);
835         gtk_widget_hide (dialog->frame_no_account);
836         gtk_widget_hide (dialog->frame_new_account);
837
838         gtk_widget_set_sensitive (dialog->button_add, TRUE);
839
840         account = accounts_dialog_model_get_selected (dialog);
841         accounts_dialog_update_account (dialog, account);
842 }
843
844 static void
845 accounts_dialog_button_add_clicked_cb (GtkWidget             *button,
846                                        EmpathyAccountsDialog *dialog)
847 {
848         GtkTreeView      *view;
849         GtkTreeSelection *selection;
850
851         view = GTK_TREE_VIEW (dialog->treeview);
852         selection = gtk_tree_view_get_selection (view);
853         gtk_tree_selection_unselect_all (selection);
854
855         gtk_widget_set_sensitive (dialog->button_add, FALSE);
856         gtk_widget_hide (dialog->vbox_details);
857         gtk_widget_hide (dialog->frame_no_account);
858         gtk_widget_show (dialog->frame_new_account);
859
860         gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_profile), 0);
861         gtk_widget_grab_focus (dialog->combobox_profile);
862 }
863
864 static void
865 accounts_dialog_remove_response_cb (GtkWidget *dialog,
866                                     gint       response,
867                                     McAccount *account)
868 {
869         if (response == GTK_RESPONSE_YES) {
870                 mc_account_delete (account);
871         }
872
873         gtk_widget_destroy (dialog);
874 }
875
876 static void
877 accounts_dialog_button_remove_clicked_cb (GtkWidget            *button,
878                                           EmpathyAccountsDialog *dialog)
879 {
880         McAccount *account;
881         GtkWidget *message_dialog;
882
883         account = accounts_dialog_model_get_selected (dialog);
884
885         if (!mc_account_is_complete (account)) {
886                 accounts_dialog_model_remove_selected (dialog);
887                 return;
888         }
889         message_dialog = gtk_message_dialog_new
890                 (GTK_WINDOW (dialog->window),
891                  GTK_DIALOG_DESTROY_WITH_PARENT,
892                  GTK_MESSAGE_QUESTION,
893                  GTK_BUTTONS_NONE,
894                  _("You are about to remove your %s account!\n"
895                    "Are you sure you want to proceed?"),
896                  mc_account_get_display_name (account));
897
898         gtk_message_dialog_format_secondary_text
899                 (GTK_MESSAGE_DIALOG (message_dialog),
900                  _("Any associated conversations and chat rooms will NOT be "
901                    "removed if you decide to proceed.\n"
902                    "\n"
903                    "Should you decide to add the account back at a later time, "
904                    "they will still be available."));
905
906         gtk_dialog_add_button (GTK_DIALOG (message_dialog),
907                                GTK_STOCK_CANCEL, 
908                                GTK_RESPONSE_NO);
909         gtk_dialog_add_button (GTK_DIALOG (message_dialog),
910                                GTK_STOCK_REMOVE, 
911                                GTK_RESPONSE_YES);
912
913         g_signal_connect (message_dialog, "response",
914                           G_CALLBACK (accounts_dialog_remove_response_cb),
915                           account);
916
917         gtk_widget_show (message_dialog);
918 }
919
920 static void
921 accounts_dialog_response_cb (GtkWidget            *widget,
922                              gint                  response,
923                              EmpathyAccountsDialog *dialog)
924 {
925         gtk_widget_destroy (widget);
926 }
927
928 static void
929 accounts_dialog_destroy_cb (GtkWidget            *widget,
930                             EmpathyAccountsDialog *dialog)
931 {
932         GList *accounts, *l;
933
934         /* Disconnect signals */
935         g_signal_handlers_disconnect_by_func (dialog->monitor,
936                                               accounts_dialog_account_added_cb,
937                                               dialog);
938         g_signal_handlers_disconnect_by_func (dialog->monitor,
939                                               accounts_dialog_account_removed_cb,
940                                               dialog);
941         g_signal_handlers_disconnect_by_func (dialog->monitor,
942                                               accounts_dialog_account_enabled_cb,
943                                               dialog);
944         dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (dialog->mc),
945                                         "AccountStatusChanged",
946                                         G_CALLBACK (accounts_dialog_status_changed_cb),
947                                         dialog);
948
949         /* Delete incomplete accounts */
950         accounts = mc_accounts_list ();
951         for (l = accounts; l; l = l->next) {
952                 McAccount *account;
953
954                 account = l->data;
955                 if (!mc_account_is_complete (account)) {
956                         /* FIXME: Warn the user the account is not complete
957                          *        and is going to be removed. */
958                         mc_account_delete (account);
959                 }
960
961                 g_object_unref (account);
962         }
963         g_list_free (accounts);
964
965         if (dialog->connecting_id) {
966                 g_source_remove (dialog->connecting_id);
967         }
968
969         g_object_unref (dialog->mc);
970         g_object_unref (dialog->monitor);
971         
972         g_free (dialog);
973 }
974
975 GtkWidget *
976 empathy_accounts_dialog_show (GtkWindow *parent)
977 {
978         static EmpathyAccountsDialog *dialog = NULL;
979         GladeXML                    *glade;
980         GtkWidget                   *bbox;
981         GtkWidget                   *button_close;
982
983         if (dialog) {
984                 gtk_window_present (GTK_WINDOW (dialog->window));
985                 return dialog->window;
986         }
987
988         dialog = g_new0 (EmpathyAccountsDialog, 1);
989
990         glade = empathy_glade_get_file ("empathy-accounts-dialog.glade",
991                                        "accounts_dialog",
992                                        NULL,
993                                        "accounts_dialog", &dialog->window,
994                                        "vbox_details", &dialog->vbox_details,
995                                        "frame_no_account", &dialog->frame_no_account,
996                                        "label_no_account", &dialog->label_no_account,
997                                        "label_no_account_blurb", &dialog->label_no_account_blurb,
998                                        "alignment_settings", &dialog->alignment_settings,
999                                        "dialog-action_area", &bbox,
1000                                        "treeview", &dialog->treeview,
1001                                        "frame_new_account", &dialog->frame_new_account,
1002                                        "hbox_type", &dialog->hbox_type,
1003                                        "button_create", &dialog->button_create,
1004                                        "button_back", &dialog->button_back,
1005                                        "image_type", &dialog->image_type,
1006                                        "label_name", &dialog->label_name,
1007                                        "button_add", &dialog->button_add,
1008                                        "button_remove", &dialog->button_remove,
1009                                        "button_close", &button_close,
1010                                        NULL);
1011
1012         empathy_glade_connect (glade,
1013                               dialog,
1014                               "accounts_dialog", "destroy", accounts_dialog_destroy_cb,
1015                               "accounts_dialog", "response", accounts_dialog_response_cb,
1016                               "button_create", "clicked", accounts_dialog_button_create_clicked_cb,
1017                               "button_back", "clicked", accounts_dialog_button_back_clicked_cb,
1018                               "button_add", "clicked", accounts_dialog_button_add_clicked_cb,
1019                               "button_remove", "clicked", accounts_dialog_button_remove_clicked_cb,
1020                               NULL);
1021
1022         g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog);
1023
1024         g_object_unref (glade);
1025
1026         /* Create profile chooser */
1027         dialog->combobox_profile = empathy_profile_chooser_new ();
1028         gtk_box_pack_end (GTK_BOX (dialog->hbox_type),
1029                           dialog->combobox_profile,
1030                           TRUE, TRUE, 0);
1031         gtk_widget_show (dialog->combobox_profile);
1032         if (empathy_profile_chooser_n_profiles (dialog->combobox_profile) <= 0) {
1033                 gtk_widget_set_sensitive (dialog->button_add, FALSE);
1034         }
1035
1036         /* Set up signalling */
1037         dialog->mc = empathy_mission_control_new ();
1038         dialog->monitor = mc_account_monitor_new ();
1039
1040         g_signal_connect (dialog->monitor, "account-created",
1041                           G_CALLBACK (accounts_dialog_account_added_cb),
1042                           dialog);
1043         g_signal_connect (dialog->monitor, "account-deleted",
1044                           G_CALLBACK (accounts_dialog_account_removed_cb),
1045                           dialog);
1046         g_signal_connect (dialog->monitor, "account-enabled",
1047                           G_CALLBACK (accounts_dialog_account_enabled_cb),
1048                           dialog);
1049         g_signal_connect (dialog->monitor, "account-disabled",
1050                           G_CALLBACK (accounts_dialog_account_enabled_cb),
1051                           dialog);
1052         dbus_g_proxy_connect_signal (DBUS_G_PROXY (dialog->mc), "AccountStatusChanged",
1053                                      G_CALLBACK (accounts_dialog_status_changed_cb),
1054                                      dialog, NULL);
1055
1056         accounts_dialog_model_setup (dialog);
1057         accounts_dialog_setup (dialog);
1058         accounts_dialog_model_select_first (dialog);
1059
1060         if (parent) {
1061                 gtk_window_set_transient_for (GTK_WINDOW (dialog->window),
1062                                               GTK_WINDOW (parent));
1063         }
1064
1065         gtk_widget_show (dialog->window);
1066
1067         return dialog->window;
1068 }
1069