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
 * AtkRelationSet:
28
 *
29
 * A set of AtkRelations, normally the set of
30
 *  AtkRelations which an AtkObject has.
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
2785
atk_relation_set_get_type (void)
49
{
50
  static GType type = 0;
51

            
52
2785
  if (!type)
53
    {
54
      static const GTypeInfo typeInfo = {
55
        sizeof (AtkRelationSetClass),
56
        (GBaseInitFunc) NULL,
57
        (GBaseFinalizeFunc) NULL,
58
        (GClassInitFunc) atk_relation_set_class_init,
59
        (GClassFinalizeFunc) NULL,
60
        NULL,
61
        sizeof (AtkRelationSet),
62
        0,
63
        (GInstanceInitFunc) NULL,
64
      };
65
164
      type = g_type_register_static (G_TYPE_OBJECT, "AtkRelationSet", &typeInfo, 0);
66
    }
67
2785
  return type;
68
}
69

            
70
static void
71
164
atk_relation_set_class_init (AtkRelationSetClass *klass)
72
{
73
164
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
74

            
75
164
  parent_class = g_type_class_peek_parent (klass);
76

            
77
164
  gobject_class->finalize = atk_relation_set_finalize;
78
164
}
79

            
80
/**
81
 * atk_relation_set_new:
82
 *
83
 * Creates a new empty relation set.
84
 *
85
 * Returns: a new #AtkRelationSet
86
 **/
87
AtkRelationSet *
88
1971
atk_relation_set_new (void)
89
{
90
  AtkRelationSet *relation_set;
91

            
92
1971
  relation_set = g_object_new (ATK_TYPE_RELATION_SET, NULL);
93
1971
  return relation_set;
94
}
95

            
96
/**
97
 * atk_relation_set_contains:
98
 * @set: an #AtkRelationSet
99
 * @relationship: an #AtkRelationType
100
 *
101
 * Determines whether the relation set contains a relation that matches the
102
 * specified type.
103
 *
104
 * Returns: %TRUE if @relationship is the relationship type of a relation
105
 * in @set, %FALSE otherwise
106
 **/
107
gboolean
108
51
atk_relation_set_contains (AtkRelationSet *set,
109
                           AtkRelationType relationship)
110
{
111
  GPtrArray *array_item;
112
  AtkRelation *item;
113
  gint i;
114

            
115
51
  g_return_val_if_fail (ATK_IS_RELATION_SET (set), FALSE);
116

            
117
51
  array_item = set->relations;
118
51
  if (array_item == NULL)
119
    return FALSE;
120
51
  for (i = 0; i < array_item->len; i++)
121
    {
122
      item = g_ptr_array_index (array_item, i);
123
      if (item->relationship == relationship)
124
        return TRUE;
125
    }
126
51
  return FALSE;
127
}
128

            
129
/**
130
 * atk_relation_set_remove:
131
 * @set: an #AtkRelationSet
132
 * @relation: an #AtkRelation
133
 *
134
 * Removes a relation from the relation set.
135
 * This function unref's the #AtkRelation so it will be deleted unless there
136
 * is another reference to it.
137
 **/
138
void
139
1
atk_relation_set_remove (AtkRelationSet *set,
140
                         AtkRelation *relation)
141
{
142
  GPtrArray *array_item;
143
  AtkRelationType relationship;
144

            
145
1
  g_return_if_fail (ATK_IS_RELATION_SET (set));
146

            
147
1
  array_item = set->relations;
148
1
  if (array_item == NULL)
149
    return;
150

            
151
1
  if (g_ptr_array_remove (array_item, relation))
152
    {
153
1
      g_object_unref (relation);
154
    }
155
  else
156
    {
157
      relationship = atk_relation_get_relation_type (relation);
158
      if (atk_relation_set_contains (set, relationship))
159
        {
160
          AtkRelation *exist_relation;
161
          gint i;
162
          exist_relation = atk_relation_set_get_relation_by_type (set, relationship);
163
          for (i = 0; i < relation->target->len; i++)
164
            {
165
              AtkObject *target = g_ptr_array_index (relation->target, i);
166
              atk_relation_remove_target (exist_relation, target);
167
            }
168
        }
169
    }
170
}
171

            
172
/**
173
 * atk_relation_set_add:
174
 * @set: an #AtkRelationSet
175
 * @relation: an #AtkRelation
176
 *
177
 * Add a new relation to the current relation set if it is not already
178
 * present.
179
 * This function ref's the AtkRelation so the caller of this function
180
 * should unref it to ensure that it will be destroyed when the AtkRelationSet
181
 * is destroyed.
182
 **/
183
void
184
51
atk_relation_set_add (AtkRelationSet *set,
185
                      AtkRelation *relation)
186
{
187
  AtkRelationType relationship;
188

            
189
51
  g_return_if_fail (ATK_IS_RELATION_SET (set));
190
51
  g_return_if_fail (relation != NULL);
191

            
192
51
  if (set->relations == NULL)
193
    {
194
51
      set->relations = g_ptr_array_new ();
195
    }
196

            
197
51
  relationship = atk_relation_get_relation_type (relation);
198
51
  if (!atk_relation_set_contains (set, relationship))
199
    {
200
51
      g_ptr_array_add (set->relations, relation);
201
51
      g_object_ref (relation);
202
    }
203
  else
204
    {
205
      AtkRelation *exist_relation;
206
      gint i;
207
      exist_relation = atk_relation_set_get_relation_by_type (set, relationship);
208
      for (i = 0; i < relation->target->len; i++)
209
        {
210
          AtkObject *target = g_ptr_array_index (relation->target, i);
211
          atk_relation_add_target (exist_relation, target);
212
        }
213
    }
214
}
215

            
216
/**
217
 * atk_relation_set_get_n_relations:
218
 * @set: an #AtkRelationSet
219
 *
220
 * Determines the number of relations in a relation set.
221
 *
222
 * Returns: an integer representing the number of relations in the set.
223
 **/
224
gint
225
4
atk_relation_set_get_n_relations (AtkRelationSet *set)
226
{
227
4
  g_return_val_if_fail (ATK_IS_RELATION_SET (set), 0);
228

            
229
4
  if (set->relations == NULL)
230
    return 0;
231

            
232
4
  return set->relations->len;
233
}
234

            
235
/**
236
 * atk_relation_set_get_relation:
237
 * @set: an #AtkRelationSet
238
 * @i: a gint representing a position in the set, starting from 0.
239
 *
240
 * Determines the relation at the specified position in the relation set.
241
 *
242
 * Returns: (transfer none): a #AtkRelation, which is the relation at
243
 * position i in the set.
244
 **/
245
AtkRelation *
246
3
atk_relation_set_get_relation (AtkRelationSet *set,
247
                               gint i)
248
{
249
  GPtrArray *array_item;
250
  AtkRelation *item;
251

            
252
3
  g_return_val_if_fail (ATK_IS_RELATION_SET (set), NULL);
253
3
  g_return_val_if_fail (i >= 0, NULL);
254

            
255
3
  array_item = set->relations;
256
3
  if (array_item == NULL)
257
    return NULL;
258
3
  item = g_ptr_array_index (array_item, i);
259
3
  if (item == NULL)
260
    return NULL;
261

            
262
3
  return item;
263
}
264

            
265
/**
266
 * atk_relation_set_get_relation_by_type:
267
 * @set: an #AtkRelationSet
268
 * @relationship: an #AtkRelationType
269
 *
270
 * Finds a relation that matches the specified type.
271
 *
272
 * Returns: (transfer none): an #AtkRelation, which is a relation matching the
273
 * specified type.
274
 **/
275
AtkRelation *
276
1
atk_relation_set_get_relation_by_type (AtkRelationSet *set,
277
                                       AtkRelationType relationship)
278
{
279
  GPtrArray *array_item;
280
  AtkRelation *item;
281
  gint i;
282

            
283
1
  g_return_val_if_fail (ATK_IS_RELATION_SET (set), NULL);
284

            
285
1
  array_item = set->relations;
286
1
  if (array_item == NULL)
287
    return NULL;
288
1
  for (i = 0; i < array_item->len; i++)
289
    {
290
1
      item = g_ptr_array_index (array_item, i);
291
1
      if (item->relationship == relationship)
292
1
        return item;
293
    }
294
  return NULL;
295
}
296

            
297
static void
298
325
atk_relation_set_finalize (GObject *object)
299
{
300
  AtkRelationSet *relation_set;
301
  GPtrArray *array;
302
  gint i;
303

            
304
325
  g_return_if_fail (ATK_IS_RELATION_SET (object));
305

            
306
325
  relation_set = ATK_RELATION_SET (object);
307
325
  array = relation_set->relations;
308

            
309
325
  if (array)
310
    {
311
1
      for (i = 0; i < array->len; i++)
312
        {
313
          g_object_unref (g_ptr_array_index (array, i));
314
        }
315
1
      g_ptr_array_free (array, TRUE);
316
    }
317

            
318
325
  G_OBJECT_CLASS (parent_class)->finalize (object);
319
}
320

            
321
/**
322
 * atk_relation_set_add_relation_by_type:
323
 * @set: an #AtkRelationSet
324
 * @relationship: an #AtkRelationType
325
 * @target: an #AtkObject
326
 *
327
 * Add a new relation of the specified type with the specified target to
328
 * the current relation set if the relation set does not contain a relation
329
 * of that type. If it is does contain a relation of that typea the target
330
 * is added to the relation.
331
 *
332
 * Since: 1.9
333
 **/
334
void
335
atk_relation_set_add_relation_by_type (AtkRelationSet *set,
336
                                       AtkRelationType relationship,
337
                                       AtkObject *target)
338
{
339
  AtkRelation *relation;
340

            
341
  g_return_if_fail (ATK_IS_RELATION_SET (set));
342
  g_return_if_fail (ATK_IS_OBJECT (target));
343

            
344
  relation = atk_relation_set_get_relation_by_type (set,
345
                                                    relationship);
346
  if (relation)
347
    {
348
      atk_relation_add_target (relation, target);
349
    }
350
  else
351
    {
352
      /* the relation hasn't been created yet ... */
353
      relation = atk_relation_new (&target, 1, relationship);
354
      atk_relation_set_add (set, relation);
355
      g_object_unref (relation);
356
    }
357
}
358

            
359
/**
360
 * atk_relation_set_contains_target:
361
 * @set: an #AtkRelationSet
362
 * @relationship: an #AtkRelationType
363
 * @target: an #AtkObject
364
 *
365
 * Determines whether the relation set contains a relation that
366
 * matches the specified pair formed by type @relationship and object
367
 * @target.
368
 *
369
 * Returns: %TRUE if @set contains a relation with the relationship
370
 * type @relationship with an object @target, %FALSE otherwise
371
 **/
372

            
373
gboolean
374
1
atk_relation_set_contains_target (AtkRelationSet *set,
375
                                  AtkRelationType relationship,
376
                                  AtkObject *target)
377
{
378
  GPtrArray *array_relations;
379
  GPtrArray *array_target;
380
  AtkObject *current_target;
381
  AtkRelation *relation;
382
  gint i;
383
  gint c;
384

            
385
1
  g_return_val_if_fail (ATK_IS_RELATION_SET (set), FALSE);
386
1
  g_return_val_if_fail (ATK_IS_OBJECT (target), FALSE);
387

            
388
1
  array_relations = set->relations;
389
1
  if (array_relations == NULL)
390
1
    return FALSE;
391

            
392
  for (i = 0; i < array_relations->len; i++)
393
    {
394
      relation = g_ptr_array_index (array_relations, i);
395
      if (relation->relationship == relationship)
396
        {
397
          array_target = atk_relation_get_target (relation);
398
          for (c = 0; c < array_target->len; c++)
399
            {
400
              current_target = g_ptr_array_index (array_target, c);
401
              if (target == current_target)
402
                return TRUE;
403
            }
404
        }
405
    }
406

            
407
  return FALSE;
408
}