/* 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 "atk.h" #include #include /** * AtkRelation: * * An object used to describe a relation between a * object and one or more other objects. * * 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; }