1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2005-2007 Imendio AB
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.
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.
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.
20 * Authors: Martyn Russell <martyn@imendio.com>
27 #include <glib/gi18n.h>
29 #include <glade/glade.h>
31 #include <libtelepathy/tp-conn.h>
32 #include <libmissioncontrol/mc-account-monitor.h>
33 #include <libmissioncontrol/mission-control.h>
35 #include <libempathy/gossip-utils.h>
37 #include "gossip-ui-utils.h"
38 #include "gossip-account-chooser.h"
40 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_ACCOUNT_CHOOSER, GossipAccountChooserPriv))
44 McAccountMonitor *monitor;
46 gboolean set_active_item;
47 gboolean can_select_all;
48 gboolean has_all_option;
49 } GossipAccountChooserPriv;
52 GossipAccountChooser *chooser;
60 COL_ACCOUNT_ENABLED, /* Usually tied to connected state */
65 static void account_chooser_finalize (GObject *object);
66 static void account_chooser_get_property (GObject *object,
70 static void account_chooser_set_property (GObject *object,
74 static void account_chooser_setup (GossipAccountChooser *chooser);
75 static void account_chooser_account_created_cb (McAccountMonitor *monitor,
76 const gchar *unique_name,
77 GossipAccountChooser *chooser);
78 static void account_chooser_account_add_foreach (McAccount *account,
79 GossipAccountChooser *chooser);
80 static void account_chooser_account_deleted_cb (McAccountMonitor *monitor,
81 const gchar *unique_name,
82 GossipAccountChooser *chooser);
83 static void account_chooser_account_remove_foreach (McAccount *account,
84 GossipAccountChooser *chooser);
85 static void account_chooser_update_iter (GossipAccountChooser *chooser,
88 static void account_chooser_status_changed_cb (MissionControl *mc,
89 TelepathyConnectionStatus status,
91 TelepathyConnectionStatusReason reason,
92 const gchar *unique_name,
93 GossipAccountChooser *chooser);
94 static gboolean account_chooser_separator_func (GtkTreeModel *model,
96 GossipAccountChooser *chooser);
97 static gboolean account_chooser_set_account_foreach (GtkTreeModel *model,
100 SetAccountData *data);
101 static gboolean account_chooser_set_enabled_foreach (GtkTreeModel *model,
104 GossipAccountChooser *chooser);
112 G_DEFINE_TYPE (GossipAccountChooser, gossip_account_chooser, GTK_TYPE_COMBO_BOX);
115 gossip_account_chooser_class_init (GossipAccountChooserClass *klass)
117 GObjectClass *object_class = G_OBJECT_CLASS (klass);
119 object_class->finalize = account_chooser_finalize;
120 object_class->get_property = account_chooser_get_property;
121 object_class->set_property = account_chooser_set_property;
123 g_object_class_install_property (object_class,
125 g_param_spec_boolean ("can-select-all",
127 "Should the user be able to select offline accounts",
131 g_object_class_install_property (object_class,
133 g_param_spec_boolean ("has-all-option",
135 "Have a separate option in the list to mean ALL accounts",
139 g_type_class_add_private (object_class, sizeof (GossipAccountChooserPriv));
143 gossip_account_chooser_init (GossipAccountChooser *chooser)
148 account_chooser_finalize (GObject *object)
150 GossipAccountChooser *chooser;
151 GossipAccountChooserPriv *priv;
153 chooser = GOSSIP_ACCOUNT_CHOOSER (object);
154 priv = GET_PRIV (object);
156 g_signal_handlers_disconnect_by_func (priv->monitor,
157 account_chooser_account_created_cb,
159 g_signal_handlers_disconnect_by_func (priv->monitor,
160 account_chooser_account_deleted_cb,
162 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
163 "AccountStatusChanged",
164 G_CALLBACK (account_chooser_status_changed_cb),
166 g_object_unref (priv->mc);
167 g_object_unref (priv->monitor);
169 G_OBJECT_CLASS (gossip_account_chooser_parent_class)->finalize (object);
173 account_chooser_get_property (GObject *object,
178 GossipAccountChooserPriv *priv;
180 priv = GET_PRIV (object);
183 case PROP_CAN_SELECT_ALL:
184 g_value_set_boolean (value, priv->can_select_all);
186 case PROP_HAS_ALL_OPTION:
187 g_value_set_boolean (value, priv->has_all_option);
190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
196 account_chooser_set_property (GObject *object,
201 GossipAccountChooserPriv *priv;
203 priv = GET_PRIV (object);
206 case PROP_CAN_SELECT_ALL:
207 gossip_account_chooser_set_can_select_all (GOSSIP_ACCOUNT_CHOOSER (object),
208 g_value_get_boolean (value));
210 case PROP_HAS_ALL_OPTION:
211 gossip_account_chooser_set_has_all_option (GOSSIP_ACCOUNT_CHOOSER (object),
212 g_value_get_boolean (value));
215 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
221 gossip_account_chooser_new (void)
223 GossipAccountChooserPriv *priv;
224 McAccountMonitor *monitor;
227 monitor = mc_account_monitor_new ();
228 chooser = g_object_new (GOSSIP_TYPE_ACCOUNT_CHOOSER, NULL);
230 priv = GET_PRIV (chooser);
232 priv->mc = gossip_mission_control_new ();
233 priv->monitor = mc_account_monitor_new ();
235 g_signal_connect (priv->monitor, "account-created",
236 G_CALLBACK (account_chooser_account_created_cb),
238 g_signal_connect (priv->monitor, "account-deleted",
239 G_CALLBACK (account_chooser_account_deleted_cb),
241 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
242 G_CALLBACK (account_chooser_status_changed_cb),
245 account_chooser_setup (GOSSIP_ACCOUNT_CHOOSER (chooser));
251 gossip_account_chooser_get_account (GossipAccountChooser *chooser)
253 GossipAccountChooserPriv *priv;
258 g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), NULL);
260 priv = GET_PRIV (chooser);
262 model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
263 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter);
265 gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
271 gossip_account_chooser_set_account (GossipAccountChooser *chooser,
274 GtkComboBox *combobox;
279 g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE);
281 combobox = GTK_COMBO_BOX (chooser);
282 model = gtk_combo_box_get_model (combobox);
283 gtk_combo_box_get_active_iter (combobox, &iter);
285 data.chooser = chooser;
286 data.account = account;
288 gtk_tree_model_foreach (model,
289 (GtkTreeModelForeachFunc) account_chooser_set_account_foreach,
296 gossip_account_chooser_get_can_select_all (GossipAccountChooser *chooser)
298 GossipAccountChooserPriv *priv;
300 g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE);
302 priv = GET_PRIV (chooser);
304 return priv->can_select_all;
308 gossip_account_chooser_set_can_select_all (GossipAccountChooser *chooser,
309 gboolean can_select_all)
311 GossipAccountChooserPriv *priv;
312 GtkComboBox *combobox;
315 g_return_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser));
317 priv = GET_PRIV (chooser);
319 if (priv->can_select_all == can_select_all) {
323 combobox = GTK_COMBO_BOX (chooser);
324 model = gtk_combo_box_get_model (combobox);
326 priv->can_select_all = can_select_all;
328 gtk_tree_model_foreach (model,
329 (GtkTreeModelForeachFunc) account_chooser_set_enabled_foreach,
332 g_object_notify (G_OBJECT (chooser), "can-select-all");
336 gossip_account_chooser_get_has_all_option (GossipAccountChooser *chooser)
338 GossipAccountChooserPriv *priv;
340 g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE);
342 priv = GET_PRIV (chooser);
344 return priv->has_all_option;
348 gossip_account_chooser_set_has_all_option (GossipAccountChooser *chooser,
349 gboolean has_all_option)
351 GossipAccountChooserPriv *priv;
352 GtkComboBox *combobox;
357 g_return_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser));
359 priv = GET_PRIV (chooser);
361 if (priv->has_all_option == has_all_option) {
365 combobox = GTK_COMBO_BOX (chooser);
366 model = gtk_combo_box_get_model (combobox);
367 store = GTK_LIST_STORE (model);
369 priv->has_all_option = has_all_option;
372 * The first 2 options are the ALL and separator
375 if (has_all_option) {
376 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
377 (GtkTreeViewRowSeparatorFunc)
378 account_chooser_separator_func,
382 gtk_list_store_prepend (store, &iter);
383 gtk_list_store_set (store, &iter,
384 COL_ACCOUNT_TEXT, NULL,
385 COL_ACCOUNT_ENABLED, TRUE,
386 COL_ACCOUNT_POINTER, NULL,
389 gtk_list_store_prepend (store, &iter);
390 gtk_list_store_set (store, &iter,
391 COL_ACCOUNT_TEXT, _("All"),
392 COL_ACCOUNT_ENABLED, TRUE,
393 COL_ACCOUNT_POINTER, NULL,
396 if (gtk_tree_model_get_iter_first (model, &iter)) {
397 if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) {
398 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
402 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
403 (GtkTreeViewRowSeparatorFunc)
409 g_object_notify (G_OBJECT (chooser), "has-all-option");
413 account_chooser_setup (GossipAccountChooser *chooser)
415 GossipAccountChooserPriv *priv;
418 GtkCellRenderer *renderer;
419 GtkComboBox *combobox;
421 priv = GET_PRIV (chooser);
423 /* Set up combo box with new store */
424 combobox = GTK_COMBO_BOX (chooser);
426 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox));
428 store = gtk_list_store_new (COL_ACCOUNT_COUNT,
430 G_TYPE_STRING, /* Name */
431 G_TYPE_BOOLEAN, /* Enabled */
434 gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store));
436 renderer = gtk_cell_renderer_pixbuf_new ();
437 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE);
438 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
439 "icon-name", COL_ACCOUNT_IMAGE,
440 "sensitive", COL_ACCOUNT_ENABLED,
442 g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
444 renderer = gtk_cell_renderer_text_new ();
445 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE);
446 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
447 "text", COL_ACCOUNT_TEXT,
448 "sensitive", COL_ACCOUNT_ENABLED,
451 /* Populate accounts */
452 accounts = mc_accounts_list ();
453 g_list_foreach (accounts,
454 (GFunc) account_chooser_account_add_foreach,
457 mc_accounts_list_free (accounts);
458 g_object_unref (store);
462 account_chooser_account_created_cb (McAccountMonitor *monitor,
463 const gchar *unique_name,
464 GossipAccountChooser *chooser)
468 account = mc_account_lookup (unique_name);
469 account_chooser_account_add_foreach (account, chooser);
470 g_object_unref (account);
474 account_chooser_account_add_foreach (McAccount *account,
475 GossipAccountChooser *chooser)
477 GossipAccountChooserPriv *priv;
479 GtkComboBox *combobox;
482 priv = GET_PRIV (chooser);
484 combobox = GTK_COMBO_BOX (chooser);
485 store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
487 gtk_list_store_append (store, &iter);
488 account_chooser_update_iter (chooser, &iter, account);
492 account_chooser_account_deleted_cb (McAccountMonitor *monitor,
493 const gchar *unique_name,
494 GossipAccountChooser *chooser)
498 account = mc_account_lookup (unique_name);
499 account_chooser_account_remove_foreach (account, chooser);
500 g_object_unref (account);
504 account_chooser_account_remove_foreach (McAccount *account,
505 GossipAccountChooser *chooser)
511 account_chooser_update_iter (GossipAccountChooser *chooser,
515 GossipAccountChooserPriv *priv;
517 GtkComboBox *combobox;
519 const gchar *icon_name;
522 priv = GET_PRIV (chooser);
524 combobox = GTK_COMBO_BOX (chooser);
525 store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
527 icon_name = gossip_icon_name_from_account (account);
528 tp_conn = mission_control_get_connection (priv->mc, account, NULL);
529 is_enabled = (tp_conn != NULL || priv->can_select_all);
532 g_object_unref (tp_conn);
535 gtk_list_store_set (store, iter,
536 COL_ACCOUNT_IMAGE, icon_name,
537 COL_ACCOUNT_TEXT, mc_account_get_display_name (account),
538 COL_ACCOUNT_ENABLED, is_enabled,
539 COL_ACCOUNT_POINTER, account,
542 /* set first connected account as active account */
543 if (priv->set_active_item == FALSE && is_enabled) {
544 priv->set_active_item = TRUE;
545 gtk_combo_box_set_active_iter (combobox, iter);
550 account_chooser_status_changed_cb (MissionControl *mc,
551 TelepathyConnectionStatus status,
553 TelepathyConnectionStatusReason reason,
554 const gchar *unique_name,
555 GossipAccountChooser *chooser)
557 /* FIXME: implement */
561 account_chooser_separator_func (GtkTreeModel *model,
563 GossipAccountChooser *chooser)
565 GossipAccountChooserPriv *priv;
567 gboolean is_separator;
569 priv = GET_PRIV (chooser);
571 if (!priv->has_all_option) {
575 gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1);
576 is_separator = text == NULL;
583 account_chooser_set_account_foreach (GtkTreeModel *model,
586 SetAccountData *data)
591 gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
593 /* Special case so we can make it possible to select the All option */
594 if (!data->account && !account) {
597 equal = gossip_account_equal (data->account, account);
598 g_object_unref (account);
602 GtkComboBox *combobox;
604 combobox = GTK_COMBO_BOX (data->chooser);
605 gtk_combo_box_set_active_iter (combobox, iter);
614 account_chooser_set_enabled_foreach (GtkTreeModel *model,
617 GossipAccountChooser *chooser)
619 GossipAccountChooserPriv *priv;
622 priv = GET_PRIV (chooser);
624 gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
629 account_chooser_update_iter (chooser, iter, account);
630 g_object_unref (account);