835ded59c854eb7f5a03dbc3f8b1649bf141ec7b
[platform/upstream/atk.git] / atk / atkrelationset.c
1 /* ATK -  Accessibility Toolkit
2  * Copyright 2001 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <glib-object.h>
21
22 #include "atk.h"
23
24 /**
25  * SECTION:atkrelationset
26  * @Short_description: A set of AtkRelations, normally the set of
27  *  AtkRelations which an AtkObject has.
28  * @Title:AtkRelationSet
29  *
30  * The AtkRelationSet held by an object establishes its relationships
31  * with objects beyond the normal "parent/child" hierarchical
32  * relationships that all user interface objects have.
33  * AtkRelationSets establish whether objects are labelled or
34  * controlled by other components, share group membership with other
35  * components (for instance within a radio-button group), or share
36  * content which "flows" between them, among other types of possible
37  * relationships.
38  */
39
40 static gpointer parent_class = NULL;
41
42 static void atk_relation_set_class_init (AtkRelationSetClass  *klass);
43 static void atk_relation_set_finalize   (GObject              *object);
44
45 GType
46 atk_relation_set_get_type (void)
47 {
48   static GType type = 0;
49
50   if (!type)
51     {
52       static const GTypeInfo typeInfo =
53       {
54         sizeof (AtkRelationSetClass),
55         (GBaseInitFunc) NULL,
56         (GBaseFinalizeFunc) NULL,
57         (GClassInitFunc) atk_relation_set_class_init,
58         (GClassFinalizeFunc) NULL,
59         NULL,
60         sizeof (AtkRelationSet),
61         0,
62         (GInstanceInitFunc) NULL,
63       } ;
64       type = g_type_register_static (G_TYPE_OBJECT, "AtkRelationSet", &typeInfo, 0) ;
65     }
66   return type;
67 }
68
69 static void
70 atk_relation_set_class_init (AtkRelationSetClass *klass)
71 {
72   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
73
74   parent_class = g_type_class_peek_parent (klass);
75
76   gobject_class->finalize = atk_relation_set_finalize;
77 }
78
79 /**
80  * atk_relation_set_new:
81  * 
82  * Creates a new empty relation set.
83  * 
84  * Returns: a new #AtkRelationSet 
85  **/
86 AtkRelationSet*
87 atk_relation_set_new (void)
88 {
89   AtkRelationSet *relation_set;
90
91   relation_set = g_object_new (ATK_TYPE_RELATION_SET, NULL);
92   return relation_set;
93 }
94
95 /**
96  * atk_relation_set_contains:
97  * @set: an #AtkRelationSet
98  * @relationship: an #AtkRelationType
99  *
100  * Determines whether the relation set contains a relation that matches the
101  * specified type.
102  *
103  * Returns: %TRUE if @relationship is the relationship type of a relation
104  * in @set, %FALSE otherwise
105  **/
106 gboolean
107 atk_relation_set_contains (AtkRelationSet   *set,
108                            AtkRelationType  relationship)
109 {
110   GPtrArray *array_item;
111   AtkRelation *item;
112   gint  i;
113
114   g_return_val_if_fail (ATK_IS_RELATION_SET (set), FALSE);
115
116   array_item = set->relations;
117   if (array_item == NULL)
118     return FALSE;
119   for (i = 0; i < array_item->len; i++)
120   {
121     item = g_ptr_array_index (array_item, i);
122     if (item->relationship == relationship)
123       return TRUE;
124   }
125   return FALSE;
126 }
127
128 /**
129  * atk_relation_set_remove:
130  * @set: an #AtkRelationSet
131  * @relation: an #AtkRelation
132  *
133  * Removes a relation from the relation set.
134  * This function unref's the #AtkRelation so it will be deleted unless there
135  * is another reference to it.
136  **/
137 void
138 atk_relation_set_remove (AtkRelationSet *set,
139                          AtkRelation    *relation)
140 {
141   GPtrArray *array_item;
142   AtkRelationType relationship;
143
144   g_return_if_fail (ATK_IS_RELATION_SET (set));
145
146   array_item = set->relations;
147   if (array_item == NULL)
148     return;
149
150   if (g_ptr_array_remove (array_item, relation))
151   {
152     g_object_unref (relation);
153   }
154   else
155   {
156     relationship = atk_relation_get_relation_type (relation);
157     if (atk_relation_set_contains (set, relationship))
158     {
159       AtkRelation *exist_relation;
160       gint i;
161       exist_relation = atk_relation_set_get_relation_by_type (set, relationship);
162       for (i = 0; i < relation->target->len; i++)
163       {
164         AtkObject *target = g_ptr_array_index(relation->target, i);
165         atk_relation_remove_target (exist_relation, target);
166       }
167     }
168   }
169 }
170
171 /**
172  * atk_relation_set_add:
173  * @set: an #AtkRelationSet
174  * @relation: an #AtkRelation
175  *
176  * Add a new relation to the current relation set if it is not already
177  * present.
178  * This function ref's the AtkRelation so the caller of this function
179  * should unref it to ensure that it will be destroyed when the AtkRelationSet
180  * is destroyed.
181  **/
182 void
183 atk_relation_set_add (AtkRelationSet *set,
184                       AtkRelation    *relation)
185 {
186   AtkRelationType relationship;
187
188   g_return_if_fail (ATK_IS_RELATION_SET (set));
189   g_return_if_fail (relation != NULL);
190
191   if (set->relations == NULL)
192   {
193     set->relations = g_ptr_array_new ();
194   }
195
196   relationship = atk_relation_get_relation_type (relation);
197   if (!atk_relation_set_contains (set, relationship))
198   {
199     g_ptr_array_add (set->relations, relation);
200     g_object_ref (relation);
201   }
202   else
203   {
204     AtkRelation *exist_relation;
205     gint i;
206     exist_relation = atk_relation_set_get_relation_by_type (set, relationship);
207     for (i = 0; i < relation->target->len; i++)
208     {
209       AtkObject *target = g_ptr_array_index(relation->target, i);
210       atk_relation_add_target (exist_relation, target); 
211     }
212   }
213 }
214
215 /**
216  * atk_relation_set_get_n_relations:
217  * @set: an #AtkRelationSet
218  *
219  * Determines the number of relations in a relation set.
220  *
221  * Returns: an integer representing the number of relations in the set.
222  **/
223 gint
224 atk_relation_set_get_n_relations (AtkRelationSet *set)
225 {
226   g_return_val_if_fail (ATK_IS_RELATION_SET (set), 0);
227
228   if (set->relations == NULL)
229     return 0;
230
231   return set->relations->len;
232 }
233
234 /**
235  * atk_relation_set_get_relation:
236  * @set: an #AtkRelationSet
237  * @i: a gint representing a position in the set, starting from 0.
238  *
239  * Determines the relation at the specified position in the relation set.
240  *
241  * Returns: (transfer none): a #AtkRelation, which is the relation at
242  * position i in the set.
243  **/
244 AtkRelation*
245 atk_relation_set_get_relation (AtkRelationSet *set,
246                                gint           i)
247 {
248   GPtrArray *array_item;
249   AtkRelation* item;
250
251   g_return_val_if_fail (ATK_IS_RELATION_SET (set), NULL);
252   g_return_val_if_fail (i >= 0, NULL);
253
254   array_item = set->relations;
255   if (array_item == NULL)
256     return NULL;
257   item = g_ptr_array_index (array_item, i);
258   if (item == NULL)
259     return NULL;
260
261   return item;
262 }
263
264 /**
265  * atk_relation_set_get_relation_by_type:
266  * @set: an #AtkRelationSet
267  * @relationship: an #AtkRelationType
268  *
269  * Finds a relation that matches the specified type.
270  *
271  * Returns: (transfer none): an #AtkRelation, which is a relation matching the
272  * specified type.
273  **/
274 AtkRelation*
275 atk_relation_set_get_relation_by_type (AtkRelationSet  *set,
276                                        AtkRelationType relationship)
277 {
278   GPtrArray *array_item;
279   AtkRelation *item;
280   gint i;
281
282   g_return_val_if_fail (ATK_IS_RELATION_SET (set), NULL);
283
284   array_item = set->relations;
285   if (array_item == NULL)
286     return NULL;
287   for (i = 0; i < array_item->len; i++)
288   {
289     item = g_ptr_array_index (array_item, i);
290     if (item->relationship == relationship)
291       return item;
292   }
293   return NULL;
294 }
295
296 static void
297 atk_relation_set_finalize (GObject *object)
298 {
299   AtkRelationSet     *relation_set;
300   GPtrArray             *array;
301   gint               i;
302
303   g_return_if_fail (ATK_IS_RELATION_SET (object));
304
305   relation_set = ATK_RELATION_SET (object);
306   array = relation_set->relations;
307
308   if (array)
309   {
310     for (i = 0; i < array->len; i++)
311     {
312       g_object_unref (g_ptr_array_index (array, i));
313     }
314     g_ptr_array_free (array, TRUE);
315   }
316
317   G_OBJECT_CLASS (parent_class)->finalize (object);
318 }
319
320 /**
321  * atk_relation_set_add_relation_by_type:
322  * @set: an #AtkRelationSet
323  * @relationship: an #AtkRelationType
324  * @target: an #AtkObject
325  *
326  * Add a new relation of the specified type with the specified target to 
327  * the current relation set if the relation set does not contain a relation
328  * of that type. If it is does contain a relation of that typea the target
329  * is added to the relation.
330  *
331  * Since: 1.9
332  **/
333 void
334 atk_relation_set_add_relation_by_type (AtkRelationSet  *set,
335                                        AtkRelationType relationship,
336                                        AtkObject       *target)
337 {
338   AtkRelation *relation;
339
340   g_return_if_fail (ATK_IS_RELATION_SET (set));
341   g_return_if_fail (ATK_IS_OBJECT (target));
342
343   relation = atk_relation_set_get_relation_by_type (set,
344                                                     relationship);
345   if (relation)
346     {
347       atk_relation_add_target (relation, target);
348     } 
349   else 
350     {
351       /* the relation hasn't been created yet ... */
352       relation = atk_relation_new (&target, 1, relationship);
353       atk_relation_set_add (set, relation);
354       g_object_unref(relation);
355     }
356 }
357
358 /**
359  * atk_relation_set_contains_target:
360  * @set: an #AtkRelationSet
361  * @relationship: an #AtkRelationType
362  * @target: an #AtkObject
363  *
364  * Determines whether the relation set contains a relation that
365  * matches the specified pair formed by type @relationship and object
366  * @target.
367  *
368  * Returns: %TRUE if @set contains a relation with the relationship
369  * type @relationship with an object @target, %FALSE otherwise
370  **/
371
372 gboolean
373 atk_relation_set_contains_target (AtkRelationSet  *set,
374                                   AtkRelationType relationship,
375                                   AtkObject       *target)
376 {
377   GPtrArray *array_relations;
378   GPtrArray *array_target;
379   AtkObject *current_target;
380   AtkRelation *relation;
381   gint i;
382   gint c;
383
384   g_return_val_if_fail (ATK_IS_RELATION_SET (set), FALSE);
385   g_return_val_if_fail (ATK_IS_OBJECT (target), FALSE);
386
387   array_relations = set->relations;
388   if (array_relations == NULL)
389     return FALSE;
390
391   for (i = 0; i < array_relations->len; i++)
392   {
393     relation = g_ptr_array_index (array_relations, i);
394     if (relation->relationship == relationship)
395       {
396         array_target = atk_relation_get_target (relation);
397         for (c = 0; c < array_target->len; c++)
398           {
399             current_target = g_ptr_array_index (array_target, c);
400             if (target == current_target)
401               return TRUE;
402           }
403       }
404   }
405
406   return FALSE;
407 }