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