aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy-gtk/gossip-account-chooser.c
diff options
context:
space:
mode:
Diffstat (limited to 'libempathy-gtk/gossip-account-chooser.c')
-rw-r--r--libempathy-gtk/gossip-account-chooser.c633
1 files changed, 633 insertions, 0 deletions
diff --git a/libempathy-gtk/gossip-account-chooser.c b/libempathy-gtk/gossip-account-chooser.c
new file mode 100644
index 000000000..8d3439f7e
--- /dev/null
+++ b/libempathy-gtk/gossip-account-chooser.c
@@ -0,0 +1,633 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Martyn Russell <martyn@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libtelepathy/tp-conn.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/gossip-utils.h>
+
+#include "gossip-ui-utils.h"
+#include "gossip-account-chooser.h"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_ACCOUNT_CHOOSER, GossipAccountChooserPriv))
+
+typedef struct {
+ MissionControl *mc;
+ McAccountMonitor *monitor;
+
+ gboolean set_active_item;
+ gboolean can_select_all;
+ gboolean has_all_option;
+} GossipAccountChooserPriv;
+
+typedef struct {
+ GossipAccountChooser *chooser;
+ McAccount *account;
+ gboolean set;
+} SetAccountData;
+
+enum {
+ COL_ACCOUNT_IMAGE,
+ COL_ACCOUNT_TEXT,
+ COL_ACCOUNT_ENABLED, /* Usually tied to connected state */
+ COL_ACCOUNT_POINTER,
+ COL_ACCOUNT_COUNT
+};
+
+static void account_chooser_finalize (GObject *object);
+static void account_chooser_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void account_chooser_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void account_chooser_setup (GossipAccountChooser *chooser);
+static void account_chooser_account_created_cb (McAccountMonitor *monitor,
+ const gchar *unique_name,
+ GossipAccountChooser *chooser);
+static void account_chooser_account_add_foreach (McAccount *account,
+ GossipAccountChooser *chooser);
+static void account_chooser_account_deleted_cb (McAccountMonitor *monitor,
+ const gchar *unique_name,
+ GossipAccountChooser *chooser);
+static void account_chooser_account_remove_foreach (McAccount *account,
+ GossipAccountChooser *chooser);
+static void account_chooser_update_iter (GossipAccountChooser *chooser,
+ GtkTreeIter *iter,
+ McAccount *account);
+static void account_chooser_status_changed_cb (MissionControl *mc,
+ TelepathyConnectionStatus status,
+ McPresence presence,
+ TelepathyConnectionStatusReason reason,
+ const gchar *unique_name,
+ GossipAccountChooser *chooser);
+static gboolean account_chooser_separator_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GossipAccountChooser *chooser);
+static gboolean account_chooser_set_account_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ SetAccountData *data);
+static gboolean account_chooser_set_enabled_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GossipAccountChooser *chooser);
+
+enum {
+ PROP_0,
+ PROP_CAN_SELECT_ALL,
+ PROP_HAS_ALL_OPTION,
+};
+
+G_DEFINE_TYPE (GossipAccountChooser, gossip_account_chooser, GTK_TYPE_COMBO_BOX);
+
+static void
+gossip_account_chooser_class_init (GossipAccountChooserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = account_chooser_finalize;
+ object_class->get_property = account_chooser_get_property;
+ object_class->set_property = account_chooser_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_CAN_SELECT_ALL,
+ g_param_spec_boolean ("can-select-all",
+ "Can Select All",
+ "Should the user be able to select offline accounts",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_HAS_ALL_OPTION,
+ g_param_spec_boolean ("has-all-option",
+ "Has All Option",
+ "Have a separate option in the list to mean ALL accounts",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (GossipAccountChooserPriv));
+}
+
+static void
+gossip_account_chooser_init (GossipAccountChooser *chooser)
+{
+}
+
+static void
+account_chooser_finalize (GObject *object)
+{
+ GossipAccountChooser *chooser;
+ GossipAccountChooserPriv *priv;
+
+ chooser = GOSSIP_ACCOUNT_CHOOSER (object);
+ priv = GET_PRIV (object);
+
+ g_signal_handlers_disconnect_by_func (priv->monitor,
+ account_chooser_account_created_cb,
+ chooser);
+ g_signal_handlers_disconnect_by_func (priv->monitor,
+ account_chooser_account_deleted_cb,
+ chooser);
+ dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
+ "AccountStatusChanged",
+ G_CALLBACK (account_chooser_status_changed_cb),
+ chooser);
+ g_object_unref (priv->mc);
+ g_object_unref (priv->monitor);
+
+ G_OBJECT_CLASS (gossip_account_chooser_parent_class)->finalize (object);
+}
+
+static void
+account_chooser_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GossipAccountChooserPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_CAN_SELECT_ALL:
+ g_value_set_boolean (value, priv->can_select_all);
+ break;
+ case PROP_HAS_ALL_OPTION:
+ g_value_set_boolean (value, priv->has_all_option);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+static void
+account_chooser_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GossipAccountChooserPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_CAN_SELECT_ALL:
+ gossip_account_chooser_set_can_select_all (GOSSIP_ACCOUNT_CHOOSER (object),
+ g_value_get_boolean (value));
+ break;
+ case PROP_HAS_ALL_OPTION:
+ gossip_account_chooser_set_has_all_option (GOSSIP_ACCOUNT_CHOOSER (object),
+ g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+GtkWidget *
+gossip_account_chooser_new (void)
+{
+ GossipAccountChooserPriv *priv;
+ McAccountMonitor *monitor;
+ GtkWidget *chooser;
+
+ monitor = mc_account_monitor_new ();
+ chooser = g_object_new (GOSSIP_TYPE_ACCOUNT_CHOOSER, NULL);
+
+ priv = GET_PRIV (chooser);
+
+ priv->mc = gossip_mission_control_new ();
+ priv->monitor = mc_account_monitor_new ();
+
+ g_signal_connect (priv->monitor, "account-created",
+ G_CALLBACK (account_chooser_account_created_cb),
+ chooser);
+ g_signal_connect (priv->monitor, "account-deleted",
+ G_CALLBACK (account_chooser_account_deleted_cb),
+ chooser);
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
+ G_CALLBACK (account_chooser_status_changed_cb),
+ chooser, NULL);
+
+ account_chooser_setup (GOSSIP_ACCOUNT_CHOOSER (chooser));
+
+ return chooser;
+}
+
+McAccount *
+gossip_account_chooser_get_account (GossipAccountChooser *chooser)
+{
+ GossipAccountChooserPriv *priv;
+ McAccount *account;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), NULL);
+
+ priv = GET_PRIV (chooser);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter);
+
+ gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
+
+ return account;
+}
+
+gboolean
+gossip_account_chooser_set_account (GossipAccountChooser *chooser,
+ McAccount *account)
+{
+ GtkComboBox *combobox;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ SetAccountData data;
+
+ g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE);
+
+ combobox = GTK_COMBO_BOX (chooser);
+ model = gtk_combo_box_get_model (combobox);
+ gtk_combo_box_get_active_iter (combobox, &iter);
+
+ data.chooser = chooser;
+ data.account = account;
+
+ gtk_tree_model_foreach (model,
+ (GtkTreeModelForeachFunc) account_chooser_set_account_foreach,
+ &data);
+
+ return data.set;
+}
+
+gboolean
+gossip_account_chooser_get_can_select_all (GossipAccountChooser *chooser)
+{
+ GossipAccountChooserPriv *priv;
+
+ g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE);
+
+ priv = GET_PRIV (chooser);
+
+ return priv->can_select_all;
+}
+
+void
+gossip_account_chooser_set_can_select_all (GossipAccountChooser *chooser,
+ gboolean can_select_all)
+{
+ GossipAccountChooserPriv *priv;
+ GtkComboBox *combobox;
+ GtkTreeModel *model;
+
+ g_return_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser));
+
+ priv = GET_PRIV (chooser);
+
+ if (priv->can_select_all == can_select_all) {
+ return;
+ }
+
+ combobox = GTK_COMBO_BOX (chooser);
+ model = gtk_combo_box_get_model (combobox);
+
+ priv->can_select_all = can_select_all;
+
+ gtk_tree_model_foreach (model,
+ (GtkTreeModelForeachFunc) account_chooser_set_enabled_foreach,
+ chooser);
+
+ g_object_notify (G_OBJECT (chooser), "can-select-all");
+}
+
+gboolean
+gossip_account_chooser_get_has_all_option (GossipAccountChooser *chooser)
+{
+ GossipAccountChooserPriv *priv;
+
+ g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE);
+
+ priv = GET_PRIV (chooser);
+
+ return priv->has_all_option;
+}
+
+void
+gossip_account_chooser_set_has_all_option (GossipAccountChooser *chooser,
+ gboolean has_all_option)
+{
+ GossipAccountChooserPriv *priv;
+ GtkComboBox *combobox;
+ GtkListStore *store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser));
+
+ priv = GET_PRIV (chooser);
+
+ if (priv->has_all_option == has_all_option) {
+ return;
+ }
+
+ combobox = GTK_COMBO_BOX (chooser);
+ model = gtk_combo_box_get_model (combobox);
+ store = GTK_LIST_STORE (model);
+
+ priv->has_all_option = has_all_option;
+
+ /*
+ * The first 2 options are the ALL and separator
+ */
+
+ if (has_all_option) {
+ gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
+ (GtkTreeViewRowSeparatorFunc)
+ account_chooser_separator_func,
+ chooser,
+ NULL);
+
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_ACCOUNT_TEXT, NULL,
+ COL_ACCOUNT_ENABLED, TRUE,
+ COL_ACCOUNT_POINTER, NULL,
+ -1);
+
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_ACCOUNT_TEXT, _("All"),
+ COL_ACCOUNT_ENABLED, TRUE,
+ COL_ACCOUNT_POINTER, NULL,
+ -1);
+ } else {
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) {
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ }
+ }
+
+ gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
+ (GtkTreeViewRowSeparatorFunc)
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ g_object_notify (G_OBJECT (chooser), "has-all-option");
+}
+
+static void
+account_chooser_setup (GossipAccountChooser *chooser)
+{
+ GossipAccountChooserPriv *priv;
+ GList *accounts;
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+ GtkComboBox *combobox;
+
+ priv = GET_PRIV (chooser);
+
+ /* Set up combo box with new store */
+ combobox = GTK_COMBO_BOX (chooser);
+
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox));
+
+ store = gtk_list_store_new (COL_ACCOUNT_COUNT,
+ G_TYPE_STRING,
+ G_TYPE_STRING, /* Name */
+ G_TYPE_BOOLEAN, /* Enabled */
+ MC_TYPE_ACCOUNT);
+
+ gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
+ "icon-name", COL_ACCOUNT_IMAGE,
+ "sensitive", COL_ACCOUNT_ENABLED,
+ NULL);
+ g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
+ "text", COL_ACCOUNT_TEXT,
+ "sensitive", COL_ACCOUNT_ENABLED,
+ NULL);
+
+ /* Populate accounts */
+ accounts = mc_accounts_list ();
+ g_list_foreach (accounts,
+ (GFunc) account_chooser_account_add_foreach,
+ chooser);
+
+ mc_accounts_list_free (accounts);
+ g_object_unref (store);
+}
+
+static void
+account_chooser_account_created_cb (McAccountMonitor *monitor,
+ const gchar *unique_name,
+ GossipAccountChooser *chooser)
+{
+ McAccount *account;
+
+ account = mc_account_lookup (unique_name);
+ account_chooser_account_add_foreach (account, chooser);
+ g_object_unref (account);
+}
+
+static void
+account_chooser_account_add_foreach (McAccount *account,
+ GossipAccountChooser *chooser)
+{
+ GossipAccountChooserPriv *priv;
+ GtkListStore *store;
+ GtkComboBox *combobox;
+ GtkTreeIter iter;
+
+ priv = GET_PRIV (chooser);
+
+ combobox = GTK_COMBO_BOX (chooser);
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+ gtk_list_store_append (store, &iter);
+ account_chooser_update_iter (chooser, &iter, account);
+}
+
+static void
+account_chooser_account_deleted_cb (McAccountMonitor *monitor,
+ const gchar *unique_name,
+ GossipAccountChooser *chooser)
+{
+ McAccount *account;
+
+ account = mc_account_lookup (unique_name);
+ account_chooser_account_remove_foreach (account, chooser);
+ g_object_unref (account);
+}
+
+static void
+account_chooser_account_remove_foreach (McAccount *account,
+ GossipAccountChooser *chooser)
+{
+ /* Fixme: TODO */
+}
+
+static void
+account_chooser_update_iter (GossipAccountChooser *chooser,
+ GtkTreeIter *iter,
+ McAccount *account)
+{
+ GossipAccountChooserPriv *priv;
+ GtkListStore *store;
+ GtkComboBox *combobox;
+ TpConn *tp_conn;
+ const gchar *icon_name;
+ gboolean is_enabled;
+
+ priv = GET_PRIV (chooser);
+
+ combobox = GTK_COMBO_BOX (chooser);
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+ icon_name = gossip_icon_name_from_account (account);
+ tp_conn = mission_control_get_connection (priv->mc, account, NULL);
+ is_enabled = (tp_conn != NULL || priv->can_select_all);
+
+ if (tp_conn) {
+ g_object_unref (tp_conn);
+ }
+
+ gtk_list_store_set (store, iter,
+ COL_ACCOUNT_IMAGE, icon_name,
+ COL_ACCOUNT_TEXT, mc_account_get_display_name (account),
+ COL_ACCOUNT_ENABLED, is_enabled,
+ COL_ACCOUNT_POINTER, account,
+ -1);
+
+ /* set first connected account as active account */
+ if (priv->set_active_item == FALSE && is_enabled) {
+ priv->set_active_item = TRUE;
+ gtk_combo_box_set_active_iter (combobox, iter);
+ }
+}
+
+static void
+account_chooser_status_changed_cb (MissionControl *mc,
+ TelepathyConnectionStatus status,
+ McPresence presence,
+ TelepathyConnectionStatusReason reason,
+ const gchar *unique_name,
+ GossipAccountChooser *chooser)
+{
+}
+
+static gboolean
+account_chooser_separator_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GossipAccountChooser *chooser)
+{
+ GossipAccountChooserPriv *priv;
+ gchar *text;
+ gboolean is_separator;
+
+ priv = GET_PRIV (chooser);
+
+ if (!priv->has_all_option) {
+ return FALSE;
+ }
+
+ gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1);
+ is_separator = text == NULL;
+ g_free (text);
+
+ return is_separator;
+}
+
+static gboolean
+account_chooser_set_account_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ SetAccountData *data)
+{
+ McAccount *account;
+ gboolean equal;
+
+ gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
+
+ /* Special case so we can make it possible to select the All option */
+ if (!data->account && !account) {
+ equal = TRUE;
+ } else {
+ equal = gossip_account_equal (data->account, account);
+ g_object_unref (account);
+ }
+
+ if (equal) {
+ GtkComboBox *combobox;
+
+ combobox = GTK_COMBO_BOX (data->chooser);
+ gtk_combo_box_set_active_iter (combobox, iter);
+
+ data->set = TRUE;
+ }
+
+ return equal;
+}
+
+static gboolean
+account_chooser_set_enabled_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GossipAccountChooser *chooser)
+{
+ GossipAccountChooserPriv *priv;
+ McAccount *account;
+
+ priv = GET_PRIV (chooser);
+
+ gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
+ if (!account) {
+ return FALSE;
+ }
+
+ account_chooser_update_iter (chooser, iter, account);
+ g_object_unref (account);
+
+ return FALSE;
+}
+