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