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