]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-chooser.c
Updated Oriya Translation
[empathy.git] / libempathy-gtk / empathy-account-chooser.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., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301  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
29 #include <glib/gi18n-lib.h>
30 #include <gtk/gtk.h>
31
32 #include <libmissioncontrol/mission-control.h>
33
34 #include <libempathy/empathy-account-manager.h>
35 #include <libempathy/empathy-utils.h>
36
37 #include "empathy-ui-utils.h"
38 #include "empathy-account-chooser.h"
39
40 /**
41  * SECTION:empathy-account-chooser
42  * @title:EmpathyAccountChooser
43  * @short_description: A widget used to choose from a list of accounts
44  * @include: libempathy-gtk/empathy-account-chooser.h
45  *
46  * #EmpathyAccountChooser is a widget which extends #GtkComboBox to provide
47  * a chooser of available accounts.
48  */
49
50 /**
51  * EmpathyAccountChooser:
52  * @parent: parent object
53  *
54  * Widget which extends #GtkComboBox to provide a chooser of available accounts.
55  */
56
57 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountChooser)
58 typedef struct {
59         EmpathyAccountManager          *manager;
60         gboolean                        set_active_item;
61         gboolean                        account_manually_set;
62         gboolean                        has_all_option;
63         EmpathyAccountChooserFilterFunc filter;
64         gpointer                        filter_data;
65 } EmpathyAccountChooserPriv;
66
67 typedef struct {
68         EmpathyAccountChooser *chooser;
69         EmpathyAccount        *account;
70         gboolean               set;
71 } SetAccountData;
72
73 enum {
74         COL_ACCOUNT_IMAGE,
75         COL_ACCOUNT_TEXT,
76         COL_ACCOUNT_ENABLED, /* Usually tied to connected state */
77         COL_ACCOUNT_POINTER,
78         COL_ACCOUNT_COUNT
79 };
80
81 static void     account_chooser_finalize               (GObject                  *object);
82 static void     account_chooser_get_property           (GObject                  *object,
83                                                         guint                     param_id,
84                                                         GValue                   *value,
85                                                         GParamSpec               *pspec);
86 static void     account_chooser_set_property           (GObject                  *object,
87                                                         guint                     param_id,
88                                                         const GValue             *value,
89                                                         GParamSpec               *pspec);
90 static void     account_chooser_setup                  (EmpathyAccountChooser    *chooser);
91 static void     account_chooser_account_created_cb     (EmpathyAccountManager    *manager,
92                                                         EmpathyAccount           *account,
93                                                         EmpathyAccountChooser    *chooser);
94 static void     account_chooser_account_add_foreach    (EmpathyAccount                *account,
95                                                         EmpathyAccountChooser    *chooser);
96 static void     account_chooser_account_deleted_cb     (EmpathyAccountManager    *manager,
97                                                         EmpathyAccount           *account,
98                                                         EmpathyAccountChooser    *chooser);
99 static void     account_chooser_account_remove_foreach (EmpathyAccount                *account,
100                                                         EmpathyAccountChooser    *chooser);
101 static void     account_chooser_update_iter            (EmpathyAccountChooser    *chooser,
102                                                         GtkTreeIter              *iter);
103 static void     account_chooser_connection_changed_cb  (EmpathyAccountManager    *manager,
104                                                         EmpathyAccount                *account,
105                                                         TpConnectionStatusReason  reason,
106                                                         TpConnectionStatus        new_status,
107                                                         TpConnectionStatus        old_status,
108                                                         EmpathyAccountChooser    *chooser);
109 static gboolean account_chooser_separator_func         (GtkTreeModel             *model,
110                                                         GtkTreeIter              *iter,
111                                                         EmpathyAccountChooser    *chooser);
112 static gboolean account_chooser_set_account_foreach    (GtkTreeModel             *model,
113                                                         GtkTreePath              *path,
114                                                         GtkTreeIter              *iter,
115                                                         SetAccountData           *data);
116
117 enum {
118         PROP_0,
119         PROP_HAS_ALL_OPTION,
120 };
121
122 G_DEFINE_TYPE (EmpathyAccountChooser, empathy_account_chooser, GTK_TYPE_COMBO_BOX);
123
124 static void
125 empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass)
126 {
127         GObjectClass *object_class = G_OBJECT_CLASS (klass);
128
129         object_class->finalize = account_chooser_finalize;
130         object_class->get_property = account_chooser_get_property;
131         object_class->set_property = account_chooser_set_property;
132
133         /**
134          * EmpathyAccountChooser:has-all-option:
135          *
136          * Have an additional option in the list to mean all accounts.
137          */
138         g_object_class_install_property (object_class,
139                                          PROP_HAS_ALL_OPTION,
140                                          g_param_spec_boolean ("has-all-option",
141                                                                "Has All Option",
142                                                                "Have a separate option in the list to mean ALL accounts",
143                                                                FALSE,
144                                                                G_PARAM_READWRITE));
145
146         g_type_class_add_private (object_class, sizeof (EmpathyAccountChooserPriv));
147 }
148
149 static void
150 empathy_account_chooser_init (EmpathyAccountChooser *chooser)
151 {
152         EmpathyAccountChooserPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser,
153                 EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserPriv);
154
155         chooser->priv = priv;
156         priv->set_active_item = FALSE;
157         priv->account_manually_set = FALSE;
158         priv->filter = NULL;
159         priv->filter_data = NULL;
160
161         priv->manager = empathy_account_manager_dup_singleton ();
162
163         g_signal_connect (priv->manager, "account-created",
164                           G_CALLBACK (account_chooser_account_created_cb),
165                           chooser);
166         g_signal_connect (priv->manager, "account-deleted",
167                           G_CALLBACK (account_chooser_account_deleted_cb),
168                           chooser);
169         g_signal_connect (priv->manager, "account-connection-changed",
170                           G_CALLBACK (account_chooser_connection_changed_cb),
171                           chooser);
172
173         account_chooser_setup (EMPATHY_ACCOUNT_CHOOSER (chooser));
174 }
175
176 static void
177 account_chooser_finalize (GObject *object)
178 {
179         EmpathyAccountChooserPriv *priv = GET_PRIV (object);
180
181         g_signal_handlers_disconnect_by_func (priv->manager,
182                                               account_chooser_connection_changed_cb,
183                                               object);
184         g_signal_handlers_disconnect_by_func (priv->manager,
185                                               account_chooser_account_created_cb,
186                                               object);
187         g_signal_handlers_disconnect_by_func (priv->manager,
188                                               account_chooser_account_deleted_cb,
189                                               object);
190         g_object_unref (priv->manager);
191
192         G_OBJECT_CLASS (empathy_account_chooser_parent_class)->finalize (object);
193 }
194
195 static void
196 account_chooser_get_property (GObject    *object,
197                               guint       param_id,
198                               GValue     *value,
199                               GParamSpec *pspec)
200 {
201         EmpathyAccountChooserPriv *priv;
202
203         priv = GET_PRIV (object);
204
205         switch (param_id) {
206         case PROP_HAS_ALL_OPTION:
207                 g_value_set_boolean (value, priv->has_all_option);
208                 break;
209         default:
210                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
211                 break;
212         };
213 }
214
215 static void
216 account_chooser_set_property (GObject      *object,
217                               guint         param_id,
218                               const GValue *value,
219                               GParamSpec   *pspec)
220 {
221         EmpathyAccountChooserPriv *priv;
222
223         priv = GET_PRIV (object);
224
225         switch (param_id) {
226         case PROP_HAS_ALL_OPTION:
227                 empathy_account_chooser_set_has_all_option (EMPATHY_ACCOUNT_CHOOSER (object),
228                                                            g_value_get_boolean (value));
229                 break;
230         default:
231                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
232                 break;
233         };
234 }
235
236 /**
237  * empathy_account_chooser_new:
238  *
239  * Creates a new #EmpathyAccountChooser.
240  *
241  * Return value: A new #EmpathyAccountChooser
242  */
243 GtkWidget *
244 empathy_account_chooser_new (void)
245 {
246         GtkWidget                *chooser;
247
248         chooser = g_object_new (EMPATHY_TYPE_ACCOUNT_CHOOSER, NULL);
249
250         return chooser;
251 }
252
253 /**
254  * empathy_account_chooser_dup_account:
255  * @chooser: an #EmpathyAccountChooser
256  *
257  * Returns the account which is currently selected in the chooser or %NULL
258  * if there is no account selected. The #EmpathyAccount returned should be
259  * unrefed with g_object_unref() when finished with.
260  *
261  * Return value: a new ref to the #EmpathyAccount currently selected, or %NULL.
262  */
263 EmpathyAccount *
264 empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser)
265 {
266         EmpathyAccountChooserPriv *priv;
267         EmpathyAccount           *account;
268         GtkTreeModel             *model;
269         GtkTreeIter               iter;
270
271         g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL);
272
273         priv = GET_PRIV (chooser);
274
275         model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
276         if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter)) {
277                 return NULL;
278         }
279
280         gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
281
282         return account;
283 }
284
285 /**
286  * empathy_account_chooser_get_connection:
287  * @chooser: an #EmpathyAccountChooser
288  *
289  * Returns a borrowed reference to the #TpConnection associated with the
290  * account currently selected. The caller must reference the returned object with
291  * g_object_ref() if it will be kept
292  *
293  * Return value: a borrowed reference to the #TpConnection associated with the
294  * account curently selected.
295  */
296 TpConnection *
297 empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser)
298 {
299         EmpathyAccountChooserPriv *priv;
300         EmpathyAccount            *account;
301         TpConnection              *connection;
302
303         g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL);
304
305         priv = GET_PRIV (chooser);
306
307         account = empathy_account_chooser_dup_account (chooser);
308         connection = empathy_account_get_connection (account);
309         g_object_unref (account);
310
311         return connection;
312 }
313
314 /**
315  * empathy_account_chooser_set_account:
316  * @chooser: an #EmpathyAccountChooser
317  * @account: an #EmpathyAccount
318  *
319  * Sets the currently selected account to @account, if it exists in the list.
320  *
321  * Return value: whether the chooser was set to @account.
322  */
323 gboolean
324 empathy_account_chooser_set_account (EmpathyAccountChooser *chooser,
325                                      EmpathyAccount *account)
326 {
327         EmpathyAccountChooserPriv *priv;
328         GtkComboBox    *combobox;
329         GtkTreeModel   *model;
330         GtkTreeIter     iter;
331         SetAccountData  data;
332
333         g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
334
335         priv = GET_PRIV (chooser);
336
337         combobox = GTK_COMBO_BOX (chooser);
338         model = gtk_combo_box_get_model (combobox);
339         gtk_combo_box_get_active_iter (combobox, &iter);
340
341         data.chooser = chooser;
342         data.account = account;
343
344         gtk_tree_model_foreach (model,
345                                 (GtkTreeModelForeachFunc) account_chooser_set_account_foreach,
346                                 &data);
347
348         priv->account_manually_set = data.set;
349
350         return data.set;
351 }
352
353 /**
354  * empathy_account_chooser_get_has_all_option:
355  * @chooser: an #EmpathyAccountChooser
356  *
357  * Returns whether @chooser has the #EmpathyAccountChooser:has-all-option property
358  * set to true.
359  *
360  * Return value: whether @chooser has the #EmpathyAccountChooser:has-all-option property
361  * enabled.
362  */
363 gboolean
364 empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser)
365 {
366         EmpathyAccountChooserPriv *priv;
367
368         g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
369
370         priv = GET_PRIV (chooser);
371
372         return priv->has_all_option;
373 }
374
375 /**
376  * empathy_account_chooser_set_has_all_option:
377  * @chooser: an #EmpathyAccountChooser
378  * @has_all_option: a new value for the #EmpathyAccountChooser:has-all-option property
379  *
380  * Sets the #EmpathyAccountChooser:has-all-option property.
381  */
382 void
383 empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
384                                            gboolean              has_all_option)
385 {
386         EmpathyAccountChooserPriv *priv;
387         GtkComboBox              *combobox;
388         GtkListStore             *store;
389         GtkTreeModel             *model;
390         GtkTreeIter               iter;
391
392         g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser));
393
394         priv = GET_PRIV (chooser);
395
396         if (priv->has_all_option == has_all_option) {
397                 return;
398         }
399
400         combobox = GTK_COMBO_BOX (chooser);
401         model = gtk_combo_box_get_model (combobox);
402         store = GTK_LIST_STORE (model);
403
404         priv->has_all_option = has_all_option;
405
406         /*
407          * The first 2 options are the ALL and separator
408          */
409
410         if (has_all_option) {
411                 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
412                                                       (GtkTreeViewRowSeparatorFunc)
413                                                       account_chooser_separator_func,
414                                                       chooser,
415                                                       NULL);
416
417                 gtk_list_store_prepend (store, &iter);
418                 gtk_list_store_set (store, &iter,
419                                     COL_ACCOUNT_TEXT, NULL,
420                                     COL_ACCOUNT_ENABLED, TRUE,
421                                     COL_ACCOUNT_POINTER, NULL,
422                                     -1);
423
424                 gtk_list_store_prepend (store, &iter);
425                 gtk_list_store_set (store, &iter,
426                                     COL_ACCOUNT_TEXT, _("All"),
427                                     COL_ACCOUNT_ENABLED, TRUE,
428                                     COL_ACCOUNT_POINTER, NULL,
429                                     -1);
430         } else {
431                 if (gtk_tree_model_get_iter_first (model, &iter)) {
432                         if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) {
433                                 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
434                         }
435                 }
436
437                 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
438                                                       (GtkTreeViewRowSeparatorFunc)
439                                                       NULL,
440                                                       NULL,
441                                                       NULL);
442         }
443
444         g_object_notify (G_OBJECT (chooser), "has-all-option");
445 }
446
447 static void
448 account_chooser_setup (EmpathyAccountChooser *chooser)
449 {
450         EmpathyAccountChooserPriv *priv;
451         GList                    *accounts;
452         GtkListStore             *store;
453         GtkCellRenderer          *renderer;
454         GtkComboBox              *combobox;
455
456         priv = GET_PRIV (chooser);
457
458         /* Set up combo box with new store */
459         combobox = GTK_COMBO_BOX (chooser);
460
461         gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox));
462
463         store = gtk_list_store_new (COL_ACCOUNT_COUNT,
464                                     G_TYPE_STRING,    /* Image */
465                                     G_TYPE_STRING,    /* Name */
466                                     G_TYPE_BOOLEAN,   /* Enabled */
467                                     EMPATHY_TYPE_ACCOUNT);
468
469         gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store));
470
471         renderer = gtk_cell_renderer_pixbuf_new ();
472         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE);
473         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
474                                         "icon-name", COL_ACCOUNT_IMAGE,
475                                         "sensitive", COL_ACCOUNT_ENABLED,
476                                         NULL);
477         g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
478
479         renderer = gtk_cell_renderer_text_new ();
480         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE);
481         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
482                                         "text", COL_ACCOUNT_TEXT,
483                                         "sensitive", COL_ACCOUNT_ENABLED,
484                                         NULL);
485
486         /* Populate accounts */
487         accounts = empathy_account_manager_dup_accounts (priv->manager);
488         g_list_foreach (accounts,
489                         (GFunc) account_chooser_account_add_foreach,
490                         chooser);
491
492         g_list_free (accounts);
493         g_object_unref (store);
494 }
495
496 static void
497 account_chooser_account_created_cb (EmpathyAccountManager *manager,
498                                     EmpathyAccount        *account,
499                                     EmpathyAccountChooser *chooser)
500 {
501         account_chooser_account_add_foreach (account, chooser);
502 }
503
504 static void
505 account_chooser_account_add_foreach (EmpathyAccount        *account,
506                                      EmpathyAccountChooser *chooser)
507 {
508         GtkListStore *store;
509         GtkComboBox  *combobox;
510         GtkTreeIter   iter;
511         gint          position;
512
513         combobox = GTK_COMBO_BOX (chooser);
514         store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
515
516         position = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
517         gtk_list_store_insert_with_values (store, &iter, position,
518                                            COL_ACCOUNT_POINTER, account,
519                                            -1);
520         account_chooser_update_iter (chooser, &iter);
521         /* We got a reffed account and it was reffed by the liststore as well */
522         g_object_unref (account);
523 }
524
525 static void
526 account_chooser_account_deleted_cb (EmpathyAccountManager *manager,
527                                     EmpathyAccount        *account,
528                                     EmpathyAccountChooser *chooser)
529 {
530         account_chooser_account_remove_foreach (account, chooser);
531 }
532
533 typedef struct {
534         EmpathyAccount   *account;
535         GtkTreeIter *iter;
536         gboolean     found;
537 } FindAccountData;
538
539 static gboolean
540 account_chooser_find_account_foreach (GtkTreeModel *model,
541                                       GtkTreePath  *path,
542                                       GtkTreeIter  *iter,
543                                       gpointer      user_data)
544 {
545         FindAccountData *data = user_data;
546         EmpathyAccount  *account;
547
548         gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
549
550         if (empathy_account_equal (account, data->account)) {
551                 data->found = TRUE;
552                 *(data->iter) = *iter;
553                 g_object_unref (account);
554
555                 return TRUE;
556         }
557
558         g_object_unref (account);
559
560         return FALSE;
561 }
562
563 static gboolean
564 account_chooser_find_account (EmpathyAccountChooser *chooser,
565                               EmpathyAccount        *account,
566                               GtkTreeIter           *iter)
567 {
568         GtkListStore    *store;
569         GtkComboBox     *combobox;
570         FindAccountData  data;
571
572         combobox = GTK_COMBO_BOX (chooser);
573         store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
574
575         data.account = account;
576         data.iter = iter;
577         gtk_tree_model_foreach (GTK_TREE_MODEL (store),
578                                 account_chooser_find_account_foreach,
579                                 &data);
580
581         return data.found;
582 }
583
584 static void
585 account_chooser_account_remove_foreach (EmpathyAccount        *account,
586                                         EmpathyAccountChooser *chooser)
587 {
588         GtkListStore *store;
589         GtkComboBox  *combobox;
590         GtkTreeIter   iter;
591
592         combobox = GTK_COMBO_BOX (chooser);
593         store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
594
595         if (account_chooser_find_account (chooser, account, &iter)) {
596                 gtk_list_store_remove (store, &iter);
597         }
598 }
599
600 static void
601 account_chooser_update_iter (EmpathyAccountChooser *chooser,
602                              GtkTreeIter           *iter)
603 {
604         EmpathyAccountChooserPriv *priv;
605         GtkListStore              *store;
606         GtkComboBox               *combobox;
607         EmpathyAccount            *account;
608         const gchar               *icon_name;
609         gboolean                   is_enabled = TRUE;
610
611         priv = GET_PRIV (chooser);
612
613         combobox = GTK_COMBO_BOX (chooser);
614         store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
615
616         gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
617                             COL_ACCOUNT_POINTER, &account,
618                             -1);
619
620         icon_name = empathy_icon_name_from_account (account);
621         if (priv->filter) {
622                 is_enabled = priv->filter (account, priv->filter_data);
623         }
624
625         gtk_list_store_set (store, iter,
626                             COL_ACCOUNT_IMAGE, icon_name,
627                             COL_ACCOUNT_TEXT, empathy_account_get_display_name (account),
628                             COL_ACCOUNT_ENABLED, is_enabled,
629                             -1);
630
631         /* set first connected account as active account */
632         if (priv->account_manually_set == FALSE &&
633             priv->set_active_item == FALSE && is_enabled) {
634                 priv->set_active_item = TRUE;
635                 gtk_combo_box_set_active_iter (combobox, iter);
636         }
637
638         g_object_unref (account);
639 }
640
641 static void
642 account_chooser_connection_changed_cb (EmpathyAccountManager   *manager,
643                                        EmpathyAccount          *account,
644                                        TpConnectionStatusReason reason,
645                                        TpConnectionStatus       new_status,
646                                        TpConnectionStatus       old_status,
647                                        EmpathyAccountChooser   *chooser)
648 {
649         GtkTreeIter iter;
650
651         if (account_chooser_find_account (chooser, account, &iter)) {
652                 account_chooser_update_iter (chooser, &iter);
653         }
654 }
655
656 static gboolean
657 account_chooser_separator_func (GtkTreeModel         *model,
658                                 GtkTreeIter          *iter,
659                                 EmpathyAccountChooser *chooser)
660 {
661         EmpathyAccountChooserPriv *priv;
662         gchar                    *text;
663         gboolean                  is_separator;
664
665         priv = GET_PRIV (chooser);
666
667         if (!priv->has_all_option) {
668                 return FALSE;
669         }
670
671         gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1);
672         is_separator = text == NULL;
673         g_free (text);
674
675         return is_separator;
676 }
677
678 static gboolean
679 account_chooser_set_account_foreach (GtkTreeModel   *model,
680                                      GtkTreePath    *path,
681                                      GtkTreeIter    *iter,
682                                      SetAccountData *data)
683 {
684         EmpathyAccount *account;
685         gboolean   equal;
686
687         gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
688
689         /* Special case so we can make it possible to select the All option */
690         if ((data->account == NULL) != (account == NULL)) {
691                 equal = FALSE;
692         }
693         else if (data->account == account) {
694                 equal = TRUE;
695         } else {
696                 equal = empathy_account_equal (data->account, account);
697         }
698
699         if (account) {
700                 g_object_unref (account);
701         }
702
703         if (equal) {
704                 GtkComboBox *combobox;
705
706                 combobox = GTK_COMBO_BOX (data->chooser);
707                 gtk_combo_box_set_active_iter (combobox, iter);
708
709                 data->set = TRUE;
710         }
711
712         return equal;
713 }
714
715 static gboolean
716 account_chooser_filter_foreach (GtkTreeModel *model,
717                                 GtkTreePath  *path,
718                                 GtkTreeIter  *iter,
719                                 gpointer      chooser)
720 {
721         account_chooser_update_iter (chooser, iter);
722         return FALSE;
723 }
724
725 /**
726  * empathy_account_chooser_set_filter:
727  * @chooser: an #EmpathyAccountChooser
728  * @filter: a filter
729  * @user_data: data to pass to @filter, or %NULL
730  *
731  * Sets a filter on the @chooser so only accounts that are %TRUE in the eyes
732  * of the filter are visible in the @chooser.
733  */
734 void
735 empathy_account_chooser_set_filter (EmpathyAccountChooser           *chooser,
736                                     EmpathyAccountChooserFilterFunc  filter,
737                                     gpointer                         user_data)
738 {
739         EmpathyAccountChooserPriv *priv;
740         GtkTreeModel *model;
741
742         g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser));
743
744         priv = GET_PRIV (chooser);
745
746         priv->filter = filter;
747         priv->filter_data = user_data;
748
749         /* Refilter existing data */
750         priv->set_active_item = FALSE;
751         model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
752         gtk_tree_model_foreach (model, account_chooser_filter_foreach, chooser);
753 }
754
755 /**
756  * EmpathyAccountChooserFilterFunc:
757  * @account: an #EmpathyAccount
758  * @user_data: user data, or %NULL
759  *
760  * A function which decides whether the account indicated by @account
761  * is visible.
762  *
763  * Return value: whether the account indicated by @account is visible.
764  */
765
766 /**
767  * empathy_account_chooser_filter_is_connected:
768  * @account: an #EmpathyAccount
769  * @user_data: user data or %NULL
770  *
771  * A useful #EmpathyAccountChooserFilterFunc that one could pass into
772  * empathy_account_chooser_set_filter() and only show connected accounts.
773  *
774  * Return value: Whether @account is connected
775  */
776 gboolean
777 empathy_account_chooser_filter_is_connected (EmpathyAccount *account,
778                                              gpointer   user_data)
779 {
780         TpConnectionStatus  status;
781
782         g_object_get (account, "status", &status, NULL);
783
784         return status == TP_CONNECTION_STATUS_CONNECTED;
785 }
786