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