Drop use of ATK_DISABLE_DEPRECATED guards in atk
[platform/upstream/atk.git] / atk / atkrelation.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 <string.h>
21 #include <glib-object.h>
22 #include "atkobject.h"
23 #include "atkrelation.h"
24 #include "atk-enum-types.h"
25
26 enum {
27   PROP_0,
28
29   PROP_RELATION_TYPE,
30   PROP_TARGET,
31   PROP_LAST
32 };
33
34 static GPtrArray *extra_names = NULL;
35
36 static gpointer parent_class = NULL;
37   
38 static void atk_relation_class_init   (AtkRelationClass *klass);
39 static void atk_relation_finalize     (GObject          *object);
40 static void atk_relation_set_property (GObject          *object,
41                                        guint            prop_id,
42                                        const GValue     *value,
43                                        GParamSpec       *pspec);
44 static void atk_relation_get_property (GObject          *object,
45                                        guint            prop_id,
46                                        GValue           *value,
47                                        GParamSpec       *pspec);
48
49 static GPtrArray* atk_relation_get_ptr_array_from_value_array (GValueArray *array);
50 static GValueArray* atk_relation_get_value_array_from_ptr_array (GPtrArray *array);
51
52 GType
53 atk_relation_get_type (void)
54 {
55   static GType type = 0;
56
57   if (!type)
58     {
59       static const GTypeInfo typeInfo =
60       {
61         sizeof (AtkRelationClass),
62         (GBaseInitFunc) NULL,
63         (GBaseFinalizeFunc) NULL,
64         (GClassInitFunc) atk_relation_class_init,
65         (GClassFinalizeFunc) NULL,
66         NULL,
67         sizeof (AtkRelation),
68         0,
69         (GInstanceInitFunc) NULL,
70       } ;
71       type = g_type_register_static (G_TYPE_OBJECT, "AtkRelation", &typeInfo, 0) ;
72     }
73   return type;
74 }
75
76 static void
77 atk_relation_class_init (AtkRelationClass *klass)
78 {
79   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
80
81   parent_class = g_type_class_peek_parent (klass);
82   
83   gobject_class->finalize = atk_relation_finalize;
84   gobject_class->set_property = atk_relation_set_property;
85   gobject_class->get_property = atk_relation_get_property;
86
87   g_object_class_install_property (gobject_class,
88                                    PROP_RELATION_TYPE,
89                                    g_param_spec_enum ("relation_type",
90                                                       "Relation Type",
91                                                       "The type of the relation",
92                                                       ATK_TYPE_RELATION_TYPE,
93                                                       ATK_RELATION_NULL,
94                                                       G_PARAM_READWRITE));
95   g_object_class_install_property (gobject_class,
96                                    PROP_TARGET,
97                                    g_param_spec_value_array ("target",
98                                                              "Target",
99                                                              "An array of the targets for the relation",
100                                                              NULL,
101
102                                                              G_PARAM_READWRITE));
103 }
104
105 /**
106  * atk_relation_type_register:
107  * @name: a name string
108  *
109  * Associate @name with a new #AtkRelationType
110  
111  * Returns: an #AtkRelationType associated with @name
112  **/
113 AtkRelationType
114 atk_relation_type_register (const gchar *name)
115 {
116   g_return_val_if_fail (name, ATK_RELATION_NULL);
117
118   if (!extra_names)
119     extra_names = g_ptr_array_new ();
120
121   g_ptr_array_add (extra_names, g_strdup (name));
122   return extra_names->len + ATK_RELATION_LAST_DEFINED;
123 }
124
125 /**
126  * atk_relation_type_get_name:
127  * @type: The #AtkRelationType whose name is required
128  *
129  * Gets the description string describing the #AtkRelationType @type.
130  *
131  * Returns: the string describing the AtkRelationType
132  */
133 const gchar*
134 atk_relation_type_get_name (AtkRelationType type)
135 {
136   GTypeClass *type_class;
137   GEnumValue *value;
138   const gchar *name = NULL;
139
140   type_class = g_type_class_ref (ATK_TYPE_RELATION_TYPE);
141   g_return_val_if_fail (G_IS_ENUM_CLASS (type_class), NULL);
142
143   value = g_enum_get_value (G_ENUM_CLASS (type_class), type);
144
145   if (value)
146     {
147       name = value->value_nick;
148     }
149   else
150     {
151       if (extra_names)
152         {
153           gint n = type;
154
155           n -= ATK_RELATION_LAST_DEFINED + 1;
156
157           if (n < extra_names->len)
158             name = g_ptr_array_index (extra_names, n);
159         }
160     }
161   g_type_class_unref (type_class);
162   return name;
163 }
164
165 /**
166  * atk_relation_type_for_name:
167  * @name: a string which is the (non-localized) name of an ATK relation type.
168  *
169  * Get the #AtkRelationType type corresponding to a relation name.
170  *
171  * Returns: the #AtkRelationType enumerated type corresponding to the specified name,
172  *          or #ATK_RELATION_NULL if no matching relation type is found.
173  **/
174 AtkRelationType
175 atk_relation_type_for_name (const gchar *name)
176 {
177   GTypeClass *type_class;
178   GEnumValue *value;
179   AtkRelationType type = ATK_RELATION_NULL;
180
181   g_return_val_if_fail (name, ATK_RELATION_NULL);
182
183   type_class = g_type_class_ref (ATK_TYPE_RELATION_TYPE);
184   g_return_val_if_fail (G_IS_ENUM_CLASS (type_class), ATK_RELATION_NULL);
185
186   value = g_enum_get_value_by_nick (G_ENUM_CLASS (type_class), name);
187
188   if (value)
189     {
190       type = value->value;
191     }
192   else
193     {
194       gint i;
195
196       if (extra_names)
197         {
198           for (i = 0; i < extra_names->len; i++)
199             {
200               gchar *extra_name = (gchar *)g_ptr_array_index (extra_names, i);
201
202               g_return_val_if_fail (extra_name, ATK_RELATION_NULL);
203          
204               if (strcmp (name, extra_name) == 0)
205                 {
206                   type = i + 1 + ATK_RELATION_LAST_DEFINED;
207                   break;
208                 }
209             }
210         }
211     }
212   g_type_class_unref (type_class);
213  
214   return type;
215 }
216
217
218 /**
219  * atk_relation_new:
220  * @targets: (array length=n_targets): an array of pointers to
221  *  #AtkObjects
222  * @n_targets: number of #AtkObjects pointed to by @targets
223  * @relationship: an #AtkRelationType with which to create the new
224  *  #AtkRelation
225  *
226  * Create a new relation for the specified key and the specified list
227  * of targets.  See also atk_object_add_relationship().
228  *
229  * Returns: a pointer to a new #AtkRelation
230  **/
231 AtkRelation*
232 atk_relation_new (AtkObject       **targets,
233                   gint            n_targets,
234                   AtkRelationType relationship)
235 {
236   AtkRelation *relation;
237   int         i;
238   GValueArray *array;
239   GValue      *value;
240
241   g_return_val_if_fail (targets != NULL, NULL);
242
243   array = g_value_array_new (n_targets);
244   for (i = 0; i < n_targets; i++)
245   {
246     value = g_new0 (GValue, 1);
247     g_value_init (value, ATK_TYPE_OBJECT);
248     g_value_set_object (value, targets[i]);
249     array = g_value_array_append (array, value);
250     g_value_unset (value);
251     g_free (value);
252   }
253   
254   relation =  g_object_new (ATK_TYPE_RELATION, 
255                             "relation_type", relationship,
256                             "target", array,
257                             NULL);
258
259   g_value_array_free (array);
260
261   return relation;
262 }
263
264 /**
265  * atk_relation_get_relation_type:
266  * @relation: an #AtkRelation 
267  *
268  * Gets the type of @relation
269  *
270  * Returns: the type of @relation
271  **/
272 AtkRelationType
273 atk_relation_get_relation_type (AtkRelation *relation)
274 {
275   g_return_val_if_fail (ATK_IS_RELATION (relation), 0);
276   
277   return relation->relationship;
278 }
279
280 /**
281  * atk_relation_get_target:
282  * @relation: an #AtkRelation
283  *
284  * Gets the target list of @relation
285  *
286  * Returns: (transfer none) (element-type Atk.Object): the target list of @relation
287  **/
288 GPtrArray*
289 atk_relation_get_target (AtkRelation *relation)
290 {
291   g_return_val_if_fail (ATK_IS_RELATION (relation), NULL);
292
293   return relation->target;
294 }
295
296 static void
297 delete_object_while_in_relation (gpointer callback_data,
298                                  GObject *where_the_object_was)
299 {
300   GPtrArray *array;
301
302   g_assert (callback_data != NULL);
303
304   array = callback_data;
305   g_ptr_array_remove (array, where_the_object_was);
306 }
307
308 /**
309  * atk_relation_add_target:
310  * @relation: an #AtkRelation
311  * @target: an #AtkObject
312  *
313  * Adds the specified AtkObject to the target for the relation, if it is
314  * not already present.  See also atk_object_add_relationship().
315  *
316  *
317  * Since: 1.9
318  **/
319 void
320 atk_relation_add_target (AtkRelation *relation,
321                          AtkObject   *target)
322 {
323   guint i;
324
325   g_return_if_fail (ATK_IS_RELATION (relation));
326   g_return_if_fail (ATK_IS_OBJECT (target));
327
328   /* first check if target occurs in array ... */
329   for (i = 0; i < relation->target->len; i++)
330     if (g_ptr_array_index(relation->target, i) == target)
331       return;
332
333   g_ptr_array_add (relation->target, target);
334   g_object_weak_ref (G_OBJECT (target), (GWeakNotify) delete_object_while_in_relation, relation->target);
335 }
336
337 /**
338  * atk_relation_remove_target:
339  * @relation: an #AtkRelation
340  * @target: an #AtkObject
341  *
342  * Remove the specified AtkObject from the target for the relation.
343  *
344  * Returns TRUE if the removal is successful.
345  **/
346
347 gboolean
348 atk_relation_remove_target (AtkRelation *relation,
349                             AtkObject *target)
350 {
351   gboolean ret = FALSE;
352   GPtrArray *array;
353
354   array = atk_relation_get_target (relation);
355
356   if (array && g_ptr_array_remove (array, target))
357     {
358       g_object_weak_unref (G_OBJECT (target),
359                            (GWeakNotify) delete_object_while_in_relation,
360                            relation->target);
361       ret = TRUE;
362     }
363   return ret;
364 }
365
366 static void
367 atk_relation_finalize (GObject *object)
368 {
369   AtkRelation        *relation;
370
371   g_return_if_fail (ATK_IS_RELATION (object));
372
373   relation = ATK_RELATION (object);
374
375   if (relation->target)
376   {
377     gint i;
378
379     for (i = 0; i < relation->target->len; i++)
380     {
381       g_object_weak_unref (G_OBJECT (g_ptr_array_index (relation->target, i)),
382                            (GWeakNotify) delete_object_while_in_relation, 
383                            relation->target);
384     }
385     g_ptr_array_free (relation->target, TRUE);
386   } 
387
388   G_OBJECT_CLASS (parent_class)->finalize (object);
389 }
390
391 static void 
392 atk_relation_set_property (GObject       *object,
393                            guint         prop_id,
394                            const GValue  *value,
395                            GParamSpec    *pspec)
396 {
397   AtkRelation *relation;
398   gpointer boxed;
399
400   relation = ATK_RELATION (object);
401
402   switch (prop_id)
403     {
404     case PROP_RELATION_TYPE:
405       relation->relationship = g_value_get_enum (value);
406       break; 
407     case PROP_TARGET:
408       if (relation->target)
409       {
410         gint i;
411
412         for (i = 0; i < relation->target->len; i++)
413         {
414           g_object_weak_unref (G_OBJECT (g_ptr_array_index (relation->target, i)),
415                                (GWeakNotify) delete_object_while_in_relation,
416                                relation->target);
417         }
418         g_ptr_array_free (relation->target, TRUE);
419       }
420       boxed = g_value_get_boxed (value);
421       relation->target = atk_relation_get_ptr_array_from_value_array ( (GValueArray *) boxed);
422       break; 
423     default:
424       break;
425     }  
426 }
427
428 static void
429 atk_relation_get_property (GObject    *object,
430                            guint      prop_id,
431                            GValue     *value,
432                            GParamSpec *pspec)
433 {
434   AtkRelation *relation;
435   GValueArray *array;
436
437   relation = ATK_RELATION (object);
438
439   switch (prop_id)
440     {
441     case PROP_RELATION_TYPE:
442       g_value_set_enum (value, relation->relationship);
443       break;
444     case PROP_TARGET:
445       array = atk_relation_get_value_array_from_ptr_array (relation->target);
446       g_value_set_boxed (value, array);
447       break;
448     default:
449       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
450       break;
451     }  
452 }
453
454 static GPtrArray*
455 atk_relation_get_ptr_array_from_value_array (GValueArray *array)
456 {
457   gint i;
458   GPtrArray *return_array;
459   GValue *value;
460   GObject *obj;
461
462   return_array = g_ptr_array_sized_new (array->n_values);
463   for (i = 0; i < array->n_values; i++)
464     {
465       value = g_value_array_get_nth (array, i);
466       obj = g_value_get_object (value);
467       g_ptr_array_add (return_array, obj);
468       g_object_weak_ref (obj, (GWeakNotify) delete_object_while_in_relation, return_array);
469     }
470       
471   return return_array;
472 }
473
474 static GValueArray*
475 atk_relation_get_value_array_from_ptr_array (GPtrArray *array)
476 {
477   int         i;
478   GValueArray *return_array;
479   GValue      *value;
480
481   return_array = g_value_array_new (array->len);
482   for (i = 0; i < array->len; i++)
483     {
484       value = g_new0 (GValue, 1);
485       g_value_init (value, ATK_TYPE_OBJECT);
486       g_value_set_object (value, g_ptr_array_index (array, i));
487       return_array = g_value_array_append (return_array, value);
488     }
489   return return_array;
490 }