]> git.0d.be Git - empathy.git/blob - src/empathy-accounts-dialog.c
rename import boolean to import_asked.
[empathy.git] / src / 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 #include <libempathy-gtk/empathy-profile-chooser.h>
44 #include <libempathy-gtk/empathy-account-widget.h>
45 #include <libempathy-gtk/empathy-account-widget-irc.h>
46 #include <libempathy-gtk/empathy-account-widget-sip.h>
47 #include <libempathy-gtk/empathy-conf.h>
48
49 #include "empathy-accounts-dialog.h"
50 #include "empathy-import-dialog.h"
51
52 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
53 #include <libempathy/empathy-debug.h>
54
55 /* Flashing delay for icons (milliseconds). */
56 #define FLASH_TIMEOUT 500
57
58 typedef struct {
59         GtkWidget        *window;
60
61         GtkWidget        *alignment_settings;
62
63         GtkWidget        *vbox_details;
64         GtkWidget        *frame_no_profile;
65
66         GtkWidget        *treeview;
67
68         GtkWidget        *button_add;
69         GtkWidget        *button_remove;
70         GtkWidget        *button_import;
71
72         GtkWidget        *frame_new_account;
73         GtkWidget        *combobox_profile;
74         GtkWidget        *hbox_type;
75         GtkWidget        *button_create;
76         GtkWidget        *button_back;
77         GtkWidget        *checkbutton_register;
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
87         MissionControl   *mc;
88         McAccountMonitor *monitor;
89         gpointer          token;
90 } EmpathyAccountsDialog;
91
92 enum {
93         COL_ENABLED,
94         COL_NAME,
95         COL_STATUS,
96         COL_ACCOUNT_POINTER,
97         COL_COUNT
98 };
99
100 static void       accounts_dialog_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_name_editing_started_cb   (GtkCellRenderer          *renderer,
105                                                              GtkCellEditable          *editable,
106                                                              gchar                    *path,
107                                                              EmpathyAccountsDialog    *dialog);
108 static void       accounts_dialog_model_select_first        (EmpathyAccountsDialog    *dialog);
109 static void       accounts_dialog_model_pixbuf_data_func    (GtkTreeViewColumn        *tree_column,
110                                                              GtkCellRenderer          *cell,
111                                                              GtkTreeModel             *model,
112                                                              GtkTreeIter              *iter,
113                                                              EmpathyAccountsDialog    *dialog);
114 static McAccount *accounts_dialog_model_get_selected        (EmpathyAccountsDialog    *dialog);
115 static void       accounts_dialog_model_set_selected        (EmpathyAccountsDialog    *dialog,
116                                                              McAccount                *account);
117 static gboolean   accounts_dialog_model_remove_selected     (EmpathyAccountsDialog    *dialog);
118 static void       accounts_dialog_model_selection_changed   (GtkTreeSelection         *selection,
119                                                              EmpathyAccountsDialog    *dialog);
120 static void       accounts_dialog_add_or_update_account     (EmpathyAccountsDialog    *dialog,
121                                                              McAccount                *account);
122 static void       accounts_dialog_account_added_cb          (McAccountMonitor         *monitor,
123                                                              gchar                    *unique_name,
124                                                              EmpathyAccountsDialog    *dialog);
125 static void       accounts_dialog_account_removed_cb        (McAccountMonitor         *monitor,
126                                                              gchar                    *unique_name,
127                                                              EmpathyAccountsDialog    *dialog);
128 static gboolean   accounts_dialog_row_changed_foreach       (GtkTreeModel             *model,
129                                                              GtkTreePath              *path,
130                                                              GtkTreeIter              *iter,
131                                                              gpointer                  user_data);
132 static gboolean   accounts_dialog_flash_connecting_cb       (EmpathyAccountsDialog    *dialog);
133 static gboolean   accounts_dialog_are_accounts_connecting   (MissionControl           *mc);
134 static void       accounts_dialog_status_changed_cb         (MissionControl           *mc,
135                                                              TpConnectionStatus        status,
136                                                              McPresence                presence,
137                                                              TpConnectionStatusReason  reason,
138                                                              const gchar              *unique_name,
139                                                              EmpathyAccountsDialog    *dialog);
140 static void       accounts_dialog_button_create_clicked_cb  (GtkWidget                *button,
141                                                              EmpathyAccountsDialog    *dialog);
142 static void       accounts_dialog_button_back_clicked_cb    (GtkWidget                *button,
143                                                              EmpathyAccountsDialog    *dialog);
144 static void       accounts_dialog_button_add_clicked_cb     (GtkWidget                *button,
145                                                              EmpathyAccountsDialog    *dialog);
146 static void       accounts_dialog_button_help_clicked_cb    (GtkWidget                *button,
147                                                              EmpathyAccountsDialog    *dialog);
148 static void       accounts_dialog_button_remove_clicked_cb  (GtkWidget                *button,
149                                                              EmpathyAccountsDialog    *dialog);
150 static void       accounts_dialog_button_import_clicked_cb  (GtkWidget                *button,
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_update_name_label (EmpathyAccountsDialog *dialog,
160                                    McAccount             *account)
161 {
162         gchar *text;
163
164         text = g_markup_printf_escaped ("<big><b>%s</b></big>",
165                         mc_account_get_display_name (account));
166         gtk_label_set_markup (GTK_LABEL (dialog->label_name), text);
167
168         g_free (text);
169 }
170
171 static void
172 accounts_dialog_update_account (EmpathyAccountsDialog *dialog,
173                                 McAccount            *account)
174 {
175         McProfile   *profile;
176         const gchar *config_ui;
177
178         if (!account) {
179                 GtkTreeView  *view;
180                 GtkTreeModel *model;
181
182                 view = GTK_TREE_VIEW (dialog->treeview);
183                 model = gtk_tree_view_get_model (view);
184
185                 if (gtk_tree_model_iter_n_children (model, NULL) > 0) {
186                         /* We have configured accounts, select the first one */
187                         accounts_dialog_model_select_first (dialog);
188                         return;
189                 }
190                 if (empathy_profile_chooser_n_profiles (dialog->combobox_profile) > 0) {
191                         /* We have no account configured but we have some
192                          * profiles instsalled. The user obviously wants to add
193                          * an account. Click on the Add button for him. */
194                         accounts_dialog_button_add_clicked_cb (dialog->button_add,
195                                                                dialog);
196                         return;
197                 }
198
199                 /* No account and no profile, warn the user */
200                 gtk_widget_hide (dialog->vbox_details);
201                 gtk_widget_hide (dialog->frame_new_account);
202                 gtk_widget_show (dialog->frame_no_profile);
203                 gtk_widget_set_sensitive (dialog->button_add, FALSE);
204                 gtk_widget_set_sensitive (dialog->button_remove, FALSE);
205                 return;
206         }
207
208         /* We have an account selected, destroy old settings and create a new
209          * one for the account selected */
210         gtk_widget_hide (dialog->frame_new_account);
211         gtk_widget_hide (dialog->frame_no_profile);
212         gtk_widget_show (dialog->vbox_details);
213         gtk_widget_set_sensitive (dialog->button_add, TRUE);
214         gtk_widget_set_sensitive (dialog->button_remove, TRUE);
215
216         if (dialog->settings_widget) {
217                 gtk_widget_destroy (dialog->settings_widget);
218                 dialog->settings_widget = NULL;
219         }
220
221         profile = mc_account_get_profile (account);
222         config_ui = mc_profile_get_configuration_ui (profile);
223         if (!tp_strdiff (config_ui, "jabber")) {
224                 dialog->settings_widget = 
225                         empathy_account_widget_jabber_new (account);
226         } 
227         else if (!tp_strdiff (config_ui, "msn")) {
228                 dialog ->settings_widget =
229                         empathy_account_widget_msn_new (account);
230         }
231         else if (!tp_strdiff (config_ui, "local-xmpp")) {
232                 dialog->settings_widget =
233                         empathy_account_widget_salut_new (account);
234         }
235         else if (!tp_strdiff (config_ui, "irc")) {
236                 dialog->settings_widget =
237                         empathy_account_widget_irc_new (account);
238         }
239         else if (!tp_strdiff(config_ui, "icq")) {
240                 dialog->settings_widget =
241                         empathy_account_widget_icq_new (account);
242         }
243         else if (!tp_strdiff(config_ui, "aim")) {
244                 dialog->settings_widget =
245                         empathy_account_widget_aim_new (account);
246         }
247         else if (!tp_strdiff (config_ui, "yahoo")) {
248                 dialog->settings_widget =
249                         empathy_account_widget_yahoo_new (account);
250         }
251         else if  (!tp_strdiff (config_ui, "sofiasip")) {
252                 dialog->settings_widget =
253                         empathy_account_widget_sip_new (account);
254         }
255         else if  (!tp_strdiff (config_ui, "groupwise")) {
256                 dialog->settings_widget =
257                         empathy_account_widget_groupwise_new (account);
258         }
259         else {
260                 dialog->settings_widget = 
261                         empathy_account_widget_generic_new (account);
262         }
263
264         gtk_container_add (GTK_CONTAINER (dialog->alignment_settings),
265                            dialog->settings_widget);
266
267
268         gtk_image_set_from_icon_name (GTK_IMAGE (dialog->image_type),
269                                       mc_profile_get_icon_name (profile),
270                                       GTK_ICON_SIZE_DIALOG);
271         gtk_widget_set_tooltip_text (dialog->image_type,
272                                      mc_profile_get_display_name (profile));
273
274         accounts_dialog_update_name_label (dialog, account);
275
276         g_object_unref (profile);
277 }
278
279 static void
280 accounts_dialog_model_setup (EmpathyAccountsDialog *dialog)
281 {
282         GtkListStore     *store;
283         GtkTreeSelection *selection;
284
285         store = gtk_list_store_new (COL_COUNT,
286                                     G_TYPE_BOOLEAN,    /* enabled */
287                                     G_TYPE_STRING,     /* name */
288                                     G_TYPE_UINT,       /* status */
289                                     MC_TYPE_ACCOUNT);  /* account */
290
291         gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview),
292                                  GTK_TREE_MODEL (store));
293
294         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview));
295         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
296
297         g_signal_connect (selection, "changed",
298                           G_CALLBACK (accounts_dialog_model_selection_changed),
299                           dialog);
300
301         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
302                                               COL_NAME, GTK_SORT_ASCENDING);
303
304         accounts_dialog_model_add_columns (dialog);
305
306         g_object_unref (store);
307 }
308
309 static void
310 accounts_dialog_name_edited_cb (GtkCellRendererText   *renderer,
311                                 gchar                 *path,
312                                 gchar                 *new_text,
313                                 EmpathyAccountsDialog *dialog)
314 {
315         McAccount    *account;
316         GtkTreeModel *model;
317         GtkTreePath  *treepath;
318         GtkTreeIter   iter;
319
320         if (accounts_dialog_are_accounts_connecting (dialog->mc)) {
321                 dialog->connecting_id = g_timeout_add (FLASH_TIMEOUT,
322                                                        (GSourceFunc) accounts_dialog_flash_connecting_cb,
323                                                        dialog);
324         }
325
326         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
327         treepath = gtk_tree_path_new_from_string (path);
328         gtk_tree_model_get_iter (model, &iter, treepath);
329         gtk_tree_model_get (model, &iter,
330                             COL_ACCOUNT_POINTER, &account,
331                             -1);
332         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
333                             COL_NAME, new_text,
334                             -1);
335         gtk_tree_path_free (treepath);
336
337         mc_account_set_display_name (account, new_text);
338         g_object_unref (account);
339 }
340
341 static void
342 accounts_dialog_enable_toggled_cb (GtkCellRendererToggle *cell_renderer,
343                                    gchar                 *path,
344                                    EmpathyAccountsDialog *dialog)
345 {
346         McAccount    *account;
347         GtkTreeModel *model;
348         GtkTreePath  *treepath;
349         GtkTreeIter   iter;
350         gboolean      enabled;
351
352         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
353         treepath = gtk_tree_path_new_from_string (path);
354         gtk_tree_model_get_iter (model, &iter, treepath);
355         gtk_tree_model_get (model, &iter,
356                             COL_ACCOUNT_POINTER, &account,
357                             -1);
358         gtk_tree_path_free (treepath);
359
360         enabled = mc_account_is_enabled (account);
361         mc_account_set_enabled (account, !enabled);
362
363         DEBUG ("%s account %s", enabled ? "Disabled" : "Enable",
364                 mc_account_get_display_name(account));
365
366         g_object_unref (account);
367 }
368
369 static void
370 accounts_dialog_name_editing_started_cb (GtkCellRenderer       *renderer,
371                                          GtkCellEditable       *editable,
372                                          gchar                 *path,
373                                          EmpathyAccountsDialog *dialog)
374 {
375         if (dialog->connecting_id) {
376                 g_source_remove (dialog->connecting_id);
377         }
378         DEBUG ("Editing account name started; stopping flashing");
379 }
380
381 static void
382 accounts_dialog_model_add_columns (EmpathyAccountsDialog *dialog)
383 {
384         GtkTreeView       *view;
385         GtkTreeViewColumn *column;
386         GtkCellRenderer   *cell;
387
388         view = GTK_TREE_VIEW (dialog->treeview);
389         gtk_tree_view_set_headers_visible (view, TRUE);
390
391         /* Enabled column */
392         cell = gtk_cell_renderer_toggle_new ();
393         gtk_tree_view_insert_column_with_attributes (view, -1,
394                                                      _("Enabled"),
395                                                      cell,
396                                                      "active", COL_ENABLED,
397                                                      NULL);
398         g_signal_connect (cell, "toggled",
399                           G_CALLBACK (accounts_dialog_enable_toggled_cb),
400                           dialog);
401         
402         /* Account column */
403         column = gtk_tree_view_column_new ();
404         gtk_tree_view_column_set_title (column, _("Accounts"));
405         gtk_tree_view_column_set_expand (column, TRUE);
406         gtk_tree_view_append_column (view, column);
407
408         /* Icon renderer */
409         cell = gtk_cell_renderer_pixbuf_new ();
410         gtk_tree_view_column_pack_start (column, cell, FALSE);
411         gtk_tree_view_column_set_cell_data_func (column, cell,
412                                                  (GtkTreeCellDataFunc)
413                                                  accounts_dialog_model_pixbuf_data_func,
414                                                  dialog,
415                                                  NULL);
416
417         /* Name renderer */
418         cell = gtk_cell_renderer_text_new ();
419         g_object_set (cell,
420                       "ellipsize", PANGO_ELLIPSIZE_END,
421                       "editable", TRUE,
422                       NULL);
423         gtk_tree_view_column_pack_start (column, cell, TRUE);
424         gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME);
425         g_signal_connect (cell, "edited",
426                           G_CALLBACK (accounts_dialog_name_edited_cb),
427                           dialog);
428         g_signal_connect (cell, "editing-started",
429                           G_CALLBACK (accounts_dialog_name_editing_started_cb),
430                           dialog);
431 }
432
433 static void
434 accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog)
435 {
436         GtkTreeView      *view;
437         GtkTreeModel     *model;
438         GtkTreeSelection *selection;
439         GtkTreeIter       iter;
440
441         /* select first */
442         view = GTK_TREE_VIEW (dialog->treeview);
443         model = gtk_tree_view_get_model (view);
444         
445         if (gtk_tree_model_get_iter_first (model, &iter)) {
446                 selection = gtk_tree_view_get_selection (view);
447                 gtk_tree_selection_select_iter (selection, &iter);
448         } else {
449                 accounts_dialog_update_account (dialog, NULL);
450         }
451 }
452
453 static void
454 accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn    *tree_column,
455                                         GtkCellRenderer      *cell,
456                                         GtkTreeModel         *model,
457                                         GtkTreeIter          *iter,
458                                         EmpathyAccountsDialog *dialog)
459 {
460         McAccount          *account;
461         const gchar        *icon_name;
462         GdkPixbuf          *pixbuf;
463         TpConnectionStatus  status;
464
465         gtk_tree_model_get (model, iter,
466                             COL_STATUS, &status,
467                             COL_ACCOUNT_POINTER, &account,
468                             -1);
469
470         icon_name = empathy_icon_name_from_account (account);
471         pixbuf = empathy_pixbuf_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
472
473         if (pixbuf) {
474                 if (status == TP_CONNECTION_STATUS_DISCONNECTED ||
475                     (status == TP_CONNECTION_STATUS_CONNECTING && 
476                      !dialog->connecting_show)) {
477                         GdkPixbuf *modded_pixbuf;
478
479                         modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
480                                                         TRUE,
481                                                         8,
482                                                         gdk_pixbuf_get_width (pixbuf),
483                                                         gdk_pixbuf_get_height (pixbuf));
484
485                         gdk_pixbuf_saturate_and_pixelate (pixbuf,
486                                                           modded_pixbuf,
487                                                           1.0,
488                                                           TRUE);
489                         g_object_unref (pixbuf);
490                         pixbuf = modded_pixbuf;
491                 }
492         }
493
494         g_object_set (cell,
495                       "visible", TRUE,
496                       "pixbuf", pixbuf,
497                       NULL);
498
499         g_object_unref (account);
500         if (pixbuf) {
501                 g_object_unref (pixbuf);
502         }
503 }
504
505 static gboolean
506 accounts_dialog_get_account_iter (EmpathyAccountsDialog *dialog,
507                                  McAccount             *account,
508                                  GtkTreeIter           *iter)
509 {
510         GtkTreeView      *view;
511         GtkTreeSelection *selection;
512         GtkTreeModel     *model;
513         gboolean          ok;
514         
515         /* Update the status in the model */
516         view = GTK_TREE_VIEW (dialog->treeview);
517         selection = gtk_tree_view_get_selection (view);
518         model = gtk_tree_view_get_model (view);
519
520         for (ok = gtk_tree_model_get_iter_first (model, iter);
521              ok;
522              ok = gtk_tree_model_iter_next (model, iter)) {
523                 McAccount *this_account;
524                 gboolean   equal;
525
526                 gtk_tree_model_get (model, iter,
527                                     COL_ACCOUNT_POINTER, &this_account,
528                                     -1);
529
530                 equal = empathy_account_equal (this_account, account);
531                 g_object_unref (this_account);
532
533                 if (equal) {
534                         return TRUE;
535                 }
536         }
537
538         return FALSE;
539 }
540
541 static McAccount *
542 accounts_dialog_model_get_selected (EmpathyAccountsDialog *dialog)
543 {
544         GtkTreeView      *view;
545         GtkTreeModel     *model;
546         GtkTreeSelection *selection;
547         GtkTreeIter       iter;
548         McAccount        *account;
549
550         view = GTK_TREE_VIEW (dialog->treeview);
551         selection = gtk_tree_view_get_selection (view);
552
553         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
554                 return NULL;
555         }
556
557         gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
558
559         return account;
560 }
561
562 static void
563 accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog,
564                                     McAccount             *account)
565 {
566         GtkTreeSelection *selection;
567         GtkTreeIter       iter;
568
569         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview));
570         if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
571                 gtk_tree_selection_select_iter (selection, &iter);
572         }
573 }
574
575 static gboolean
576 accounts_dialog_model_remove_selected (EmpathyAccountsDialog *dialog)
577 {
578         GtkTreeView      *view;
579         GtkTreeModel     *model;
580         GtkTreeSelection *selection;
581         GtkTreeIter       iter;
582
583         view = GTK_TREE_VIEW (dialog->treeview);
584         selection = gtk_tree_view_get_selection (view);
585
586         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
587                 return FALSE;
588         }
589
590         return gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
591 }
592
593 static void
594 accounts_dialog_model_selection_changed (GtkTreeSelection     *selection,
595                                          EmpathyAccountsDialog *dialog)
596 {
597         McAccount    *account;
598         GtkTreeModel *model;
599         GtkTreeIter   iter;
600         gboolean      is_selection;
601
602         is_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
603
604         account = accounts_dialog_model_get_selected (dialog);
605         accounts_dialog_update_account (dialog, account);
606
607         if (account) {
608                 g_object_unref (account);
609         }
610 }
611
612 static void
613 accounts_dialog_add_or_update_account (EmpathyAccountsDialog *dialog,
614                                        McAccount             *account)
615 {
616         GtkTreeModel       *model;
617         GtkTreeIter         iter;
618         TpConnectionStatus  status;
619         const gchar        *name;
620         gboolean            enabled;
621
622         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
623         status = mission_control_get_connection_status (dialog->mc, account, NULL);
624         name = mc_account_get_display_name (account);
625         enabled = mc_account_is_enabled (account);
626
627         if (!accounts_dialog_get_account_iter (dialog, account, &iter)) {
628                 DEBUG ("Adding new account");
629                 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
630         }
631
632         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
633                             COL_ENABLED, enabled,
634                             COL_NAME, name,
635                             COL_STATUS, status,
636                             COL_ACCOUNT_POINTER, account,
637                             -1);
638
639         accounts_dialog_status_changed_cb (dialog->mc,
640                                            status,
641                                            MC_PRESENCE_UNSET,
642                                            TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
643                                            mc_account_get_unique_name (account),
644                                            dialog);
645 }
646
647 static void
648 accounts_dialog_account_added_cb (McAccountMonitor     *monitor,
649                                   gchar                *unique_name,
650                                   EmpathyAccountsDialog *dialog)
651 {
652         McAccount   *account;
653         const gchar *current_name;
654         gchar       *account_param = NULL;
655
656         account = mc_account_lookup (unique_name);
657         accounts_dialog_add_or_update_account (dialog, account);
658
659         /* Change the display name to "%s (%s)" % (protocol, account).
660          *  - The protocol is the display name of the profile.
661          *  - The account should be the normalized name of the McAccount but
662          *    it's not set until first connection, so we get the "account"
663          *    parameter for CM that have it. */
664         current_name = mc_account_get_display_name (account);
665         mc_account_get_param_string (account, "account", &account_param);
666         if (!G_STR_EMPTY (account_param)) {
667                 McProfile   *profile;
668                 const gchar *profile_name;
669                 gchar       *new_name;
670
671                 profile = mc_account_get_profile (account);
672                 profile_name = mc_profile_get_display_name (profile);
673                 new_name = g_strdup_printf ("%s (%s)", profile_name,
674                                             account_param);
675
676                 DEBUG ("Setting new display name for account %s: '%s'",
677                        unique_name, new_name);
678
679                 mc_account_set_display_name (account, new_name);
680                 g_free (new_name);
681                 g_object_unref (profile);
682         } else {
683                 /* FIXME: This CM has no account parameter, what can be done? */
684         }
685         g_free (account_param);
686         g_object_unref (account);
687 }
688
689 static void
690 accounts_dialog_account_removed_cb (McAccountMonitor     *monitor,
691                                     gchar                *unique_name,
692                                     EmpathyAccountsDialog *dialog)
693 {
694         McAccount *account;
695
696         account = mc_account_lookup (unique_name);
697
698         accounts_dialog_model_set_selected (dialog, account);
699         accounts_dialog_model_remove_selected (dialog);
700
701         g_object_unref (account);
702 }
703
704 static gboolean
705 accounts_dialog_row_changed_foreach (GtkTreeModel *model,
706                                      GtkTreePath  *path,
707                                      GtkTreeIter  *iter,
708                                      gpointer      user_data)
709 {
710         gtk_tree_model_row_changed (model, path, iter);
711
712         return FALSE;
713 }
714
715 static gboolean
716 accounts_dialog_flash_connecting_cb (EmpathyAccountsDialog *dialog)
717 {
718         GtkTreeView  *view;
719         GtkTreeModel *model;
720
721         dialog->connecting_show = !dialog->connecting_show;
722
723         view = GTK_TREE_VIEW (dialog->treeview);
724         model = gtk_tree_view_get_model (view);
725
726         gtk_tree_model_foreach (model, accounts_dialog_row_changed_foreach, NULL);
727
728         return TRUE;
729 }
730
731 static gboolean
732 accounts_dialog_are_accounts_connecting (MissionControl *mc)
733 {
734         GList    *accounts, *l;
735         gboolean  found = FALSE;
736
737         /* Check if there is still accounts in CONNECTING state */
738         accounts = mc_accounts_list_by_enabled (TRUE);
739         for (l = accounts; l; l = l->next) {
740                 McAccount          *this_account = l->data;
741                 TpConnectionStatus  status;
742
743                 status = mission_control_get_connection_status (mc, this_account,
744                                                                 NULL);
745                 if (status == TP_CONNECTION_STATUS_CONNECTING) {
746                         found = TRUE;
747                         break;
748                 }
749         }
750         mc_accounts_list_free (accounts);
751
752         return found;
753 }
754
755 static void
756 accounts_dialog_status_changed_cb (MissionControl           *mc,
757                                    TpConnectionStatus        status,
758                                    McPresence                presence,
759                                    TpConnectionStatusReason  reason,
760                                    const gchar              *unique_name,
761                                    EmpathyAccountsDialog    *dialog)
762 {
763         GtkTreeModel *model;
764         GtkTreeIter   iter;
765         McAccount    *account;
766         gboolean      found = FALSE;
767         
768         /* Update the status in the model */
769         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
770         account = mc_account_lookup (unique_name);
771         if (!account) {
772                 return;
773         }
774
775         DEBUG ("Status changed for account %s: status=%d presence=%d",
776                 unique_name, status, presence);
777
778         if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
779                 GtkTreePath *path;
780
781                 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
782                                     COL_STATUS, status,
783                                     -1);
784
785                 path = gtk_tree_model_get_path (model, &iter);
786                 gtk_tree_model_row_changed (model, path, &iter);
787                 gtk_tree_path_free (path);
788         }
789         g_object_unref (account);
790
791         found = accounts_dialog_are_accounts_connecting (mc);
792
793         if (!found && dialog->connecting_id) {
794                 g_source_remove (dialog->connecting_id);
795                 dialog->connecting_id = 0;
796         }
797         if (found && !dialog->connecting_id) {
798                 dialog->connecting_id = g_timeout_add (FLASH_TIMEOUT,
799                                                        (GSourceFunc) accounts_dialog_flash_connecting_cb,
800                                                        dialog);
801         }
802 }
803
804 static void
805 accounts_dialog_account_enabled_cb (McAccountMonitor      *monitor,
806                                     gchar                 *unique_name,
807                                     EmpathyAccountsDialog *dialog)
808 {
809         GtkTreeModel *model;
810         GtkTreeIter   iter;
811         McAccount    *account;
812         gboolean      enabled;
813
814         /* Update the status in the model */
815         model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
816         account = mc_account_lookup (unique_name);
817         enabled = mc_account_is_enabled (account);
818
819         DEBUG ("Account %s is now %s",
820                 mc_account_get_display_name (account),
821                 enabled ? "enabled" : "disabled");
822
823         if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
824                 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
825                                     COL_ENABLED, enabled,
826                                     -1);
827         }
828
829         g_object_unref (account);
830 }
831
832 static void
833 accounts_dialog_account_changed_cb (McAccountMonitor       *monitor,
834                                     gchar                  *unique_name,
835                                     EmpathyAccountsDialog  *dialog)
836 {
837
838         McAccount *account;
839         McAccount *selected_account;
840
841         account = mc_account_lookup (unique_name);
842         if (!account) {
843                 return;
844         }
845
846         accounts_dialog_add_or_update_account (dialog, account);
847         selected_account = accounts_dialog_model_get_selected (dialog);
848         if (empathy_account_equal (account, selected_account)) {
849                 accounts_dialog_update_name_label (dialog, account);
850         }
851 }
852
853 static void
854 accounts_dialog_button_create_clicked_cb (GtkWidget             *button,
855                                           EmpathyAccountsDialog  *dialog)
856 {
857         McProfile *profile;
858         McAccount *account;
859         gchar     *str;
860         McProfileCapabilityFlags cap;
861
862         profile = empathy_profile_chooser_get_selected (dialog->combobox_profile);
863
864         /* Create account */
865         account = mc_account_create (profile);
866         /* To translator: %s is the protocol name */
867         str = g_strdup_printf (_("New %s account"),
868                                mc_profile_get_display_name (profile));
869         mc_account_set_display_name (account, str);
870         g_free (str);
871
872         cap = mc_profile_get_capabilities (profile);
873         if (cap & MC_PROFILE_CAPABILITY_REGISTRATION_UI) {
874                 gboolean active;
875
876                 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_register));
877                 if (!active) {
878                         mc_account_set_param_boolean (account, "register", TRUE);
879                 }
880         }
881
882         accounts_dialog_add_or_update_account (dialog, account);
883         accounts_dialog_model_set_selected (dialog, account);
884
885         g_object_unref (account);
886         g_object_unref (profile);
887 }
888
889 static void
890 accounts_dialog_button_back_clicked_cb (GtkWidget             *button,
891                                         EmpathyAccountsDialog  *dialog)
892 {
893         McAccount *account;
894
895         account = accounts_dialog_model_get_selected (dialog);
896         accounts_dialog_update_account (dialog, account);
897 }
898
899 static void
900 accounts_dialog_profile_changed_cb (GtkWidget             *widget,
901                                     EmpathyAccountsDialog *dialog)
902 {
903         McProfile *profile;
904         McProfileCapabilityFlags cap;
905
906         profile = empathy_profile_chooser_get_selected (dialog->combobox_profile);
907         cap = mc_profile_get_capabilities (profile);
908
909         if (cap & MC_PROFILE_CAPABILITY_REGISTRATION_UI) {
910                 gtk_widget_show (dialog->checkbutton_register);
911         } else {
912                 gtk_widget_hide (dialog->checkbutton_register);
913         }
914         g_object_unref (profile);
915 }
916
917 static void
918 accounts_dialog_button_add_clicked_cb (GtkWidget             *button,
919                                        EmpathyAccountsDialog *dialog)
920 {
921         GtkTreeView      *view;
922         GtkTreeSelection *selection;
923         GtkTreeModel     *model;
924
925         view = GTK_TREE_VIEW (dialog->treeview);
926         model = gtk_tree_view_get_model (view);
927         selection = gtk_tree_view_get_selection (view);
928         gtk_tree_selection_unselect_all (selection);
929
930         gtk_widget_set_sensitive (dialog->button_add, FALSE);
931         gtk_widget_set_sensitive (dialog->button_remove, FALSE);
932         gtk_widget_hide (dialog->vbox_details);
933         gtk_widget_hide (dialog->frame_no_profile);
934         gtk_widget_show (dialog->frame_new_account);
935
936         /* If we have no account, no need of a back button */
937         if (gtk_tree_model_iter_n_children (model, NULL) > 0) {
938                 gtk_widget_show (dialog->button_back);
939         } else {
940                 gtk_widget_hide (dialog->button_back);
941         }
942
943         accounts_dialog_profile_changed_cb (dialog->checkbutton_register, dialog);
944         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_register),
945                                       TRUE);
946         gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_profile), 0);
947         gtk_widget_grab_focus (dialog->combobox_profile);
948 }
949
950 static void
951 accounts_dialog_button_help_clicked_cb (GtkWidget             *button,
952                                         EmpathyAccountsDialog *dialog)
953 {
954         empathy_url_show ("ghelp:empathy?empathy-create-account");
955 }
956
957 static void
958 accounts_dialog_button_remove_clicked_cb (GtkWidget            *button,
959                                           EmpathyAccountsDialog *dialog)
960 {
961         McAccount *account;
962         GtkWidget *message_dialog;
963         gint       res;
964
965         account = accounts_dialog_model_get_selected (dialog);
966
967         if (!mc_account_is_complete (account)) {
968                 accounts_dialog_model_remove_selected (dialog);
969                 accounts_dialog_model_select_first (dialog);
970                 return;
971         }
972         message_dialog = gtk_message_dialog_new
973                 (GTK_WINDOW (dialog->window),
974                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
975                  GTK_MESSAGE_QUESTION,
976                  GTK_BUTTONS_NONE,
977                  _("You are about to remove your %s account!\n"
978                    "Are you sure you want to proceed?"),
979                  mc_account_get_display_name (account));
980
981         gtk_message_dialog_format_secondary_text
982                 (GTK_MESSAGE_DIALOG (message_dialog),
983                  _("Any associated conversations and chat rooms will NOT be "
984                    "removed if you decide to proceed.\n"
985                    "\n"
986                    "Should you decide to add the account back at a later time, "
987                    "they will still be available."));
988
989         gtk_dialog_add_button (GTK_DIALOG (message_dialog),
990                                GTK_STOCK_CANCEL, 
991                                GTK_RESPONSE_NO);
992         gtk_dialog_add_button (GTK_DIALOG (message_dialog),
993                                GTK_STOCK_REMOVE, 
994                                GTK_RESPONSE_YES);
995
996         gtk_widget_show (message_dialog);
997         res = gtk_dialog_run (GTK_DIALOG (message_dialog));
998
999         if (res == GTK_RESPONSE_YES) {
1000                 mc_account_delete (account);
1001                 accounts_dialog_model_select_first (dialog);
1002         }
1003         gtk_widget_destroy (message_dialog);
1004 }
1005
1006 static void
1007 accounts_dialog_button_import_clicked_cb (GtkWidget             *button,
1008                                           EmpathyAccountsDialog *dialog)
1009 {
1010         empathy_import_dialog_show (GTK_WINDOW (dialog->window), TRUE);
1011 }
1012
1013 static void
1014 accounts_dialog_response_cb (GtkWidget            *widget,
1015                              gint                  response,
1016                              EmpathyAccountsDialog *dialog)
1017 {
1018         if (response == GTK_RESPONSE_CLOSE) {
1019                 gtk_widget_destroy (widget);
1020         }
1021 }
1022
1023 static void
1024 accounts_dialog_destroy_cb (GtkWidget            *widget,
1025                             EmpathyAccountsDialog *dialog)
1026 {
1027         GList *accounts, *l;
1028
1029         /* Disconnect signals */
1030         g_signal_handlers_disconnect_by_func (dialog->monitor,
1031                                               accounts_dialog_account_added_cb,
1032                                               dialog);
1033         g_signal_handlers_disconnect_by_func (dialog->monitor,
1034                                               accounts_dialog_account_removed_cb,
1035                                               dialog);
1036         g_signal_handlers_disconnect_by_func (dialog->monitor,
1037                                               accounts_dialog_account_enabled_cb,
1038                                               dialog);
1039         g_signal_handlers_disconnect_by_func (dialog->monitor,
1040                                               accounts_dialog_account_changed_cb,
1041                                               dialog);
1042         empathy_disconnect_account_status_changed (dialog->token);
1043
1044         /* Delete incomplete accounts */
1045         accounts = mc_accounts_list ();
1046         for (l = accounts; l; l = l->next) {
1047                 McAccount *account;
1048
1049                 account = l->data;
1050                 if (!mc_account_is_complete (account)) {
1051                         /* FIXME: Warn the user the account is not complete
1052                          *        and is going to be removed. */
1053                         mc_account_delete (account);
1054                 }
1055
1056                 g_object_unref (account);
1057         }
1058         g_list_free (accounts);
1059
1060         if (dialog->connecting_id) {
1061                 g_source_remove (dialog->connecting_id);
1062         }
1063
1064         g_object_unref (dialog->mc);
1065         g_object_unref (dialog->monitor);
1066         
1067         g_free (dialog);
1068 }
1069
1070 GtkWidget *
1071 empathy_accounts_dialog_show (GtkWindow *parent,
1072                               McAccount *selected_account)
1073 {
1074         static EmpathyAccountsDialog *dialog = NULL;
1075         GladeXML                     *glade;
1076         gchar                        *filename;
1077         GList                        *accounts, *l;
1078         gboolean                      import_asked;
1079
1080         if (dialog) {
1081                 gtk_window_present (GTK_WINDOW (dialog->window));
1082                 return dialog->window;
1083         }
1084
1085         dialog = g_new0 (EmpathyAccountsDialog, 1);
1086
1087         filename = empathy_file_lookup ("empathy-accounts-dialog.glade",
1088                                         "src");
1089         glade = empathy_glade_get_file (filename,
1090                                        "accounts_dialog",
1091                                        NULL,
1092                                        "accounts_dialog", &dialog->window,
1093                                        "vbox_details", &dialog->vbox_details,
1094                                        "frame_no_profile", &dialog->frame_no_profile,
1095                                        "alignment_settings", &dialog->alignment_settings,
1096                                        "treeview", &dialog->treeview,
1097                                        "frame_new_account", &dialog->frame_new_account,
1098                                        "hbox_type", &dialog->hbox_type,
1099                                        "button_create", &dialog->button_create,
1100                                        "button_back", &dialog->button_back,
1101                                        "checkbutton_register", &dialog->checkbutton_register,
1102                                        "image_type", &dialog->image_type,
1103                                        "label_name", &dialog->label_name,
1104                                        "button_add", &dialog->button_add,
1105                                        "button_remove", &dialog->button_remove,
1106                                        "button_import", &dialog->button_import,
1107                                        NULL);
1108         g_free (filename);
1109
1110         empathy_glade_connect (glade,
1111                               dialog,
1112                               "accounts_dialog", "destroy", accounts_dialog_destroy_cb,
1113                               "accounts_dialog", "response", accounts_dialog_response_cb,
1114                               "button_create", "clicked", accounts_dialog_button_create_clicked_cb,
1115                               "button_back", "clicked", accounts_dialog_button_back_clicked_cb,
1116                               "button_add", "clicked", accounts_dialog_button_add_clicked_cb,
1117                               "button_remove", "clicked", accounts_dialog_button_remove_clicked_cb,
1118                               "button_import", "clicked", accounts_dialog_button_import_clicked_cb,
1119                               "button_help", "clicked", accounts_dialog_button_help_clicked_cb,
1120                               NULL);
1121
1122         g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog);
1123
1124         g_object_unref (glade);
1125
1126         /* Create profile chooser */
1127         dialog->combobox_profile = empathy_profile_chooser_new ();
1128         gtk_box_pack_end (GTK_BOX (dialog->hbox_type),
1129                           dialog->combobox_profile,
1130                           TRUE, TRUE, 0);
1131         gtk_widget_show (dialog->combobox_profile);
1132         g_signal_connect (dialog->combobox_profile, "changed",
1133                           G_CALLBACK (accounts_dialog_profile_changed_cb),
1134                           dialog);
1135
1136         /* Set up signalling */
1137         dialog->mc = empathy_mission_control_new ();
1138         dialog->monitor = mc_account_monitor_new ();
1139
1140         g_signal_connect (dialog->monitor, "account-created",
1141                           G_CALLBACK (accounts_dialog_account_added_cb),
1142                           dialog);
1143         g_signal_connect (dialog->monitor, "account-deleted",
1144                           G_CALLBACK (accounts_dialog_account_removed_cb),
1145                           dialog);
1146         g_signal_connect (dialog->monitor, "account-enabled",
1147                           G_CALLBACK (accounts_dialog_account_enabled_cb),
1148                           dialog);
1149         g_signal_connect (dialog->monitor, "account-disabled",
1150                           G_CALLBACK (accounts_dialog_account_enabled_cb),
1151                           dialog);
1152         g_signal_connect (dialog->monitor, "account-changed",
1153                           G_CALLBACK (accounts_dialog_account_changed_cb),
1154                           dialog);
1155         dialog->token = empathy_connect_to_account_status_changed (dialog->mc,
1156                                                    G_CALLBACK (accounts_dialog_status_changed_cb),
1157                                                    dialog, NULL);
1158
1159         accounts_dialog_model_setup (dialog);
1160
1161         /* Add existing accounts */
1162         accounts = mc_accounts_list ();
1163         for (l = accounts; l; l = l->next) {
1164                 accounts_dialog_add_or_update_account (dialog, l->data);
1165                 g_object_unref (l->data);
1166         }
1167         g_list_free (accounts);
1168
1169         if (selected_account) {
1170                 accounts_dialog_model_set_selected (dialog, selected_account);
1171         } else {
1172                 accounts_dialog_model_select_first (dialog);
1173         }
1174
1175         if (parent) {
1176                 gtk_window_set_transient_for (GTK_WINDOW (dialog->window),
1177                                               GTK_WINDOW (parent));
1178         }
1179
1180         gtk_widget_show (dialog->window);
1181
1182         empathy_conf_get_bool (empathy_conf_get (),
1183                                EMPATHY_PREFS_IMPORT_ASKED, &import_asked);
1184
1185         if (!import_asked) {
1186                 empathy_conf_set_bool (empathy_conf_get (),
1187                                        EMPATHY_PREFS_IMPORT_ASKED, TRUE);
1188                 empathy_import_dialog_show (GTK_WINDOW (dialog->window),
1189                                             FALSE);
1190         }
1191
1192         return dialog->window;
1193 }
1194