Logo Search packages:      
Sourcecode: telepathy-inspector version File versions  Download package

ti-page-properties.c

/*
 * Telapathy Inspector - A Telepathy client which exposes Telepathy interfaces.
 *                       Meant to inspect and/or test connection managers.
 *
 * ti-page-properties.c:
 * A GtkNotebook page exposing
 * org.freedesktop.Telepathy.Properties functionality.
 *
 * Copyright (C) 2007 INdT - Instituto Nokia de Tecnologia
 * Author - Daniel d'Andrada T. de Carvalho <daniel.carvalho@indt.org.br>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "ti-page-properties.h"
#include "ti-page-priv.h"
#include "ti-constants.h"
#include "ti-util.h"

#include <glade/glade.h>
#include <string.h>

enum {
    TI_COLUMN_PROP_ID = 0,
    TI_COLUMN_PROP_NAME,
    TI_COLUMN_PROP_SIGNATURE,
    TI_COLUMN_PROP_FLAGS,
    TI_COLUMN_PROP_VALUE,
    TI_PROP_N_COLUMNS
};

struct _TIPagePropertiesClass {
    TIPageClass parent;
};

G_DEFINE_TYPE (TIPageProperties, ti_page_properties, TI_TYPE_PAGE);

/* Function prototypes */
static void _ti_page_properties_setup_page (TIPage* page, GladeXML* glade_xml);
static void _ti_page_properties_restart_page (TIPage* page);
static void _ti_page_properties_build_tree_view_props (TIPageProperties* self, GladeXML* glade_xml);
static void _ti_page_properties_list (TIPageProperties* self);
static void _ti_page_properties_get (TIPageProperties* self);
static void _ti_page_properties_set (TIPageProperties* self, guint id, const gchar* signature, const gchar* new_value);
static void _ti_page_properties_add_prop (TIPageProperties* self, guint id, const gchar* name,
                                          const gchar* signature, guint flags);
static void _ti_page_properties_on_props_changed (TIPageProperties* self, GPtrArray* prop_values);
static void _ti_page_properties_on_prop_flags_changed (TIPageProperties* self, GPtrArray* flags);
static void _ti_page_properties_update_prop_value (TIPageProperties* self, guint id, const GValue* value);
static void _ti_page_properties_update_prop_flags (TIPageProperties* self, guint id, guint flags);
static void _ti_page_properties_get_prop_row (TIPageProperties* self, GtkTreeIter* iter, guint id);
static void _ti_page_properties_property_value_edited (TIPageProperties* self, gchar* row_index, gchar* new_value);
static gchar* _ti_prop_flags_to_string (guint flags);

/*
 * Instance private data.
 */
struct _TIPagePropertiesPrivate {

    TIProperties* properties;

    GtkTreeView* tree_view_props;
    GtkListStore* list_store_props;
    GtkTreeSelection* selection_props;
};
typedef struct _TIPagePropertiesPrivate TIPagePropertiesPrivate;

#define TI_PAGE_PROPERTIES_GET_PRIVATE(object)  (G_TYPE_INSTANCE_GET_PRIVATE ((object), TI_TYPE_PAGE_PROPERTIES, TIPagePropertiesPrivate))

/*
 * Drop all references to other objects.
 */
static void
ti_page_properties_dispose (GObject *object)
{
    TIPageProperties* self = TI_PAGE_PROPERTIES (object);
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);

    if (priv->properties != NULL)
    {
        g_signal_handlers_disconnect_by_func(priv->properties,
                                             G_CALLBACK (_ti_page_properties_on_props_changed),
                                             self);

        g_signal_handlers_disconnect_by_func(priv->properties,
                                             G_CALLBACK (_ti_page_properties_on_prop_flags_changed),
                                             self);

        g_object_unref (priv->properties);
        priv->properties = NULL;
    }

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

/*
 * Finalizes the object, marking the memory as ready for reuse
 */
/*static void
ti_page_properties_finalize (GObject *object)
{
    TIPageProperties* self = TI_PAGE_PROPERTIES (object);
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);

    G_OBJECT_CLASS (ti_page_properties_parent_class)->finalize (object);
}*/

/*
 * Class initialization.
 */
static void
ti_page_properties_class_init (TIPagePropertiesClass* page_properties_class)
{
    GObjectClass *gobject_class = G_OBJECT_CLASS (page_properties_class);
    TIPageClass* page_class = TI_PAGE_CLASS (page_properties_class);

    /* override base object methods */ 
    gobject_class->dispose = ti_page_properties_dispose;
    //gobject_class->finalize = ti_page_properties_finalize;

    page_class->setup_page = _ti_page_properties_setup_page;
    page_class->restart_page = _ti_page_properties_restart_page;

    /* Add private */
    g_type_class_add_private (page_properties_class, sizeof (TIPagePropertiesPrivate));
}

/*
 * Instance initialization.
 */
static void
ti_page_properties_init (TIPageProperties* self)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);

    priv->properties = NULL;
}

/*
 * Returns a new instance.
 */
TIPageProperties*
ti_page_properties_new (GtkNotebook* parent_notebook, TIProperties* properties)
{
    TIPageProperties* page_properties;
    TIPagePropertiesPrivate *priv;

    page_properties = g_object_new (TI_TYPE_PAGE_PROPERTIES, NULL);
    priv = TI_PAGE_PROPERTIES_GET_PRIVATE (page_properties);

    priv->properties = properties;
    g_object_ref (properties);

    g_signal_connect_swapped (priv->properties, "properties-changed",
                              G_CALLBACK (_ti_page_properties_on_props_changed), page_properties);

    g_signal_connect_swapped (priv->properties, "property-flags-changed",
                              G_CALLBACK (_ti_page_properties_on_prop_flags_changed), page_properties);

    _ti_page_new ((TIPage**)&page_properties, parent_notebook, "page-properties.xml");

    return page_properties;
}

/*
 * Setup Page
 */
static void
_ti_page_properties_setup_page (TIPage* page, GladeXML* glade_xml)
{
    TIPageProperties* self = TI_PAGE_PROPERTIES (page);
    //TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GtkWidget* widget;

    // Properties list
    _ti_page_properties_build_tree_view_props (self, glade_xml);

    // Button "Refresh"
    widget = glade_xml_get_widget (glade_xml, "button_refresh");
    g_assert (widget != NULL && GTK_IS_BUTTON (widget));
    g_signal_connect_swapped (widget, "clicked", G_CALLBACK (_ti_page_properties_list), self);

    // Button "Get"
    widget = glade_xml_get_widget (glade_xml, "button_get");
    g_assert (widget != NULL && GTK_IS_BUTTON (widget));
    g_signal_connect_swapped (widget, "clicked", G_CALLBACK (_ti_page_properties_get), self);
}

/*
 * Restart Page
 */
static void
_ti_page_properties_restart_page (TIPage* page)
{
    TIPageProperties* self = TI_PAGE_PROPERTIES (page);

    _ti_page_properties_list (self);
}

/*
 * Build Treeview Props
 */
static void
_ti_page_properties_build_tree_view_props (TIPageProperties* self, GladeXML* glade_xml)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GtkCellRenderer* renderer;
    GtkCellRenderer* value_renderer;
    GtkTreeViewColumn* column;

    priv->tree_view_props = GTK_TREE_VIEW (glade_xml_get_widget(glade_xml, "treeview_props"));
    g_assert (priv->tree_view_props != NULL && GTK_IS_TREE_VIEW (priv->tree_view_props));

    priv->list_store_props = gtk_list_store_new (TI_PROP_N_COLUMNS,
                                                 G_TYPE_UINT,    // id
                                                 G_TYPE_STRING,  // name
                                                 G_TYPE_STRING,  // signature
                                                 G_TYPE_STRING,  // flags
                                                 G_TYPE_STRING,  // value
                                                 G_TYPE_STRING); // value color

    gtk_tree_view_set_model (priv->tree_view_props, GTK_TREE_MODEL (priv->list_store_props));

    renderer = gtk_cell_renderer_text_new ();

    value_renderer = gtk_cell_renderer_text_new ();
    g_object_set (value_renderer,
                  "editable", TRUE,
                  NULL);
    g_signal_connect_swapped (value_renderer, "edited",
                              G_CALLBACK (_ti_page_properties_property_value_edited), self);

    // Id column
    column = gtk_tree_view_column_new_with_attributes ("Id",
                                                       renderer,
                                                       "text", TI_COLUMN_PROP_ID,
                                                       NULL);
    gtk_tree_view_append_column (priv->tree_view_props, column);

    // Name column
    column = gtk_tree_view_column_new_with_attributes ("Name",
                                                       renderer,
                                                       "text", TI_COLUMN_PROP_NAME,
                                                       NULL);
    gtk_tree_view_append_column (priv->tree_view_props, column);

    // Signature column
    column = gtk_tree_view_column_new_with_attributes ("Sig",
                                                       renderer,
                                                       "text", TI_COLUMN_PROP_SIGNATURE,
                                                       NULL);
    gtk_tree_view_append_column (priv->tree_view_props, column);

    // Flags column
    column = gtk_tree_view_column_new_with_attributes ("Flags",
                                                       renderer,
                                                       "text", TI_COLUMN_PROP_FLAGS,
                                                       NULL);
    gtk_tree_view_append_column (priv->tree_view_props, column);

    // Value column
    column = gtk_tree_view_column_new_with_attributes ("Value",
                                                       value_renderer,
                                                       "text", TI_COLUMN_PROP_VALUE,
                                                       NULL);
    gtk_tree_view_append_column (priv->tree_view_props, column);

    priv->selection_props = gtk_tree_view_get_selection (priv->tree_view_props);
    gtk_tree_selection_set_mode (priv->selection_props, GTK_SELECTION_MULTIPLE);
}

/*
 * List Properties
 * Called when the "Refresh" button is clicked
 */
static void
_ti_page_properties_list (TIPageProperties* self)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GError* error = NULL;
    GPtrArray* props = NULL;
    GValueArray* property = NULL;
    guint i;
    guint id;
    const gchar* name;
    const gchar* signature;
    guint flags;

    gtk_list_store_clear (priv->list_store_props);

    props = ti_properties_list_properties (priv->properties, &error);
    if (error != NULL)
    {
        // TODO: Display a message or something.
        goto CLEAN_UP;
    }

    for (i = 0; i < props->len; i++)
    {
        property = (GValueArray*) g_ptr_array_index (props, i);

        id = g_value_get_uint (g_value_array_get_nth (property, 0));
        name = g_value_get_string (g_value_array_get_nth (property, 1));
        signature = g_value_get_string (g_value_array_get_nth (property, 2));
        flags = g_value_get_uint (g_value_array_get_nth (property, 3));

        _ti_page_properties_add_prop (self, id, name, signature, flags);

        g_value_array_free (property);
    }

    CLEAN_UP:
    g_ptr_array_free (props, TRUE);

    if (error != NULL)
        g_error_free (error);

}

/*
 * Get Properties
 * Called when the "Get" button is clicked
 */
static void
_ti_page_properties_get (TIPageProperties* self)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    guint i;
    guint id;
    GValue* value;
    GArray* prop_ids = NULL;
    GError* error = NULL;
    GPtrArray* prop_values = NULL;
    GValueArray* prop_value = NULL;

    prop_ids = ti_get_selected_elements (priv->selection_props, TI_COLUMN_PROP_ID, G_TYPE_UINT);
    if (prop_ids == NULL)
        goto CLEAN_UP;

    prop_values = ti_properties_get_properties (priv->properties, prop_ids, &error);
    if (error != NULL)
    {
        // TODO: Display a message or something.
        goto CLEAN_UP;
    }

    for (i = 0; i < prop_values->len; i++)
    {
        prop_value = (GValueArray*) g_ptr_array_index (prop_values, i);

        id = g_value_get_uint (g_value_array_get_nth (prop_value, 0));
        value = (GValue*) g_value_get_boxed (g_value_array_get_nth (prop_value, 1));

        g_assert (G_IS_VALUE (value));

        _ti_page_properties_update_prop_value (self, id, value);

        g_value_array_free (prop_value);
    }

    CLEAN_UP:
    if (prop_ids != NULL)
        g_array_free (prop_ids, TRUE);

    if (error != NULL)
        g_error_free (error);

    if (prop_values != NULL)
        g_ptr_array_free (prop_values, TRUE);
}

/*
 * Set Property
 */
static void
_ti_page_properties_set (TIPageProperties* self, guint id, const gchar* signature, const gchar* new_value)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GError* error = NULL;
    GPtrArray* prop_values = NULL;
    GValueArray* prop_value_struct = NULL;
    GValue value;

    // Create the GValue
    memset (&value, 0, sizeof (GValue));
    ti_string_to_value (&value, signature, new_value);

    // Create the (id, value) struct.
    prop_value_struct = g_value_array_new (2);

    g_value_array_append (prop_value_struct, NULL);
    g_value_init (g_value_array_get_nth (prop_value_struct, 0), G_TYPE_UINT);
    g_value_set_uint (g_value_array_get_nth (prop_value_struct, 0), id);

    g_value_array_append (prop_value_struct, NULL);
    g_value_init (g_value_array_get_nth (prop_value_struct, 1), G_TYPE_VALUE);
    g_value_set_boxed (g_value_array_get_nth (prop_value_struct, 1), &value);

    // Create the array to hold the (id, value) struct.
    prop_values = g_ptr_array_new ();
    g_ptr_array_add (prop_values, prop_value_struct);

    // And finally send the D-Bus command.
    ti_properties_set_properties (priv->properties, prop_values, &error);

    // Clean up
    if (error != NULL)
        g_error_free (error);

    if (prop_values != NULL)
        g_ptr_array_free (prop_values, TRUE);

    if (prop_value_struct != NULL)
        g_value_array_free (prop_value_struct);

    g_value_unset (&value);
}

/*
 * Add Property
 * Adds a property (without its value) to the properties list.
 */
static void
_ti_page_properties_add_prop (TIPageProperties* self, guint id, const gchar* name,
                              const gchar* signature, guint flags)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GtkTreeIter iter;
    gboolean ok;
    gboolean found = FALSE;
    guint curr_id;
    gchar* flags_str = NULL;

    // Look for property's row
    ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_props), &iter);
    while (ok && !found)
    {
        gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store_props), &iter,
                            TI_COLUMN_PROP_ID, &curr_id,
                            -1);

        if (curr_id == id)
        {
            found = TRUE;
        }
        else
        {
            ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store_props), &iter);
        }
    }

    if (!found)
    {
        // Create a new row for that property
        gtk_list_store_append (priv->list_store_props, &iter);
    }

    // Build flags string
    flags_str = _ti_prop_flags_to_string (flags);

    // Set row contents
    gtk_list_store_set (priv->list_store_props, &iter,
                        TI_COLUMN_PROP_ID, id,
                        TI_COLUMN_PROP_NAME, name,
                        TI_COLUMN_PROP_SIGNATURE, signature,
                        TI_COLUMN_PROP_FLAGS, flags_str,
                        -1);

    // Clean up
    g_free (flags_str);
}

/*
 * On Properties Changed
 * Event handler for "properties-changed" signal emitted by TIProperties
 */
static void
_ti_page_properties_on_props_changed (TIPageProperties* self, GPtrArray* prop_values)
{
    GValueArray* prop_value;
    guint i;
    guint id;
    GValue* value;

    for (i = 0; i < prop_values->len; i++)
    {
        prop_value = (GValueArray*) g_ptr_array_index (prop_values, i);

        id = g_value_get_uint (g_value_array_get_nth (prop_value, 0));
        value = (GValue*) g_value_get_boxed (g_value_array_get_nth (prop_value, 1));

        g_assert (G_IS_VALUE (value));

        _ti_page_properties_update_prop_value (self, id, value);
    }
}

/*
 * On Property Flags Changed
 * Event handler for "property-flags-changed" signal emitted by TIProperties
 */
static void
_ti_page_properties_on_prop_flags_changed (TIPageProperties* self, GPtrArray* flags)
{
    GValueArray* prop_flags;
    guint i;
    guint id;
    guint flags_uint;

    for (i = 0; i < flags->len; i++)
    {
        prop_flags = (GValueArray*) g_ptr_array_index (flags, i);

        id = g_value_get_uint (g_value_array_get_nth (prop_flags, 0));
        flags_uint = g_value_get_uint (g_value_array_get_nth (prop_flags, 1));

        _ti_page_properties_update_prop_flags (self, id, flags_uint);
    }
}

/*
 * Update Property Value
 * Updates the value of the property that has the given ID
 *
 * This is done on the local list that gets displayed to the user, not on the connection manager.
 */
static void
_ti_page_properties_update_prop_value (TIPageProperties* self, guint id, const GValue* value)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GtkTreeIter iter;
    gchar* value_str = NULL;

    _ti_page_properties_get_prop_row (self, &iter, id);

    value_str = ti_value_to_string (value);

    gtk_list_store_set (priv->list_store_props, &iter,
                        TI_COLUMN_PROP_VALUE, value_str,
                        -1);

    // Clean up
    g_free (value_str);
}

/*
 * Update Property Flags
  * Updates the flags of the property that has the given ID
 *
 * This is done on the local list that gets displayed to the user, not on the connection manager.
 */
static void
_ti_page_properties_update_prop_flags (TIPageProperties* self, guint id, guint flags)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GtkTreeIter iter;
    gchar* flags_str = NULL;

    _ti_page_properties_get_prop_row (self, &iter, id);

    flags_str = _ti_prop_flags_to_string (flags);

    gtk_list_store_set (priv->list_store_props, &iter,
                        TI_COLUMN_PROP_FLAGS, flags_str,
                        -1);

    // Clean up
    g_free (flags_str);
}

/*
 * Get Property Row
 */
static void
_ti_page_properties_get_prop_row (TIPageProperties* self, GtkTreeIter* iter, guint id)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    gboolean ok;
    gboolean found = FALSE;
    guint curr_id;

    ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_props), iter);
    while (ok && !found)
    {
        gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store_props), iter,
                            TI_COLUMN_PROP_ID, &curr_id,
                            -1);

        if (curr_id == id)
        {
            found = TRUE;
        }
        else
        {
            ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store_props), iter);
        }
    }

     // There must be already a row for that property.
    if (!found)
    {
        g_error ("_ti_page_properties_get_prop_row: Haven't found a row for the given property id.");
    }
}

/*
 * Property Value Edited
 * Called after the user edits a property value (the cell at the "Value" column of a given property row).
 */
static void
_ti_page_properties_property_value_edited (TIPageProperties* self, gchar* row_index, gchar* new_value)
{
    TIPagePropertiesPrivate* priv = TI_PAGE_PROPERTIES_GET_PRIVATE (self);
    GtkTreeIter iter;
    gchar* current_value = NULL;
    gchar* signature = NULL;
    guint id;
    gboolean ok;

    ok = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (priv->list_store_props), &iter, row_index);
    g_assert (ok);

    gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store_props), &iter,
                        TI_COLUMN_PROP_ID, &id,
                        TI_COLUMN_PROP_SIGNATURE, &signature,
                        TI_COLUMN_PROP_VALUE, &current_value,
                        -1);

    if (current_value == NULL)
    {
        current_value = g_strdup ("");
    }

    if (!g_str_equal (current_value, new_value))
    {
        _ti_page_properties_set (self, id, signature, new_value);
    }

    // Clean up
    g_free (current_value);
    g_free (signature);
}

/*
 * Property Flags to String
 */
static gchar* _ti_prop_flags_to_string (guint flags)
{
    GString* flags_str = g_string_new (NULL);

    if ((flags & TI_CHANNEL_PROPERTY_FLAG_READ) == TI_CHANNEL_PROPERTY_FLAG_READ)
        g_string_append (flags_str, "r");

    if ((flags & TI_CHANNEL_PROPERTY_FLAG_WRITE) == TI_CHANNEL_PROPERTY_FLAG_WRITE)
        g_string_append (flags_str, "w");

    return g_string_free (flags_str, FALSE);
}

Generated by  Doxygen 1.6.0   Back to index