Codebase list ssh-contact / upstream/0.6 src / vinagre / tree-view.c
upstream/0.6

Tree @upstream/0.6 (Download .tar.gz)

tree-view.c @upstream/0.6raw · history · blame

/*
 * Copyright (C) 2010 Collabora Ltd.
 *
 * 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., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */
#include <gtk/gtk.h>

#include <telepathy-glib/telepathy-glib.h>

#include "tree-view.h"
#include "../client-helpers.h"

enum
{
  COL_ACCOUNT,
  COL_CONTACT,
  COL_TEXT,
  N_COL
};

struct _SshContactTreeViewPrivate
{
  GtkListStore *store;
  TpAccountManager *account_manager;
};

G_DEFINE_TYPE (SshContactTreeView, ssh_contact_tree_view,
    GTK_TYPE_TREE_VIEW);

static TpAccount *
find_account_for_contact (SshContactTreeView *self,
    TpContact *contact)
{
  TpAccount *account = NULL;
  TpConnection *connection;
  GList *list;

  connection = tp_contact_get_connection (contact);
  list = tp_account_manager_get_valid_accounts (self->priv->account_manager);
  while (list)
    {
      if (tp_account_get_connection (list->data) == connection)
        {
          account = list->data;
          break;
        }
        
      list = g_list_delete_link (list, list);
    }
  g_list_free (list);

  return account;
}

static void
got_contacts_cb (TpConnection *connection,
    guint n_contacts,
    TpContact * const *contacts,
    guint n_failed,
    const TpHandle *failed,
    const GError *error,
    gpointer user_data,
    GObject *weak_object)
{
  SshContactTreeView *self = user_data;
  guint i;

  if (error != NULL)
    {
      g_debug ("%s", error->message);
      return;
    }

  for (i = 0; i < n_contacts; i++)
    {
      TpAccount *account;

      if (!_capabilities_has_stream_tube (tp_contact_get_capabilities (contacts[i])))
        continue;

      account = find_account_for_contact (self, contacts[i]);
      gtk_list_store_insert_with_values (self->priv->store, NULL, -1,
          COL_ACCOUNT, account,
          COL_CONTACT, contacts[i],
          COL_TEXT, tp_contact_get_alias (contacts[i]),
          -1);
    }
}

static void
stored_channel_prepare_cb (GObject *object,
    GAsyncResult *res,
    gpointer self)
{
  TpChannel *channel = TP_CHANNEL (object);
  TpConnection *connection;
  TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS,
      TP_CONTACT_FEATURE_CAPABILITIES };
  const TpIntSet *set;
  GArray *handles;
  GError *error = NULL;

  if (!tp_proxy_prepare_finish (channel, res, &error))
    {
      g_debug ("%s", error->message);
      g_clear_error (&error);
      return;
    }

  connection = tp_channel_borrow_connection (channel);
  set = tp_channel_group_get_members (channel);
  handles = tp_intset_to_array (set);

  tp_connection_get_contacts_by_handle (connection, handles->len,
      (TpHandle *) handles->data, G_N_ELEMENTS (features), features,
      got_contacts_cb, self, NULL, NULL);

  g_array_unref (handles);
}

static void
ensure_stored_channel_cb (TpConnection *connection,
    gboolean yours,
    const gchar *channel_path,
    GHashTable *properties,
    const GError *error,
    gpointer self,
    GObject *weak_object)
{
  TpChannel *channel;
  GQuark features[] = { TP_CHANNEL_FEATURE_GROUP, 0 };
  GError *err = NULL;

  if (error != NULL)
    {
      g_debug ("%s", error->message);
      return;
    }

  channel = tp_channel_new_from_properties (connection, channel_path,
      properties, &err);
  if (channel == NULL)
    {
      g_debug ("%s", err->message);
      g_clear_error (&err);
      return;
    }

  tp_proxy_prepare_async (TP_PROXY (channel), features,
      stored_channel_prepare_cb, self);

  g_object_unref (channel);
}

static void
connection_prepare_cb (GObject *object,
    GAsyncResult *res,
    gpointer self)
{
  TpConnection *connection = TP_CONNECTION (object);
  GError *error = NULL;
  GHashTable *request;

  if (!tp_proxy_prepare_finish (TP_PROXY (connection), res, &error))
    {
      g_debug ("%s", error->message);
      g_clear_error (&error);
      return;
    }

  if (!_capabilities_has_stream_tube (tp_connection_get_capabilities (connection)))
    return;

  request = tp_asv_new (
      TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
        TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
      TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
        TP_HANDLE_TYPE_LIST,
      TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING,
        "stored",
      NULL);

  tp_cli_connection_interface_requests_call_ensure_channel (connection, -1,
      request, ensure_stored_channel_cb, self, NULL, NULL);

  g_hash_table_unref (request);
}

static void
account_manager_prepare_cb (GObject *object,
    GAsyncResult *res,
    gpointer self)
{
  TpAccountManager *manager = TP_ACCOUNT_MANAGER (object);
  GList *accounts, *l;
  GError *error = NULL;

  if (!tp_proxy_prepare_finish (TP_PROXY (manager), res, &error))
    {
      g_debug ("%s", error->message);
      g_clear_error (&error);
      return;
    }

  accounts = tp_account_manager_get_valid_accounts (manager);
  for (l = accounts; l != NULL; l = l->next)
    {
      GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 };
      TpAccount *account = l->data;
      TpConnection *connection;
    
      connection = tp_account_get_connection (account);
      if (connection != NULL)
        tp_proxy_prepare_async (TP_PROXY (connection), features,
            connection_prepare_cb, self);
    }
  g_list_free (accounts);
}

static void
dispose (GObject *object)
{
  SshContactTreeView *self = SSH_CONTACT_TREE_VIEW (object);

  tp_clear_object (&self->priv->store);
  tp_clear_object (&self->priv->account_manager);

  G_OBJECT_CLASS (ssh_contact_tree_view_parent_class)->dispose (object);
}

static void
ssh_contact_tree_view_init (SshContactTreeView *self)
{
  GtkTreeView *view = GTK_TREE_VIEW (self);
  GtkCellRenderer *renderer;
  GtkTreeViewColumn *column;

  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SSH_CONTACT_TYPE_TREE_VIEW,
      SshContactTreeViewPrivate);

  self->priv->store = gtk_list_store_new (N_COL,
      G_TYPE_OBJECT,  /* ACCOUNT */
      G_TYPE_OBJECT,  /* CONTACT */
      G_TYPE_STRING); /* TEXT */

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes ("Contacts",
      renderer, "text", COL_TEXT, NULL);

  gtk_tree_view_append_column (view, column);
  gtk_tree_view_set_headers_visible (view, FALSE);
  gtk_tree_view_set_model (view, GTK_TREE_MODEL (self->priv->store));

  self->priv->account_manager = tp_account_manager_dup ();
  tp_proxy_prepare_async (TP_PROXY (self->priv->account_manager), NULL,
      account_manager_prepare_cb, self);
}

static void
ssh_contact_tree_view_class_init (SshContactTreeViewClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->dispose = dispose;

  g_type_class_add_private (klass, sizeof (SshContactTreeViewPrivate));
}

GtkWidget *
ssh_contact_tree_view_new (void)
{
  return g_object_new (SSH_CONTACT_TYPE_TREE_VIEW, NULL);
}

TpAccount *
ssh_contact_tree_view_get_selected_account (SshContactTreeView *self)
{
  GtkTreeSelection *selection;
  GtkTreeModel *model;
  GtkTreeIter iter;
  TpAccount *account = NULL;

  g_return_val_if_fail (SSH_CONTACT_IS_TREE_VIEW (self), NULL);

  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
    return NULL;

  gtk_tree_model_get (model, &iter, COL_ACCOUNT, &account, -1);
  g_object_unref (account);

  return account;
}

TpContact *
ssh_contact_tree_view_get_selected_contact (SshContactTreeView *self)
{
  GtkTreeSelection *selection;
  GtkTreeModel *model;
  GtkTreeIter iter;
  TpContact *contact;

  g_return_val_if_fail (SSH_CONTACT_IS_TREE_VIEW (self), NULL);

  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
    return NULL;

  gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1);
  g_object_unref (contact);

  return contact;
}

/* vim: set ts=8: */