]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-chooser.c
Updated Basque 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  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * Authors: Martyn Russell <martyn@imendio.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
29 #include <glade/glade.h>
30
31 #include <libtelepathy/tp-conn.h>
32 #include <libmissioncontrol/mc-account-monitor.h>
33 #include <libmissioncontrol/mission-control.h>
34
35 #include <libempathy/empathy-utils.h>
36
37 #include "empathy-ui-utils.h"
38 #include "empathy-account-chooser.h"
39
40 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserPriv))
41
42 typedef struct {
43         MissionControl                 *mc;
44         McAccountMonitor               *monitor;
45         gboolean                        set_active_item;
46         gboolean                        has_all_option;
47         EmpathyAccountChooserFilterFunc filter;
48         gpointer                        filter_data;
49 } EmpathyAccountChooserPriv;
50
51 typedef struct {
52         EmpathyAccountChooser *chooser;
53         McAccount             *account;
54         gboolean               set;
55 } SetAccountData;
56
57 enum {
58         COL_ACCOUNT_IMAGE,
59         COL_ACCOUNT_TEXT,
60         COL_ACCOUNT_ENABLED, /* Usually tied to connected state */
61         COL_ACCOUNT_POINTER,
62         COL_ACCOUNT_COUNT
63 };
64
65 static void     account_chooser_finalize               (GObject                         *object);
66 static void     account_chooser_get_property           (GObject                         *object,
67                                                         guint                            param_id,
68                                                         GValue                          *value,
69                                                         GParamSpec                      *pspec);
70 static void     account_chooser_set_property           (GObject                         *object,
71                                                         guint                            param_id,
72                                                         const GValue                    *value,
73                                                         GParamSpec                      *pspec);
74 static void     account_chooser_setup                  (EmpathyAccountChooser            *chooser);
75 static void     account_chooser_account_created_cb     (McAccountMonitor                *monitor,
76                                                         const gchar                     *unique_name,
77                                                         EmpathyAccountChooser            *chooser);
78 static void     account_chooser_account_add_foreach    (McAccount                       *account,
79                                                         EmpathyAccountChooser            *chooser);
80 static void     account_chooser_account_deleted_cb     (McAccountMonitor                *monitor,
81                                                         const gchar                     *unique_name,
82                                                         EmpathyAccountChooser            *chooser);
83 static void     account_chooser_account_remove_foreach (McAccount                       *account,
84                                                         EmpathyAccountChooser            *chooser);
85 static void     account_chooser_update_iter            (EmpathyAccountChooser            *chooser,
86                                                         GtkTreeIter                     *iter,
87                                                         McAccount                       *account);
88 static void     account_chooser_status_changed_cb      (MissionControl                  *mc,
89                                                         TelepathyConnectionStatus        status,
90                                                         McPresence                       presence,
91                                                         TelepathyConnectionStatusReason  reason,
92                                                         const gchar                     *unique_name,
93                                                         EmpathyAccountChooser            *chooser);
94 static gboolean account_chooser_separator_func         (GtkTreeModel                    *model,
95                                                         GtkTreeIter                     *iter,
96                                                         EmpathyAccountChooser            *chooser);
97 static gboolean account_chooser_set_account_foreach    (GtkTreeModel                    *model,
98                                                         GtkTreePath                     *path,
99                                                         GtkTreeIter                     *iter,
100                                                         SetAccountData                  *data);
101
102 enum {
103         PROP_0,
104         PROP_HAS_ALL_OPTION,
105 };
106
107 G_DEFINE_TYPE (EmpathyAccountChooser, empathy_account_chooser, GTK_TYPE_COMBO_BOX);
108
109 static void
110 empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass)
111 {
112         GObjectClass *object_class = G_OBJECT_CLASS (klass);
113
114         object_class->finalize = account_chooser_finalize;
115         object_class->get_property = account_chooser_get_property;
116         object_class->set_property = account_chooser_set_property;
117
118         g_object_class_install_property (object_class,
119                                          PROP_HAS_ALL_OPTION,
120                                          g_param_spec_boolean ("has-all-option",
121                                                                "Has All Option",
122                                                                "Have a separate option in the list to mean ALL accounts",
123                                                                FALSE,
124                                                                G_PARAM_READWRITE));
125
126         g_type_class_add_private (object_class, sizeof (EmpathyAccountChooserPriv));
127 }
128
129 static void
130 empathy_account_chooser_init (EmpathyAccountChooser *chooser)
131 {
132         EmpathyAccountChooserPriv *priv = GET_PRIV (chooser);
133
134         priv->set_active_item = FALSE;
135         priv->filter = NULL;
136         priv->filter_data = NULL;
137 }
138
139 static void
140 account_chooser_finalize (GObject *object)
141 {
142         EmpathyAccountChooser     *chooser;
143         EmpathyAccountChooserPriv *priv;
144
145         chooser = EMPATHY_ACCOUNT_CHOOSER (object);
146         priv = GET_PRIV (object);
147
148         g_signal_handlers_disconnect_by_func (priv->monitor,
149                                               account_chooser_account_created_cb,
150                                               chooser);
151         g_signal_handlers_disconnect_by_func (priv->monitor,
152                                               account_chooser_account_deleted_cb,
153                                               chooser);
154         dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
155                                         "AccountStatusChanged",
156                                         G_CALLBACK (account_chooser_status_changed_cb),
157                                         chooser);
158         g_object_unref (priv->mc);
159         g_object_unref (priv->monitor);
160
161         G_OBJECT_CLASS (empathy_account_chooser_parent_class)->finalize (object);
162 }
163
164 static void
165 account_chooser_get_property (GObject    *object,
166                               guint       param_id,
167                               GValue     *value,
168                               GParamSpec *pspec)
169 {
170         EmpathyAccountChooserPriv *priv;
171
172         priv = GET_PRIV (object);
173
174         switch (param_id) {
175         case PROP_HAS_ALL_OPTION:
176                 g_value_set_boolean (value, priv->has_all_option);
177                 break;
178         default:
179                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
180                 break;
181         };
182 }
183
184 static void
185 account_chooser_set_property (GObject      *object,
186                               guint         param_id,
187                               const GValue *value,
188                               GParamSpec   *pspec)
189 {
190         EmpathyAccountChooserPriv *priv;
191
192         priv = GET_PRIV (object);
193
194         switch (param_id) {
195         case PROP_HAS_ALL_OPTION:
196                 empathy_account_chooser_set_has_all_option (EMPATHY_ACCOUNT_CHOOSER (object),
197                                                            g_value_get_boolean (value));
198                 break;
199         default:
200                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
201                 break;
202         };
203 }
204
205 GtkWidget *
206 empathy_account_chooser_new (void)
207 {
208         EmpathyAccountChooserPriv *priv;
209         McAccountMonitor         *monitor;
210         GtkWidget                *chooser;
211
212         monitor = mc_account_monitor_new ();
213         chooser = g_object_new (EMPATHY_TYPE_ACCOUNT_CHOOSER, NULL);
214
215         priv = GET_PRIV (chooser);
216
217         priv->mc = empathy_mission_control_new ();
218         priv->monitor = mc_account_monitor_new ();
219
220         g_signal_connect (priv->monitor, "account-created",
221                           G_CALLBACK (account_chooser_account_created_cb),
222                           chooser);
223         g_signal_connect (priv->monitor, "account-deleted",
224                           G_CALLBACK (account_chooser_account_deleted_cb),
225                           chooser);
226         dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
227                                      G_CALLBACK (account_chooser_status_changed_cb),
228                                      chooser, NULL);
229
230         account_chooser_setup (EMPATHY_ACCOUNT_CHOOSER (chooser));
231
232         return chooser;
233 }
234
235 McAccount *
236 empathy_account_chooser_get_account (EmpathyAccountChooser *chooser)
237 {
238         EmpathyAccountChooserPriv *priv;
239         McAccount                *account;
240         GtkTreeModel             *model;
241         GtkTreeIter               iter;
242
243         g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL);
244
245         priv = GET_PRIV (chooser);
246
247         model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
248         gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter);
249
250         gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
251
252         return account;
253 }
254
255 gboolean
256 empathy_account_chooser_set_account (EmpathyAccountChooser *chooser,
257                                     McAccount            *account)
258 {
259         GtkComboBox    *combobox;
260         GtkTreeModel   *model;
261         GtkTreeIter     iter;
262         SetAccountData  data;
263
264         g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
265
266         combobox = GTK_COMBO_BOX (chooser);
267         model = gtk_combo_box_get_model (combobox);
268         gtk_combo_box_get_active_iter (combobox, &iter);
269
270         data.chooser = chooser;
271         data.account = account;
272
273         gtk_tree_model_foreach (model,
274                                 (GtkTreeModelForeachFunc) account_chooser_set_account_foreach,
275                                 &data);
276
277         return data.set;
278 }
279
280 gboolean
281 empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser)
282 {
283         EmpathyAccountChooserPriv *priv;
284
285         g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
286
287         priv = GET_PRIV (chooser);
288         
289         return priv->has_all_option;
290 }
291
292 void
293 empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
294                                            gboolean              has_all_option)
295 {
296         EmpathyAccountChooserPriv *priv;
297         GtkComboBox              *combobox;
298         GtkListStore             *store;
299         GtkTreeModel             *model;
300         GtkTreeIter               iter;
301
302         g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser));
303
304         priv = GET_PRIV (chooser);
305
306         if (priv->has_all_option == has_all_option) {
307                 return;
308         }
309
310         combobox = GTK_COMBO_BOX (chooser);
311         model = gtk_combo_box_get_model (combobox);
312         store = GTK_LIST_STORE (model);
313
314         priv->has_all_option = has_all_option;
315
316         /*
317          * The first 2 options are the ALL and separator
318          */
319
320         if (has_all_option) {
321                 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), 
322                                                       (GtkTreeViewRowSeparatorFunc)
323                                                       account_chooser_separator_func,
324                                                       chooser, 
325                                                       NULL);
326
327                 gtk_list_store_prepend (store, &iter);
328                 gtk_list_store_set (store, &iter, 
329                                     COL_ACCOUNT_TEXT, NULL,
330                                     COL_ACCOUNT_ENABLED, TRUE,
331                                     COL_ACCOUNT_POINTER, NULL,
332                                     -1);
333
334                 gtk_list_store_prepend (store, &iter);
335                 gtk_list_store_set (store, &iter, 
336                                     COL_ACCOUNT_TEXT, _("All"), 
337                                     COL_ACCOUNT_ENABLED, TRUE,
338                                     COL_ACCOUNT_POINTER, NULL,
339                                     -1);
340         } else {
341                 if (gtk_tree_model_get_iter_first (model, &iter)) {
342                         if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) {
343                                 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
344                         }
345                 }
346
347                 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), 
348                                                       (GtkTreeViewRowSeparatorFunc)
349                                                       NULL,
350                                                       NULL, 
351                                                       NULL);
352         }
353
354         g_object_notify (G_OBJECT (chooser), "has-all-option");
355 }
356
357 static void
358 account_chooser_setup (EmpathyAccountChooser *chooser)
359 {
360         EmpathyAccountChooserPriv *priv;
361         GList                    *accounts;
362         GtkListStore             *store;
363         GtkCellRenderer          *renderer;
364         GtkComboBox              *combobox;
365
366         priv = GET_PRIV (chooser);
367
368         /* Set up combo box with new store */
369         combobox = GTK_COMBO_BOX (chooser);
370
371         gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox));
372
373         store = gtk_list_store_new (COL_ACCOUNT_COUNT,
374                                     G_TYPE_STRING,
375                                     G_TYPE_STRING,    /* Name */
376                                     G_TYPE_BOOLEAN,   /* Enabled */
377                                     MC_TYPE_ACCOUNT);
378
379         gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store));
380
381         renderer = gtk_cell_renderer_pixbuf_new ();
382         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE);
383         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
384                                         "icon-name", COL_ACCOUNT_IMAGE,
385                                         "sensitive", COL_ACCOUNT_ENABLED,
386                                         NULL);
387         g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
388
389         renderer = gtk_cell_renderer_text_new ();
390         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE);
391         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
392                                         "text", COL_ACCOUNT_TEXT,
393                                         "sensitive", COL_ACCOUNT_ENABLED,
394                                         NULL);
395
396         /* Populate accounts */
397         accounts = mc_accounts_list ();
398         g_list_foreach (accounts,
399                         (GFunc) account_chooser_account_add_foreach,
400                         chooser);
401
402         mc_accounts_list_free (accounts);
403         g_object_unref (store);
404 }
405
406 static void
407 account_chooser_account_created_cb (McAccountMonitor     *monitor,
408                                     const gchar          *unique_name,
409                                     EmpathyAccountChooser *chooser)
410 {
411         McAccount *account;
412
413         account = mc_account_lookup (unique_name);
414         account_chooser_account_add_foreach (account, chooser);
415         g_object_unref (account);
416 }
417
418 static void
419 account_chooser_account_add_foreach (McAccount            *account,
420                                      EmpathyAccountChooser *chooser)
421 {
422         EmpathyAccountChooserPriv *priv;
423         GtkListStore             *store;
424         GtkComboBox              *combobox;
425         GtkTreeIter               iter;
426
427         priv = GET_PRIV (chooser);
428
429         combobox = GTK_COMBO_BOX (chooser);
430         store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
431
432         gtk_list_store_append (store, &iter);
433         account_chooser_update_iter (chooser, &iter, account);
434 }
435
436 static void
437 account_chooser_account_deleted_cb (McAccountMonitor     *monitor,
438                                     const gchar          *unique_name,
439                                     EmpathyAccountChooser *chooser)
440 {
441         McAccount *account;
442
443         account = mc_account_lookup (unique_name);
444         account_chooser_account_remove_foreach (account, chooser);
445         g_object_unref (account);
446 }
447
448 static void
449 account_chooser_account_remove_foreach (McAccount            *account,
450                                         EmpathyAccountChooser *chooser)
451 {
452         /* Fixme: TODO */
453 }
454
455 static void
456 account_chooser_update_iter (EmpathyAccountChooser *chooser,
457                              GtkTreeIter           *iter,
458                              McAccount             *account)
459 {
460         EmpathyAccountChooserPriv *priv;
461         GtkListStore              *store;
462         GtkComboBox               *combobox;
463         const gchar               *icon_name;
464         gboolean                   is_enabled = TRUE;
465
466         priv = GET_PRIV (chooser);
467
468         combobox = GTK_COMBO_BOX (chooser);
469         store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
470
471         icon_name = empathy_icon_name_from_account (account);
472         if (priv->filter) {
473                 is_enabled = priv->filter (account, priv->filter_data);
474         }
475
476         gtk_list_store_set (store, iter,
477                             COL_ACCOUNT_IMAGE, icon_name,
478                             COL_ACCOUNT_TEXT, mc_account_get_display_name (account),
479                             COL_ACCOUNT_ENABLED, is_enabled,
480                             COL_ACCOUNT_POINTER, account,
481                             -1);
482
483         /* set first connected account as active account */
484         if (priv->set_active_item == FALSE && is_enabled) {
485                 priv->set_active_item = TRUE;
486                 gtk_combo_box_set_active_iter (combobox, iter);
487         }
488 }
489
490 static void
491 account_chooser_status_changed_cb (MissionControl                  *mc,
492                                    TelepathyConnectionStatus        status,
493                                    McPresence                       presence,
494                                    TelepathyConnectionStatusReason  reason,
495                                    const gchar                     *unique_name,
496                                    EmpathyAccountChooser            *chooser)
497 {
498         /* FIXME: implement */
499 }
500
501 static gboolean
502 account_chooser_separator_func (GtkTreeModel         *model,
503                                 GtkTreeIter          *iter,
504                                 EmpathyAccountChooser *chooser)
505 {
506         EmpathyAccountChooserPriv *priv;
507         gchar                    *text;
508         gboolean                  is_separator;
509
510         priv = GET_PRIV (chooser);
511         
512         if (!priv->has_all_option) {
513                 return FALSE;
514         }
515         
516         gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1);
517         is_separator = text == NULL;
518         g_free (text);
519
520         return is_separator;
521 }
522
523 static gboolean
524 account_chooser_set_account_foreach (GtkTreeModel   *model,
525                                      GtkTreePath    *path,
526                                      GtkTreeIter    *iter,
527                                      SetAccountData *data)
528 {
529         McAccount *account;
530         gboolean   equal;
531
532         gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
533
534         /* Special case so we can make it possible to select the All option */
535         if (!data->account && !account) {
536                 equal = TRUE;
537         }
538         else if ((data->account && !account) || (!data->account && account)) {
539                 equal = FALSE;
540         } else {
541                 equal = empathy_account_equal (data->account, account);
542                 g_object_unref (account);
543         }
544
545         if (equal) {
546                 GtkComboBox *combobox;
547
548                 combobox = GTK_COMBO_BOX (data->chooser);
549                 gtk_combo_box_set_active_iter (combobox, iter);
550
551                 data->set = TRUE;
552         }
553
554         return equal;
555 }
556
557 static gboolean
558 account_chooser_filter_foreach (GtkTreeModel          *model,
559                                 GtkTreePath           *path,
560                                 GtkTreeIter           *iter,
561                                 gpointer               chooser)
562 {
563         EmpathyAccountChooserPriv *priv;
564         McAccount                 *account;
565         gboolean                   is_enabled = TRUE;
566
567         priv = GET_PRIV (chooser);
568
569         gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
570
571         if (priv->filter) {
572                 is_enabled = priv->filter (account, priv->filter_data);
573         }
574
575         gtk_list_store_set (GTK_LIST_STORE (model), iter,
576                             COL_ACCOUNT_ENABLED, is_enabled,
577                             -1);
578
579         /* set first connected account as active account */
580         if (!priv->set_active_item && is_enabled) {
581                 priv->set_active_item = TRUE;
582                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (chooser), iter);
583         }
584
585         g_object_unref (account);
586
587         return FALSE;
588 }
589
590 void
591 empathy_account_chooser_set_filter (EmpathyAccountChooser           *chooser,
592                                     EmpathyAccountChooserFilterFunc  filter,
593                                     gpointer                         user_data)
594 {
595         EmpathyAccountChooserPriv *priv;
596         GtkTreeModel *model;
597
598         g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser));
599
600         priv = GET_PRIV (chooser);
601
602         priv->filter = filter;
603         priv->filter_data = user_data;
604
605         /* Refilter existing data */
606         priv->set_active_item = FALSE;
607         model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
608         gtk_tree_model_foreach (model, account_chooser_filter_foreach, chooser);
609 }
610
611 gboolean
612 empathy_account_chooser_filter_is_connected (McAccount *account,
613                                              gpointer   user_data)
614 {
615         MissionControl *mc;
616         TpConn         *tp_conn;
617
618         g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
619
620         mc = empathy_mission_control_new ();
621         tp_conn = mission_control_get_connection (mc, account, NULL);
622         g_object_unref (mc);
623
624         if (tp_conn == NULL) {
625                 return FALSE;
626         }
627
628         g_object_unref (tp_conn);
629         return TRUE;
630 }