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