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);
164 spimatchrule->_mrp = NULL;
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])){
472 match_attributes_any_p (Accessibility_Accessible child, Accessibility_AttributeSet *attributes, CORBA_Environment *ev){
476 Accessibility_AttributeSet *oa;
478 if (attributes->_length == 0 || attributes == NULL)
481 oa = Accessibility_Accessible_getAttributes (child, ev);
483 for (i = 0; i < attributes->_length; i++)
484 for (k = 0; k < oa->_length; k++)
485 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]))
511 match_attributes_lookup (Accessibility_Accessible child, MatchRulePrivate *mrp, CORBA_Environment *ev){
513 switch (mrp->attributematchtype){
515 case Accessibility_Collection_MATCH_ALL :
516 if (match_attributes_all_p (child, mrp->attributes, ev))
520 case Accessibility_Collection_MATCH_ANY :
521 if (match_attributes_any_p (child, mrp->attributes, ev))
525 case Accessibility_Collection_MATCH_NONE :
526 if (match_attributes_none_p (child, mrp->attributes, ev))
540 traverse_p (Accessibility_Accessible child,
541 const CORBA_boolean traverse,
542 CORBA_Environment *ev){
546 else return !child_collection_p (child, ev);
551 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
552 gint kount, gint max,
553 Accessibility_Accessible obj, glong index, gboolean flag,
554 Accessibility_Accessible pobj, CORBA_boolean recurse,
555 CORBA_boolean traverse, CORBA_Environment *ev){
558 glong acount = Accessibility_Accessible__get_childCount (obj, ev);
559 gboolean prev = pobj? TRUE : FALSE;
561 for (; i < acount && (max == 0 || kount < max); i++){
562 Accessibility_Accessible child = Accessibility_Accessible_getChildAtIndex (obj, i, ev);
565 if (prev && CORBA_Object_is_equivalent (child, pobj, ev)){
571 if (flag && match_interfaces_lookup (child, mrp, ev) && match_states_lookup (child, mrp, ev)
572 && match_roles_lookup (child, mrp, ev)
573 && match_attributes_lookup (child, mrp, ev)
576 ls = g_list_append (ls, child);
585 if (recurse && traverse_p (child, traverse, ev))
586 kount = sort_order_canonical (mrp, ls, kount, max, child, 0, TRUE, pobj, recurse, traverse, ev);
592 query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
593 GList *ls, gint kount, gint max,
594 Accessibility_Accessible obj, glong index,
596 Accessibility_Accessible pobj,
597 CORBA_boolean recurse, CORBA_boolean traverse,
598 CORBA_Environment *ev){
600 case Accessibility_Collection_SORT_ORDER_CANONICAL : kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag, pobj, recurse, traverse, ev);
602 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
603 kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag, pobj, recurse, traverse, ev);
606 default: kount = 0; g_warning ("Sort method not implemented yet"); break;
614 static Accessibility_AccessibleSet *
615 _accessible_list_to_set (GList *ls, gint kount){
616 Accessibility_AccessibleSet *retval;
619 retval = Accessibility_AccessibleSet__alloc ();
620 retval->_maximum = kount;
621 retval->_length = kount;
622 retval->_buffer = Accessibility_AccessibleSet_allocbuf (kount);
624 for (i=0; i < kount; i++){
625 retval->_buffer [i] = ls->data;
626 ls = g_list_next (ls);
629 CORBA_sequence_set_release (retval, TRUE);
634 static Accessibility_AccessibleSet *
635 impl_getMatchesFrom (PortableServer_Servant servant,
636 const Accessibility_Accessible current_object,
637 const Accessibility_MatchRule rule,
638 const Accessibility_Collection_SortOrder sortby,
639 const CORBA_boolean isrestrict,
641 const CORBA_boolean traverse,
642 CORBA_Environment *ev){
645 Accessibility_Accessible parent;
646 MatchRulePrivate *mrp;
647 glong index = Accessibility_Accessible_getIndexInParent (current_object, ev);
650 ls = g_list_append (ls, current_object);
651 mrp = get_collection_from_servant (servant)->_mrp;;
654 parent = Accessibility_Accessible__get_parent (current_object, ev);
655 kount = query_exec (mrp, sortby, ls, 0, count, parent, index, FALSE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
659 kount = query_exec (mrp, sortby, ls, 0,count, current_object, 0, FALSE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
662 ls = g_list_next (ls);
664 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
665 ls = g_list_reverse (ls);
667 return _accessible_list_to_set (ls, kount);
671 static Accessibility_AccessibleSet *
672 impl_getMatchesTo (PortableServer_Servant servant,
673 const Accessibility_Accessible current_object,
674 const Accessibility_MatchRule rule,
675 const Accessibility_Collection_SortOrder sortby,
676 const CORBA_boolean recurse,
678 const CORBA_boolean traverse,
679 CORBA_Environment *ev){
684 Accessibility_Accessible obj;
685 MatchRulePrivate *mrp;
689 ls = g_list_append (ls, current_object);
690 mrp = get_collection_from_servant (servant)->_mrp;
694 obj = Accessibility_Accessible__get_parent (current_object, ev);
695 kount = query_exec (mrp, sortby, ls, 0, count, obj, 0, TRUE, current_object, TRUE, traverse, ev);
698 aobj = get_atkobject_from_servant (servant);
699 obj = spi_accessible_new_return (aobj, FALSE, ev);
700 kount = query_exec (mrp, sortby, ls, 0, count, obj, 0, TRUE, current_object, TRUE, traverse, ev);
704 ls = g_list_next (ls);
706 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
707 ls = g_list_reverse (ls);
709 return _accessible_list_to_set (ls, kount);
715 static Accessibility_AccessibleSet *
716 impl_getMatches (PortableServer_Servant servant,
717 const Accessibility_MatchRule rule,
718 const Accessibility_Collection_SortOrder sortby,
720 const CORBA_boolean traverse,
721 CORBA_Environment *ev){
723 AtkObject *aobj = get_atkobject_from_servant (servant);
724 Accessibility_Accessible obj;
725 MatchRulePrivate *mrp;
728 obj = spi_accessible_new_return (aobj, FALSE, ev);
729 ls = g_list_prepend (ls, obj);
730 mrp = get_collection_from_servant (servant)->_mrp;
732 kount = query_exec (mrp, sortby, ls, 0, count, obj, 0, TRUE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
734 ls = g_list_next (ls);
736 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
737 ls = g_list_reverse (ls);
739 return _accessible_list_to_set (ls, kount);
743 spi_collection_class_init (SpiCollectionClass *klass)
746 POA_Accessibility_Collection__epv *epv = &klass->epv;
749 epv->isAncestorOf = impl_isAncestorOf;
752 epv->createMatchRule = impl_createMatchRule;
753 epv->freeMatchRule = impl_freeMatchRule;
754 epv->getMatches = impl_getMatches;
755 epv->getMatchesTo = impl_getMatchesTo;
756 epv->getMatchesFrom = impl_getMatchesFrom;
760 epv->getActiveDescendant = impl_getActiveDescendant;
766 spi_collection_init (SpiCollection *collection)
769 //collection->_mrp = g_new (MatchRulePrivate, 1);
773 BONOBO_TYPE_FUNC_FULL (SpiCollection,
774 Accessibility_Collection,