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