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