13
0
livetrax/libs/tk/ztk/atkrelation.c

502 lines
14 KiB
C
Raw Normal View History

/* ATK - Accessibility Toolkit
* Copyright 2001 Sun Microsystems Inc.
*
* This library 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 library 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 Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <glib-object.h>
#include "atk.h"
/**
* SECTION:atkrelation
* @Short_description: An object used to describe a relation between a
* object and one or more other objects.
* @Title:AtkRelation
*
* An AtkRelation describes a relation between an object and one or
* more other objects. The actual relations that an object has with
* other objects are defined as an AtkRelationSet, which is a set of
* AtkRelations.
*/
enum {
PROP_0,
PROP_RELATION_TYPE,
PROP_TARGET,
PROP_LAST
};
static GPtrArray *extra_names = NULL;
static gpointer parent_class = NULL;
static void atk_relation_class_init (AtkRelationClass *klass);
static void atk_relation_finalize (GObject *object);
static void atk_relation_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void atk_relation_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static GPtrArray* atk_relation_get_ptr_array_from_value_array (GValueArray *array);
static GValueArray* atk_relation_get_value_array_from_ptr_array (GPtrArray *array);
GType
atk_relation_get_type (void)
{
static GType type = 0;
if (!type)
{
static const GTypeInfo typeInfo =
{
sizeof (AtkRelationClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) atk_relation_class_init,
(GClassFinalizeFunc) NULL,
NULL,
sizeof (AtkRelation),
0,
(GInstanceInitFunc) NULL,
} ;
type = g_type_register_static (G_TYPE_OBJECT, "AtkRelation", &typeInfo, 0) ;
}
return type;
}
static void
atk_relation_class_init (AtkRelationClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = atk_relation_finalize;
gobject_class->set_property = atk_relation_set_property;
gobject_class->get_property = atk_relation_get_property;
g_object_class_install_property (gobject_class,
PROP_RELATION_TYPE,
g_param_spec_enum ("relation_type",
"Relation Type",
"The type of the relation",
ATK_TYPE_RELATION_TYPE,
ATK_RELATION_NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_TARGET,
g_param_spec_value_array ("target",
"Target",
"An array of the targets for the relation",
NULL,
G_PARAM_READWRITE));
}
/**
* atk_relation_type_register:
* @name: a name string
*
* Associate @name with a new #AtkRelationType
* Returns: an #AtkRelationType associated with @name
**/
AtkRelationType
atk_relation_type_register (const gchar *name)
{
g_return_val_if_fail (name, ATK_RELATION_NULL);
if (!extra_names)
extra_names = g_ptr_array_new ();
g_ptr_array_add (extra_names, g_strdup (name));
return extra_names->len + ATK_RELATION_LAST_DEFINED;
}
/**
* atk_relation_type_get_name:
* @type: The #AtkRelationType whose name is required
*
* Gets the description string describing the #AtkRelationType @type.
*
* Returns: the string describing the AtkRelationType
*/
const gchar*
atk_relation_type_get_name (AtkRelationType type)
{
GTypeClass *type_class;
GEnumValue *value;
const gchar *name = NULL;
type_class = g_type_class_ref (ATK_TYPE_RELATION_TYPE);
g_return_val_if_fail (G_IS_ENUM_CLASS (type_class), NULL);
value = g_enum_get_value (G_ENUM_CLASS (type_class), type);
if (value)
{
name = value->value_nick;
}
else
{
if (extra_names)
{
gint n = type;
n -= ATK_RELATION_LAST_DEFINED + 1;
if (n < extra_names->len)
name = g_ptr_array_index (extra_names, n);
}
}
g_type_class_unref (type_class);
return name;
}
/**
* atk_relation_type_for_name:
* @name: a string which is the (non-localized) name of an ATK relation type.
*
* Get the #AtkRelationType type corresponding to a relation name.
*
* Returns: the #AtkRelationType enumerated type corresponding to the specified name,
* or #ATK_RELATION_NULL if no matching relation type is found.
**/
AtkRelationType
atk_relation_type_for_name (const gchar *name)
{
GTypeClass *type_class;
GEnumValue *value;
AtkRelationType type = ATK_RELATION_NULL;
g_return_val_if_fail (name, ATK_RELATION_NULL);
type_class = g_type_class_ref (ATK_TYPE_RELATION_TYPE);
g_return_val_if_fail (G_IS_ENUM_CLASS (type_class), ATK_RELATION_NULL);
value = g_enum_get_value_by_nick (G_ENUM_CLASS (type_class), name);
if (value)
{
type = value->value;
}
else
{
gint i;
if (extra_names)
{
for (i = 0; i < extra_names->len; i++)
{
gchar *extra_name = (gchar *)g_ptr_array_index (extra_names, i);
g_return_val_if_fail (extra_name, ATK_RELATION_NULL);
if (strcmp (name, extra_name) == 0)
{
type = i + 1 + ATK_RELATION_LAST_DEFINED;
break;
}
}
}
}
g_type_class_unref (type_class);
return type;
}
/**
* atk_relation_new:
* @targets: (array length=n_targets): an array of pointers to
* #AtkObjects
* @n_targets: number of #AtkObjects pointed to by @targets
* @relationship: an #AtkRelationType with which to create the new
* #AtkRelation
*
* Create a new relation for the specified key and the specified list
* of targets. See also atk_object_add_relationship().
*
* Returns: a pointer to a new #AtkRelation
**/
AtkRelation*
atk_relation_new (AtkObject **targets,
gint n_targets,
AtkRelationType relationship)
{
AtkRelation *relation;
int i;
GValueArray *array;
GValue *value;
g_return_val_if_fail (targets != NULL, NULL);
array = g_value_array_new (n_targets);
for (i = 0; i < n_targets; i++)
{
value = g_new0 (GValue, 1);
g_value_init (value, ATK_TYPE_OBJECT);
g_value_set_object (value, targets[i]);
array = g_value_array_append (array, value);
g_value_unset (value);
g_free (value);
}
relation = g_object_new (ATK_TYPE_RELATION,
"relation_type", relationship,
"target", array,
NULL);
g_value_array_free (array);
return relation;
}
/**
* atk_relation_get_relation_type:
* @relation: an #AtkRelation
*
* Gets the type of @relation
*
* Returns: the type of @relation
**/
AtkRelationType
atk_relation_get_relation_type (AtkRelation *relation)
{
g_return_val_if_fail (ATK_IS_RELATION (relation), 0);
return relation->relationship;
}
/**
* atk_relation_get_target:
* @relation: an #AtkRelation
*
* Gets the target list of @relation
*
* Returns: (transfer none) (element-type Atk.Object): the target list of @relation
**/
GPtrArray*
atk_relation_get_target (AtkRelation *relation)
{
g_return_val_if_fail (ATK_IS_RELATION (relation), NULL);
return relation->target;
}
static void
delete_object_while_in_relation (gpointer callback_data,
GObject *where_the_object_was)
{
GPtrArray *array;
g_assert (callback_data != NULL);
array = callback_data;
g_ptr_array_remove (array, where_the_object_was);
}
/**
* atk_relation_add_target:
* @relation: an #AtkRelation
* @target: an #AtkObject
*
* Adds the specified AtkObject to the target for the relation, if it is
* not already present. See also atk_object_add_relationship().
*
*
* Since: 1.9
**/
void
atk_relation_add_target (AtkRelation *relation,
AtkObject *target)
{
guint i;
g_return_if_fail (ATK_IS_RELATION (relation));
g_return_if_fail (ATK_IS_OBJECT (target));
/* first check if target occurs in array ... */
for (i = 0; i < relation->target->len; i++)
if (g_ptr_array_index(relation->target, i) == target)
return;
g_ptr_array_add (relation->target, target);
g_object_weak_ref (G_OBJECT (target), (GWeakNotify) delete_object_while_in_relation, relation->target);
}
/**
* atk_relation_remove_target:
* @relation: an #AtkRelation
* @target: an #AtkObject
*
* Remove the specified AtkObject from the target for the relation.
*
* Returns: TRUE if the removal is successful.
**/
gboolean
atk_relation_remove_target (AtkRelation *relation,
AtkObject *target)
{
gboolean ret = FALSE;
GPtrArray *array;
array = atk_relation_get_target (relation);
if (array && g_ptr_array_remove (array, target))
{
g_object_weak_unref (G_OBJECT (target),
(GWeakNotify) delete_object_while_in_relation,
relation->target);
ret = TRUE;
}
return ret;
}
static void
atk_relation_finalize (GObject *object)
{
AtkRelation *relation;
g_return_if_fail (ATK_IS_RELATION (object));
relation = ATK_RELATION (object);
if (relation->target)
{
gint i;
for (i = 0; i < relation->target->len; i++)
{
g_object_weak_unref (G_OBJECT (g_ptr_array_index (relation->target, i)),
(GWeakNotify) delete_object_while_in_relation,
relation->target);
}
g_ptr_array_free (relation->target, TRUE);
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
atk_relation_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
AtkRelation *relation;
gpointer boxed;
relation = ATK_RELATION (object);
switch (prop_id)
{
case PROP_RELATION_TYPE:
relation->relationship = g_value_get_enum (value);
break;
case PROP_TARGET:
if (relation->target)
{
gint i;
for (i = 0; i < relation->target->len; i++)
{
g_object_weak_unref (G_OBJECT (g_ptr_array_index (relation->target, i)),
(GWeakNotify) delete_object_while_in_relation,
relation->target);
}
g_ptr_array_free (relation->target, TRUE);
}
boxed = g_value_get_boxed (value);
relation->target = atk_relation_get_ptr_array_from_value_array ( (GValueArray *) boxed);
break;
default:
break;
}
}
static void
atk_relation_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
AtkRelation *relation;
GValueArray *array;
relation = ATK_RELATION (object);
switch (prop_id)
{
case PROP_RELATION_TYPE:
g_value_set_enum (value, relation->relationship);
break;
case PROP_TARGET:
array = atk_relation_get_value_array_from_ptr_array (relation->target);
g_value_set_boxed (value, array);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GPtrArray*
atk_relation_get_ptr_array_from_value_array (GValueArray *array)
{
gint i;
GPtrArray *return_array;
GValue *value;
GObject *obj;
return_array = g_ptr_array_sized_new (array->n_values);
for (i = 0; i < array->n_values; i++)
{
value = g_value_array_get_nth (array, i);
obj = g_value_get_object (value);
g_ptr_array_add (return_array, obj);
g_object_weak_ref (obj, (GWeakNotify) delete_object_while_in_relation, return_array);
}
return return_array;
}
static GValueArray*
atk_relation_get_value_array_from_ptr_array (GPtrArray *array)
{
int i;
GValueArray *return_array;
GValue *value;
return_array = g_value_array_new (array->len);
for (i = 0; i < array->len; i++)
{
value = g_new0 (GValue, 1);
g_value_init (value, ATK_TYPE_OBJECT);
g_value_set_object (value, g_ptr_array_index (array, i));
return_array = g_value_array_append (return_array, value);
}
return return_array;
}