AtkRelation: added method that checks relationship and target
[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 static gpointer parent_class = NULL;
25
26 static void atk_relation_set_class_init (AtkRelationSetClass  *klass);
27 static void atk_relation_set_finalize   (GObject              *object);
28
29 GType
30 atk_relation_set_get_type (void)
31 {
32   static GType type = 0;
33
34   if (!type)
35     {
36       static const GTypeInfo typeInfo =
37       {
38         sizeof (AtkRelationSetClass),
39         (GBaseInitFunc) NULL,
40         (GBaseFinalizeFunc) NULL,
41         (GClassInitFunc) atk_relation_set_class_init,
42         (GClassFinalizeFunc) NULL,
43         NULL,
44         sizeof (AtkRelationSet),
45         0,
46         (GInstanceInitFunc) NULL,
47       } ;
48       type = g_type_register_static (G_TYPE_OBJECT, "AtkRelationSet", &typeInfo, 0) ;
49     }
50   return type;
51 }
52
53 static void
54 atk_relation_set_class_init (AtkRelationSetClass *klass)
55 {
56   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
57
58   parent_class = g_type_class_peek_parent (klass);
59
60   gobject_class->finalize = atk_relation_set_finalize;
61 }
62
63 /**
64  * atk_relation_set_new:
65  * 
66  * Creates a new empty relation set.
67  * 
68  * Returns: a new #AtkRelationSet 
69  **/
70 AtkRelationSet*
71 atk_relation_set_new (void)
72 {
73   AtkRelationSet *relation_set;
74
75   relation_set = g_object_new (ATK_TYPE_RELATION_SET, NULL);
76   return relation_set;
77 }
78
79 /**
80  * atk_relation_set_contains:
81  * @set: an #AtkRelationSet
82  * @relationship: an #AtkRelationType
83  *
84  * Determines whether the relation set contains a relation that matches the
85  * specified type.
86  *
87  * Returns: %TRUE if @relationship is the relationship type of a relation
88  * in @set, %FALSE otherwise
89  **/
90 gboolean
91 atk_relation_set_contains (AtkRelationSet   *set,
92                            AtkRelationType  relationship)
93 {
94   GPtrArray *array_item;
95   AtkRelation *item;
96   gint  i;
97
98   g_return_val_if_fail (ATK_IS_RELATION_SET (set), FALSE);
99
100   array_item = set->relations;
101   if (array_item == NULL)
102     return FALSE;
103   for (i = 0; i < array_item->len; i++)
104   {
105     item = g_ptr_array_index (array_item, i);
106     if (item->relationship == relationship)
107       return TRUE;
108   }
109   return FALSE;
110 }
111
112 /**
113  * atk_relation_set_remove:
114  * @set: an #AtkRelationSet
115  * @relation: an #AtkRelation
116  *
117  * Removes a relation from the relation set.
118  * This function unref's the #AtkRelation so it will be deleted unless there
119  * is another reference to it.
120  **/
121 void
122 atk_relation_set_remove (AtkRelationSet *set,
123                          AtkRelation    *relation)
124 {
125   GPtrArray *array_item;
126   AtkRelationType relationship;
127
128   g_return_if_fail (ATK_IS_RELATION_SET (set));
129
130   array_item = set->relations;
131   if (array_item == NULL)
132     return;
133
134   if (g_ptr_array_remove (array_item, relation))
135   {
136     g_object_unref (relation);
137   }
138   else
139   {
140     relationship = atk_relation_get_relation_type (relation);
141     if (atk_relation_set_contains (set, relationship))
142     {
143       AtkRelation *exist_relation;
144       gint i;
145       exist_relation = atk_relation_set_get_relation_by_type (set, relationship);
146       for (i = 0; i < relation->target->len; i++)
147       {
148         AtkObject *target = g_ptr_array_index(relation->target, i);
149         atk_relation_remove_target (exist_relation, target);
150       }
151     }
152   }
153 }
154
155 /**
156  * atk_relation_set_add:
157  * @set: an #AtkRelationSet
158  * @relation: an #AtkRelation
159  *
160  * Add a new relation to the current relation set if it is not already
161  * present.
162  * This function ref's the AtkRelation so the caller of this function
163  * should unref it to ensure that it will be destroyed when the AtkRelationSet
164  * is destroyed.
165  **/
166 void
167 atk_relation_set_add (AtkRelationSet *set,
168                       AtkRelation    *relation)
169 {
170   AtkRelationType relationship;
171
172   g_return_if_fail (ATK_IS_RELATION_SET (set));
173   g_return_if_fail (relation != NULL);
174
175   if (set->relations == NULL)
176   {
177     set->relations = g_ptr_array_new ();
178   }
179
180   relationship = atk_relation_get_relation_type (relation);
181   if (!atk_relation_set_contains (set, relationship))
182   {
183     g_ptr_array_add (set->relations, relation);
184     g_object_ref (relation);
185   }
186   else
187   {
188     AtkRelation *exist_relation;
189     gint i;
190     exist_relation = atk_relation_set_get_relation_by_type (set, relationship);
191     for (i = 0; i < relation->target->len; i++)
192     {
193       AtkObject *target = g_ptr_array_index(relation->target, i);
194       atk_relation_add_target (exist_relation, target); 
195     }
196   }
197 }
198
199 /**
200  * atk_relation_set_get_n_relations:
201  * @set: an #AtkRelationSet
202  *
203  * Determines the number of relations in a relation set.
204  *
205  * Returns: an integer representing the number of relations in the set.
206  **/
207 gint
208 atk_relation_set_get_n_relations (AtkRelationSet *set)
209 {
210   g_return_val_if_fail (ATK_IS_RELATION_SET (set), 0);
211
212   if (set->relations == NULL)
213     return 0;
214
215   return set->relations->len;
216 }
217
218 /**
219  * atk_relation_set_get_relation:
220  * @set: an #AtkRelationSet
221  * @i: a gint representing a position in the set, starting from 0.
222  *
223  * Determines the relation at the specified position in the relation set.
224  *
225  * Returns: (transfer none): a #AtkRelation, which is the relation at
226  * position i in the set.
227  **/
228 AtkRelation*
229 atk_relation_set_get_relation (AtkRelationSet *set,
230                                gint           i)
231 {
232   GPtrArray *array_item;
233   AtkRelation* item;
234
235   g_return_val_if_fail (ATK_IS_RELATION_SET (set), NULL);
236   g_return_val_if_fail (i >= 0, NULL);
237
238   array_item = set->relations;
239   if (array_item == NULL)
240     return NULL;
241   item = g_ptr_array_index (array_item, i);
242   if (item == NULL)
243     return NULL;
244
245   return item;
246 }
247
248 /**
249  * atk_relation_set_get_relation_by_type:
250  * @set: an #AtkRelationSet
251  * @relationship: an #AtkRelationType
252  *
253  * Finds a relation that matches the specified type.
254  *
255  * Returns: (transfer none): an #AtkRelation, which is a relation matching the
256  * specified type.
257  **/
258 AtkRelation*
259 atk_relation_set_get_relation_by_type (AtkRelationSet  *set,
260                                        AtkRelationType relationship)
261 {
262   GPtrArray *array_item;
263   AtkRelation *item;
264   gint i;
265
266   g_return_val_if_fail (ATK_IS_RELATION_SET (set), NULL);
267
268   array_item = set->relations;
269   if (array_item == NULL)
270     return NULL;
271   for (i = 0; i < array_item->len; i++)
272   {
273     item = g_ptr_array_index (array_item, i);
274     if (item->relationship == relationship)
275       return item;
276   }
277   return NULL;
278 }
279
280 static void
281 atk_relation_set_finalize (GObject *object)
282 {
283   AtkRelationSet     *relation_set;
284   GPtrArray             *array;
285   gint               i;
286
287   g_return_if_fail (ATK_IS_RELATION_SET (object));
288
289   relation_set = ATK_RELATION_SET (object);
290   array = relation_set->relations;
291
292   if (array)
293   {
294     for (i = 0; i < array->len; i++)
295     {
296       g_object_unref (g_ptr_array_index (array, i));
297     }
298     g_ptr_array_free (array, TRUE);
299   }
300
301   G_OBJECT_CLASS (parent_class)->finalize (object);
302 }
303
304 /**
305  * atk_relation_set_add_relation_by_type:
306  * @set: an #AtkRelationSet
307  * @relationship: an #AtkRelationType
308  * @target: an #AtkObject
309  *
310  * Add a new relation of the specified type with the specified target to 
311  * the current relation set if the relation set does not contain a relation
312  * of that type. If it is does contain a relation of that typea the target
313  * is added to the relation.
314  *
315  * Since: 1.9
316  **/
317 void
318 atk_relation_set_add_relation_by_type (AtkRelationSet  *set,
319                                        AtkRelationType relationship,
320                                        AtkObject       *target)
321 {
322   AtkRelation *relation;
323
324   g_return_if_fail (ATK_IS_RELATION_SET (set));
325   g_return_if_fail (ATK_IS_OBJECT (target));
326
327   relation = atk_relation_set_get_relation_by_type (set,
328                                                     relationship);
329   if (relation)
330     {
331       atk_relation_add_target (relation, target);
332     } 
333   else 
334     {
335       /* the relation hasn't been created yet ... */
336       relation = atk_relation_new (&target, 1, relationship);
337       atk_relation_set_add (set, relation);
338       g_object_unref(relation);
339     }
340 }
341
342 /**
343  * atk_relation_set_contains_target:
344  * @set: an #AtkRelationSet
345  * @relationship: an #AtkRelationType
346  * @target: an #AtkObject
347  *
348  * Determines whether the relation set contains a relation that
349  * matches the specified pair formed by type @relationship and object
350  * @target.
351  *
352  * Returns: %TRUE if @set contains a relation with the relationship
353  * type @relationship with an object @target, %FALSE otherwise
354  **/
355
356 gboolean
357 atk_relation_set_contains_target (AtkRelationSet  *set,
358                                   AtkRelationType relationship,
359                                   AtkObject       *target)
360 {
361   GPtrArray *array_relations;
362   GPtrArray *array_target;
363   AtkObject *current_target;
364   AtkRelation *relation;
365   gint i;
366   gint c;
367
368   g_return_val_if_fail (ATK_IS_RELATION_SET (set), FALSE);
369   g_return_val_if_fail (ATK_IS_OBJECT (target), FALSE);
370
371   array_relations = set->relations;
372   if (array_relations == NULL)
373     return FALSE;
374
375   for (i = 0; i < array_relations->len; i++)
376   {
377     relation = g_ptr_array_index (array_relations, i);
378     if (relation->relationship == relationship)
379       {
380         array_target = atk_relation_get_target (relation);
381         for (c = 0; c < array_target->len; c++)
382           {
383             current_target = g_ptr_array_index (array_target, c);
384             if (target == current_target)
385               return TRUE;
386           }
387       }
388   }
389
390   return FALSE;
391 }