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