2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2007 IBM Corp.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 /* collection.c: implements the Collection interface */
28 #include <bonobo/bonobo-exception.h>
29 #include <libspi/accessible.h>
30 #include <libspi/collection.h>
31 #include <libspi/matchrule.h>
32 #include <libspi/stateset.h>
33 #include <libspi/spi-private.h>
36 spi_collection_interface_new (AtkObject *obj)
39 SpiCollection *new_collection = g_object_new (SPI_COLLECTION_TYPE, NULL);
40 spi_base_construct (SPI_BASE (new_collection), G_OBJECT (obj));
42 return new_collection;
48 get_atkobject_from_servant (PortableServer_Servant servant){
50 SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
52 g_return_val_if_fail (object, NULL);
53 g_return_val_if_fail (ATK_IS_OBJECT (object->gobj), NULL);
55 return ATK_OBJECT (object->gobj);
58 static SpiCollection *
59 get_collection_from_servant (PortableServer_Servant servant)
61 SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
63 g_return_val_if_fail (object, NULL);
64 g_return_val_if_fail (IS_COLLECTION (object), NULL);
66 return SPI_COLLECTION (object);
71 static Accessibility_MatchRule
72 impl_createMatchRule (PortableServer_Servant servant,
73 const Accessibility_StateSet states,
74 const Accessibility_Collection_MatchType statematchtype,
75 const Accessibility_AttributeSet *attributes,
76 const Accessibility_Collection_MatchType attributematchtype,
77 const Accessibility_RoleSet *roles,
78 const Accessibility_Collection_MatchType rolematchtype,
79 const CORBA_char *interfaces,
80 const Accessibility_Collection_MatchType interfacematchtype,
81 const CORBA_boolean invert,
82 CORBA_Environment *ev){
84 Accessibility_MatchRule retval = NULL;
86 SpiMatchrule *matchrule = spi_matchrule_interface_new ();
87 MatchRulePrivate *mrp = get_collection_from_servant (servant)->_mrp;
88 Accessibility_StateSet ss = CORBA_Object_duplicate (states, ev);
93 CORBA_free (mrp->attributes);
94 CORBA_free (mrp->roles);
95 CORBA_free (mrp->interfaces);
100 get_collection_from_servant (servant)->_mrp = g_new (MatchRulePrivate, 1);
101 mrp = get_collection_from_servant (servant)->_mrp;
106 mrp->statematchtype = statematchtype;
110 mrp->attributes = CORBA_sequence_CORBA_string__alloc ();
111 mrp->attributes->_maximum = attributes->_maximum;
112 mrp->attributes->_length = attributes->_length;
113 mrp->attributes->_buffer = CORBA_sequence_CORBA_string_allocbuf (attributes->_length);
115 for (i = 0; i < mrp->attributes->_length; i++)
116 mrp->attributes->_buffer [i]= CORBA_string_dup (attributes->_buffer [i]);
118 CORBA_sequence_set_release (mrp->attributes, TRUE);
119 mrp->attributematchtype = attributematchtype;
123 mrp->roles = Accessibility_RoleSet__alloc ();
124 mrp->roles->_maximum = roles->_maximum;
125 mrp->roles->_length = roles->_length;
126 mrp->roles->_buffer = Accessibility_RoleSet_allocbuf (roles->_length);
128 for (i = 0; i < roles->_length; i++)
129 mrp->roles->_buffer [i] = roles->_buffer [i];
131 CORBA_sequence_set_release (mrp->roles, TRUE);
132 mrp->rolematchtype = rolematchtype;
136 mrp->interfaces = CORBA_string_dup (interfaces);
137 mrp->interfacematchtype = interfacematchtype;
139 mrp->invert = invert;
141 retval = CORBA_Object_duplicate (BONOBO_OBJREF (matchrule), ev);
147 static void impl_freeMatchRule (PortableServer_Servant servant,
148 Accessibility_MatchRule matchrule,
149 CORBA_Environment *ev){
151 SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
152 SpiCollection *spimatchrule;
154 MatchRulePrivate *mrp;
156 spimatchrule = SPI_COLLECTION (object);
157 mrp = spimatchrule->_mrp;
159 CORBA_free (mrp->attributes);
160 CORBA_free (mrp->roles);
161 CORBA_free (mrp->interfaces);
170 child_interface_p (Accessibility_Accessible child, gchar *repo_id, CORBA_Environment *ev) {
174 retval = Bonobo_Unknown_queryInterface (child, repo_id, ev);
176 return (retval != CORBA_OBJECT_NIL)? TRUE : FALSE;
180 #define child_collection_p(ch,ev) (child_interface_p (ch,"IDL:Accessibility/Collection:1.0", ev))
183 match_states_all_p (Accessibility_Accessible child, Accessibility_StateSet set, CORBA_Environment *ev){
186 Accessibility_StateSet chs ;
187 Accessibility_StateSeq *seq = Accessibility_StateSet_getStates (set, ev);
190 if (seq->_length == 0 || seq == NULL)
193 chs = Accessibility_Accessible_getState (child, ev);
196 for (i = 0; i < seq->_length; i++)
197 if (!Accessibility_StateSet_contains (chs, seq->_buffer [i], ev))
205 match_states_any_p (Accessibility_Accessible child, Accessibility_StateSet set, CORBA_Environment *ev){
207 Accessibility_StateSet chs;
208 Accessibility_StateSeq *seq = Accessibility_StateSet_getStates (set, ev);
211 if (seq->_length == 0 || seq == NULL)
214 chs = Accessibility_Accessible_getState (child, ev);
216 for (i = 0; i < seq->_length; i++)
217 if (Accessibility_StateSet_contains (chs, seq->_buffer [i], ev))
225 match_states_none_p (Accessibility_Accessible child, Accessibility_StateSet set, CORBA_Environment *ev){
227 Accessibility_StateSet chs;
228 Accessibility_StateSeq *seq = Accessibility_StateSet_getStates (set, ev);
231 if (seq->_length == 0)
233 chs = Accessibility_Accessible_getState (child, ev);
235 for (i = 0; i < seq->_length; i++)
236 if (Accessibility_StateSet_contains (chs, seq->_buffer [i], ev))
244 match_states_lookup (Accessibility_Accessible child, MatchRulePrivate *mrp, CORBA_Environment *ev){
246 switch (mrp->statematchtype){
247 case Accessibility_Collection_MATCH_ALL :
248 if (match_states_all_p (child, mrp->states, ev))
252 case Accessibility_Collection_MATCH_ANY :
253 if (match_states_any_p (child, mrp->states, ev))
257 case Accessibility_Collection_MATCH_NONE :
258 if (match_states_none_p (child, mrp->states, ev))
270 match_roles_all_p (Accessibility_Accessible child, Accessibility_RoleSet *roles, CORBA_Environment *ev){
272 Accessibility_Role role;
274 if (roles->_length > 1)
276 else if (roles->_length == 0 || roles == NULL)
279 role = Accessibility_Accessible_getRole (child, ev);
281 if (role == roles->_buffer [0])
290 match_roles_any_p (Accessibility_Accessible child, Accessibility_RoleSet *roles, CORBA_Environment *ev){
292 Accessibility_Role role;
295 if (roles->_length == 0 || roles == NULL)
298 role = Accessibility_Accessible_getRole (child, ev);
300 for (i = 0; i < roles->_length; i++)
301 if (role == roles->_buffer [i])
309 match_roles_none_p (Accessibility_Accessible child, Accessibility_RoleSet *roles, CORBA_Environment *ev){
311 Accessibility_Role role ;
314 if (roles->_length == 0 || roles == NULL)
317 role = Accessibility_Accessible_getRole (child, ev);
319 for (i = 0; i < roles->_length; i++)
320 if (role == roles->_buffer [i])
329 match_roles_lookup (Accessibility_Accessible child, MatchRulePrivate *mrp, CORBA_Environment *ev){
331 switch (mrp->rolematchtype){
332 case Accessibility_Collection_MATCH_ALL :
333 if (match_roles_all_p (child, mrp->roles, ev))
337 case Accessibility_Collection_MATCH_ANY :
338 if (match_roles_any_p (child, mrp->roles, ev))
342 case Accessibility_Collection_MATCH_NONE :
343 if (match_roles_none_p (child, mrp->roles, ev))
356 #define split_ifaces(ifaces) (g_strsplit (ifaces, ";", 0))
359 match_interfaces_all_p (Accessibility_Accessible obj, gchar *interfaces, CORBA_Environment *ev){
363 if (interfaces == NULL)
366 ifaces = split_ifaces (interfaces);
367 length = g_strv_length (ifaces);
369 for (i = 0; i < length; i++)
370 if (!child_interface_p (obj, ifaces [i], ev)){
380 match_interfaces_any_p (Accessibility_Accessible obj, gchar *interfaces, CORBA_Environment *ev){
384 if (interfaces == NULL)
387 ifaces = split_ifaces (interfaces);
388 length = g_strv_length (ifaces);
390 for (i = 0; i < length; i++)
391 if (child_interface_p (obj, ifaces [i], ev)){
400 match_interfaces_none_p (Accessibility_Accessible obj, gchar *interfaces, CORBA_Environment *ev){
402 gchar **ifaces = split_ifaces (interfaces);
403 gint i, length = g_strv_length (ifaces);
408 for (i = 0; i < length; i++)
409 if (child_interface_p (obj, ifaces [i], ev))
418 match_interfaces_lookup (Accessibility_Accessible child, MatchRulePrivate *mrp, CORBA_Environment *ev){
420 switch (mrp->interfacematchtype){
422 case Accessibility_Collection_MATCH_ALL :
423 if (match_interfaces_all_p (child, mrp->interfaces, ev))
427 case Accessibility_Collection_MATCH_ANY :
428 if (match_interfaces_any_p (child, mrp->interfaces, ev))
432 case Accessibility_Collection_MATCH_NONE :
433 if (match_interfaces_none_p (child, mrp->interfaces, ev))
443 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
446 match_attributes_all_p (Accessibility_Accessible child, Accessibility_AttributeSet *attributes, CORBA_Environment *ev){
449 Accessibility_AttributeSet *oa ;
450 gboolean flag = FALSE;
452 if (attributes->_length == 0 || attributes == NULL)
455 oa = Accessibility_Accessible_getAttributes (child, ev);
457 for (i = 0; i < attributes->_length; i++){
458 for (k = 0; k < oa->_length; k++)
459 if (!g_ascii_strcasecmp (oa->_buffer [k], attributes->_buffer [i]))
470 match_attributes_any_p (Accessibility_Accessible child, Accessibility_AttributeSet *attributes, CORBA_Environment *ev){
474 Accessibility_AttributeSet *oa;
476 if (attributes->_length == 0 || attributes == NULL)
479 oa = Accessibility_Accessible_getAttributes (child, ev);
481 for (i = 0; i < attributes->_length; i++)
482 for (k = 0; k < oa->_length; k++)
483 if (!g_ascii_strcasecmp (oa->_buffer [k], attributes->_buffer[i]))
491 match_attributes_none_p (Accessibility_Accessible child, Accessibility_AttributeSet *attributes, CORBA_Environment *ev){
494 Accessibility_AttributeSet *oa;
495 gboolean flag = FALSE;
497 if (attributes->_length == 0 || attributes == NULL)
500 oa = Accessibility_Accessible_getAttributes (child, ev);
502 for (i = 0; i < attributes->_length; i++){
503 for (k = 0; k < oa->_length; k++)
504 if (!g_ascii_strcasecmp (oa->_buffer [k], attributes->_buffer [i]))
518 match_attributes_lookup (Accessibility_Accessible child, MatchRulePrivate *mrp, CORBA_Environment *ev){
520 switch (mrp->attributematchtype){
522 case Accessibility_Collection_MATCH_ALL :
523 if (match_attributes_all_p (child, mrp->attributes, ev))
527 case Accessibility_Collection_MATCH_ANY :
528 if (match_attributes_any_p (child, mrp->attributes, ev))
532 case Accessibility_Collection_MATCH_NONE :
533 if (match_attributes_none_p (child, mrp->attributes, ev))
547 traverse_p (Accessibility_Accessible child,
548 const CORBA_boolean traverse,
549 CORBA_Environment *ev){
553 else return !child_collection_p (child, ev);
558 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
559 gint kount, gint max,
560 Accessibility_Accessible obj, glong index, gboolean flag,
561 Accessibility_Accessible pobj, CORBA_boolean recurse,
562 CORBA_boolean traverse, CORBA_Environment *ev){
565 glong acount = Accessibility_Accessible__get_childCount (obj, ev);
566 gboolean prev = pobj? TRUE : FALSE;
568 for (; i < acount && (max == 0 || kount < max); i++){
569 Accessibility_Accessible child = Accessibility_Accessible_getChildAtIndex (obj, i, ev);
572 if (prev && CORBA_Object_is_equivalent (child, pobj, ev)){
578 if (flag && match_interfaces_lookup (child, mrp, ev) && match_states_lookup (child, mrp, ev)
579 && match_roles_lookup (child, mrp, ev)
580 && match_attributes_lookup (child, mrp, ev)
583 ls = g_list_append (ls, child);
592 if (recurse && traverse_p (child, traverse, ev))
593 kount = sort_order_canonical (mrp, ls, kount, max, child, 0, TRUE, pobj, recurse, traverse, ev);
599 query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
600 GList *ls, gint kount, gint max,
601 Accessibility_Accessible obj, glong index,
603 Accessibility_Accessible pobj,
604 CORBA_boolean recurse, CORBA_boolean traverse,
605 CORBA_Environment *ev){
607 case Accessibility_Collection_SORT_ORDER_CANONICAL : kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag, pobj, recurse, traverse, ev);
609 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
610 kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag, pobj, recurse, traverse, ev);
613 default: kount = 0; g_warning ("Sort method not implemented yet"); break;
621 static Accessibility_AccessibleSet *
622 _accessible_list_to_set (GList *ls, gint kount){
623 Accessibility_AccessibleSet *retval;
626 retval = Accessibility_AccessibleSet__alloc ();
627 retval->_maximum = kount;
628 retval->_length = kount;
629 retval->_buffer = Accessibility_AccessibleSet_allocbuf (kount);
631 for (i=0; i < kount; i++){
632 retval->_buffer [i] = ls->data;
633 ls = g_list_next (ls);
636 CORBA_sequence_set_release (retval, TRUE);
641 static Accessibility_AccessibleSet *
642 impl_getMatchesFrom (PortableServer_Servant servant,
643 const Accessibility_Accessible current_object,
644 const Accessibility_MatchRule rule,
645 const Accessibility_Collection_SortOrder sortby,
646 const CORBA_boolean restrict,
648 const CORBA_boolean traverse,
649 CORBA_Environment *ev){
652 Accessibility_Accessible parent;
653 MatchRulePrivate *mrp;
654 glong index = Accessibility_Accessible_getIndexInParent (current_object, ev);
657 ls = g_list_append (ls, current_object);
658 mrp = get_collection_from_servant (servant)->_mrp;;
661 parent = Accessibility_Accessible__get_parent (current_object, ev);
662 kount = query_exec (mrp, sortby, ls, 0, count, parent, index, FALSE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
666 kount = query_exec (mrp, sortby, ls, 0,count, current_object, 0, FALSE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
669 ls = g_list_next (ls);
671 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
672 ls = g_list_reverse (ls);
674 return _accessible_list_to_set (ls, kount);
678 static Accessibility_AccessibleSet *
679 impl_getMatchesTo (PortableServer_Servant servant,
680 const Accessibility_Accessible current_object,
681 const Accessibility_MatchRule rule,
682 const Accessibility_Collection_SortOrder sortby,
683 const CORBA_boolean restrict,
685 const CORBA_boolean traverse,
686 CORBA_Environment *ev){
691 Accessibility_Accessible obj;
692 MatchRulePrivate *mrp;
696 ls = g_list_append (ls, current_object);
697 mrp = get_collection_from_servant (servant)->_mrp;
701 obj = Accessibility_Accessible__get_parent (current_object, ev);
702 kount = query_exec (mrp, sortby, ls, 0, count, obj, 0, TRUE, current_object, TRUE, traverse, ev);
705 aobj = get_atkobject_from_servant (servant);
706 obj = spi_accessible_new_return (aobj, FALSE, ev);
707 kount = query_exec (mrp, sortby, ls, 0, count, obj, 0, TRUE, current_object, TRUE, traverse, ev);
711 ls = g_list_next (ls);
713 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
714 ls = g_list_reverse (ls);
716 return _accessible_list_to_set (ls, kount);
722 static Accessibility_AccessibleSet *
723 impl_getMatches (PortableServer_Servant servant,
724 const Accessibility_MatchRule rule,
725 const Accessibility_Collection_SortOrder sortby,
727 const CORBA_boolean traverse,
728 CORBA_Environment *ev){
730 AtkObject *aobj = get_atkobject_from_servant (servant);
731 Accessibility_Accessible obj;
732 MatchRulePrivate *mrp;
735 obj = spi_accessible_new_return (aobj, FALSE, ev);
736 ls = g_list_prepend (ls, obj);
737 mrp = get_collection_from_servant (servant)->_mrp;
739 kount = query_exec (mrp, sortby, ls, 0, count, obj, 0, TRUE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
741 ls = g_list_next (ls);
743 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
744 ls = g_list_reverse (ls);
746 return _accessible_list_to_set (ls, kount);
750 spi_collection_class_init (SpiCollectionClass *klass)
753 POA_Accessibility_Collection__epv *epv = &klass->epv;
756 epv->isAncestorOf = impl_isAncestorOf;
759 epv->createMatchRule = impl_createMatchRule;
760 epv->freeMatchRule = impl_freeMatchRule;
761 epv->getMatches = impl_getMatches;
762 epv->getMatchesTo = impl_getMatchesTo;
763 epv->getMatchesFrom = impl_getMatchesFrom;
767 epv->getActiveDescendant = impl_getActiveDescendant;
773 spi_collection_init (SpiCollection *collection)
776 //collection->_mrp = g_new (MatchRulePrivate, 1);
780 BONOBO_TYPE_FUNC_FULL (SpiCollection,
781 Accessibility_Collection,