* Boston, MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <string.h>
#include <glib-object.h>
-#include "atkobject.h"
-#include "atkrelation.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 void atk_relation_class_init (AtkRelationClass *klass);
-static void atk_relation_finalize (GObject *object);
+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)
{
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));
}
/**
* @name: a name string
*
* Associate @name with a new #AtkRelationType
- *
+
* Returns: an #AtkRelationType associated with @name
**/
AtkRelationType
atk_relation_type_register (const gchar *name)
{
- /* TODO: associate name with new type */
- static guint type = ATK_RELATION_LAST_DEFINED;
- return (++type);
+ 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_from_string:
+ * 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.
* or #ATK_RELATION_NULL if no matching relation type is found.
**/
AtkRelationType
-atk_relation_type_from_string (const gchar *name)
+atk_relation_type_for_name (const gchar *name)
{
- /*
- * TODO: implement properly,
- * checking type namelist in conjunction with above function.
- */
- if ( !strcmp (name, "controlled_by") ) return ATK_RELATION_CONTROLLED_BY;
- else if (!strcmp (name, "controller_for")) return ATK_RELATION_CONTROLLER_FOR;
- else if (!strcmp (name, "label_for")) return ATK_RELATION_LABEL_FOR;
- else if (!strcmp (name, "labelled_by")) return ATK_RELATION_LABELLED_BY;
- else if (!strcmp (name, "member_of")) return ATK_RELATION_MEMBER_OF;
- else return ATK_RELATION_NULL;
+ 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: an array of pointers to #AtkObjects
+ * @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.
+ * of targets. See also atk_object_add_relationship().
*
* Returns: a pointer to a new #AtkRelation
**/
{
AtkRelation *relation;
int i;
- GPtrArray *array;
+ GValueArray *array;
+ GValue *value;
g_return_val_if_fail (targets != NULL, NULL);
- relation = g_object_new (ATK_TYPE_RELATION, NULL);
- array = g_ptr_array_sized_new (n_targets);
+ array = g_value_array_new (n_targets);
for (i = 0; i < n_targets; i++)
{
- /*
- * Add a reference to AtkObject being added to a relation
- */
- g_object_ref (targets[i]);
- g_ptr_array_add (array, 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->target = array;
- relation->relationship = relationship;
+ relation = g_object_new (ATK_TYPE_RELATION,
+ "relation_type", relationship,
+ "target", array,
+ NULL);
+
+ g_value_array_free (array);
return relation;
}
*
* Gets the target list of @relation
*
- * Returns: 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), FALSE);
+ 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;
for (i = 0; i < relation->target->len; i++)
{
- /*
- * Remove a reference to AtkObject being removed from a relation
- */
- g_object_unref (g_ptr_array_index (relation->target, 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;
}