2008-02-27 Ariel Rios <ariel@gnu.org>
[platform/core/uifw/at-spi2-atk.git] / libspi / collection.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2007 IBM Corp.
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /* collection.c: implements the Collection interface */
24
25 #include <config.h>
26 #include <glib.h>
27 #include <stdio.h>
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>
34
35 SpiCollection *
36 spi_collection_interface_new (AtkObject *obj)
37 {
38      SpiCollection *new_collection = g_object_new (SPI_COLLECTION_TYPE, NULL);
39      spi_base_construct (SPI_BASE (new_collection), G_OBJECT (obj));
40
41      return  new_collection;
42 }
43
44 static AtkObject *
45 get_atkobject_from_servant (PortableServer_Servant servant){
46
47   SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
48
49   g_return_val_if_fail (object, NULL);
50   g_return_val_if_fail (ATK_IS_OBJECT (object->gobj), NULL);
51
52   return ATK_OBJECT (object->gobj);
53 }
54
55 static SpiCollection *
56 get_collection_from_servant (PortableServer_Servant servant)
57 {
58      SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
59
60      g_return_val_if_fail (object, NULL);
61      g_return_val_if_fail (IS_COLLECTION (object), NULL);
62
63      return SPI_COLLECTION (object);
64 }
65
66 static Accessibility_MatchRule 
67 impl_createMatchRule (PortableServer_Servant servant,
68                 const Accessibility_StateSet states,
69                 const Accessibility_Collection_MatchType statematchtype,
70                 const Accessibility_AttributeSet *attributes,
71                 const Accessibility_Collection_MatchType attributematchtype,
72                 const Accessibility_RoleSet *roles,
73                 const Accessibility_Collection_MatchType rolematchtype,
74                 const CORBA_char *interfaces,
75                 const Accessibility_Collection_MatchType interfacematchtype,
76                 const CORBA_boolean invert,
77                 CORBA_Environment *ev){
78
79      Accessibility_MatchRule  retval = NULL;
80
81      SpiMatchrule *matchrule = spi_matchrule_interface_new ();
82      MatchRulePrivate *mrp   = get_collection_from_servant (servant)->_mrp;     
83      Accessibility_StateSet ss = CORBA_Object_duplicate (states, ev);
84      gint i;
85
86      if (mrp != NULL){
87        CORBA_free (mrp->attributes);
88        CORBA_free (mrp->roles);
89        CORBA_free (mrp->interfaces);
90
91        g_free (mrp);
92      }
93
94      get_collection_from_servant (servant)->_mrp  = g_new(MatchRulePrivate, 1);
95      mrp   = get_collection_from_servant (servant)->_mrp;
96
97      /* states */
98      mrp->states  = ss;
99      mrp->statematchtype = statematchtype;
100
101      /* attributes */
102      mrp->attributes = CORBA_sequence_CORBA_string__alloc ();
103      mrp->attributes->_maximum = attributes->_maximum;
104      mrp->attributes->_length = attributes->_length;
105      mrp->attributes->_buffer = 
106                    CORBA_sequence_CORBA_string_allocbuf (attributes->_length);
107
108      for (i = 0; i < mrp->attributes->_length; i++)
109           mrp->attributes->_buffer [i] = 
110                    CORBA_string_dup (attributes->_buffer [i]);
111     
112      CORBA_sequence_set_release (mrp->attributes, TRUE);
113      mrp->attributematchtype = attributematchtype;
114
115      /* roles */
116      mrp->roles = Accessibility_RoleSet__alloc ();
117      mrp->roles->_maximum = roles->_maximum;
118      mrp->roles->_length = roles->_length;
119      mrp->roles->_buffer = Accessibility_RoleSet_allocbuf (roles->_length);
120
121      for (i = 0; i < roles->_length; i++)
122           mrp->roles->_buffer [i] = roles->_buffer [i];
123
124      CORBA_sequence_set_release (mrp->roles, TRUE);
125      mrp->rolematchtype = rolematchtype;
126
127      /* interfaces */
128      mrp->interfaces = CORBA_string_dup (interfaces);
129      mrp->interfacematchtype = interfacematchtype;
130
131      mrp->invert = invert;
132
133      retval = CORBA_Object_duplicate (BONOBO_OBJREF (matchrule), ev);
134
135      return retval;
136 }
137
138 static void impl_freeMatchRule (PortableServer_Servant servant,
139                                 Accessibility_MatchRule matchrule,     
140                                 CORBA_Environment *ev){
141
142      SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
143      SpiCollection *spimatchrule;
144
145      MatchRulePrivate *mrp;  
146
147      spimatchrule = SPI_COLLECTION (object);
148      mrp = spimatchrule->_mrp;
149
150      CORBA_free (mrp->attributes);
151      CORBA_free (mrp->roles);     
152      CORBA_free (mrp->interfaces);
153
154      g_free (mrp);
155      spimatchrule->_mrp = NULL;
156 }
157
158 static gboolean
159 child_interface_p (Accessibility_Accessible child, 
160                    gchar *repo_id, 
161                    CORBA_Environment *ev) {
162
163      CORBA_Object retval;
164
165      retval = Bonobo_Unknown_queryInterface (child, repo_id, ev);
166
167      return (retval != CORBA_OBJECT_NIL)? TRUE : FALSE;
168 }
169
170 #define child_collection_p(ch,ev) (child_interface_p (ch,"IDL:Accessibility/Collection:1.0", ev))
171
172 static gboolean
173 match_states_all_p (Accessibility_Accessible child, 
174                     Accessibility_StateSet set,  
175                     CORBA_Environment *ev){
176      
177      Accessibility_StateSet chs  ;
178      Accessibility_StateSeq *seq = Accessibility_StateSet_getStates (set, ev); 
179      gint i;
180
181      if (seq->_length == 0 || seq == NULL)
182           return TRUE;
183
184      chs = Accessibility_Accessible_getState (child, ev);
185
186      for (i = 0; i < seq->_length; i++)
187           if (!Accessibility_StateSet_contains (chs, seq->_buffer [i], ev))
188                return FALSE;
189    
190      return TRUE;
191 }
192
193 static gboolean
194 match_states_any_p  (Accessibility_Accessible child, 
195                      Accessibility_StateSet set,  
196                      CORBA_Environment *ev){
197
198      Accessibility_StateSet chs; 
199      Accessibility_StateSeq *seq = Accessibility_StateSet_getStates (set, ev);
200      gint i;
201
202      if (seq->_length == 0 || seq == NULL)
203           return TRUE;
204
205      chs = Accessibility_Accessible_getState (child, ev);
206
207      for (i = 0; i < seq->_length; i++)
208           if (Accessibility_StateSet_contains (chs, seq->_buffer [i], ev))
209                return TRUE;
210
211      return FALSE;
212 }
213
214 static gboolean
215 match_states_none_p (Accessibility_Accessible child, 
216                      Accessibility_StateSet set,  
217                      CORBA_Environment *ev){
218      
219      Accessibility_StateSet chs; 
220      Accessibility_StateSeq *seq = Accessibility_StateSet_getStates (set, ev);
221      gint i;
222
223      if (seq->_length == 0)
224           return TRUE; 
225      chs = Accessibility_Accessible_getState (child, ev);
226      
227      for (i = 0; i < seq->_length; i++)
228           if (Accessibility_StateSet_contains (chs, seq->_buffer [i], ev))
229                return FALSE;
230
231      return TRUE;
232 }
233
234 static gboolean
235 match_states_lookup (Accessibility_Accessible child,  
236                      MatchRulePrivate *mrp, 
237                      CORBA_Environment *ev){
238
239      switch (mrp->statematchtype){
240      case Accessibility_Collection_MATCH_ALL : 
241           if (match_states_all_p (child, mrp->states, ev))
242                return TRUE;
243           break;
244           
245      case  Accessibility_Collection_MATCH_ANY :
246           if (match_states_any_p (child, mrp->states, ev))
247                return TRUE;
248           break;
249           
250      case  Accessibility_Collection_MATCH_NONE :
251           if (match_states_none_p (child, mrp->states, ev))
252                return TRUE;
253           break;
254
255       default : break;    
256      }
257
258      return FALSE;    
259 }
260
261 static gboolean
262 match_roles_all_p (Accessibility_Accessible child, 
263                    Accessibility_RoleSet *roles,  
264                    CORBA_Environment *ev){
265
266    Accessibility_Role role; 
267
268      if (roles->_length > 1) 
269           return FALSE;
270      else if (roles->_length == 0 || roles == NULL)
271           return TRUE;
272
273      role  = Accessibility_Accessible_getRole (child, ev);
274
275      if (role  == roles->_buffer [0])
276           return TRUE;
277      else 
278           return FALSE;
279     
280 }
281
282 static gboolean
283 match_roles_any_p (Accessibility_Accessible child, 
284                    Accessibility_RoleSet *roles, 
285                    CORBA_Environment *ev){
286
287      Accessibility_Role role; 
288      int i;
289
290      if (roles->_length == 0 || roles == NULL)
291           return TRUE;
292
293      role =  Accessibility_Accessible_getRole (child, ev);
294
295      for (i = 0; i < roles->_length; i++)
296           if (role  == roles->_buffer [i])
297                return TRUE;
298
299      return FALSE;
300 }
301
302 static gboolean
303 match_roles_none_p (Accessibility_Accessible child, 
304                     Accessibility_RoleSet *roles,  
305                     CORBA_Environment *ev){
306
307   Accessibility_Role role ; 
308      int i;
309
310      if (roles->_length == 0 || roles == NULL)
311           return TRUE;
312
313      role =  Accessibility_Accessible_getRole (child, ev);
314
315      for (i = 0; i < roles->_length; i++)
316           if (role == roles->_buffer [i])
317                return FALSE;
318
319      return TRUE;
320 }
321
322 static gboolean
323 match_roles_lookup (Accessibility_Accessible child,  
324                     MatchRulePrivate *mrp, 
325                     CORBA_Environment *ev){
326
327       switch (mrp->rolematchtype){
328          case Accessibility_Collection_MATCH_ALL : 
329               if (match_roles_all_p (child, mrp->roles, ev))
330                    return TRUE;
331               break;
332
333          case  Accessibility_Collection_MATCH_ANY :
334               if (match_roles_any_p (child, mrp->roles, ev))
335                    return TRUE;
336               break;
337
338          case  Accessibility_Collection_MATCH_NONE :
339               if (match_roles_none_p (child, mrp->roles, ev))
340                    return TRUE;
341               break;
342
343       default : break;
344  
345          }
346       return FALSE;
347 }
348
349 #define split_ifaces(ifaces) (g_strsplit (ifaces, ";", 0))
350
351 static gboolean
352 match_interfaces_all_p (Accessibility_Accessible obj, 
353                         gchar *interfaces, 
354                         CORBA_Environment *ev){
355      gchar **ifaces; 
356      gint i, length; 
357
358      if (interfaces == NULL)
359        return TRUE;
360
361      ifaces = split_ifaces (interfaces);
362      length = g_strv_length (ifaces);
363
364      for (i = 0; i < length; i++)
365        if (!child_interface_p (obj, ifaces [i], ev)){
366             g_free (ifaces);
367                return FALSE;
368        }
369      return TRUE;
370 }
371
372 static gboolean
373 match_interfaces_any_p (Accessibility_Accessible obj, 
374                         gchar *interfaces, 
375                         CORBA_Environment *ev){
376      gchar **ifaces; 
377      gint i, length; 
378
379      if (interfaces == NULL)
380        return TRUE;
381
382      ifaces = split_ifaces (interfaces);
383      length = g_strv_length (ifaces);
384
385      for (i = 0; i < length; i++)
386        if (child_interface_p (obj, ifaces [i], ev)){
387                 g_free (ifaces);
388                 return TRUE;
389        }
390      return FALSE;
391 }
392
393 static gboolean
394 match_interfaces_none_p (Accessibility_Accessible obj, 
395                          gchar *interfaces, 
396                          CORBA_Environment *ev){
397
398  gchar **ifaces = split_ifaces (interfaces);
399      gint i, length = g_strv_length (ifaces);
400
401      if (length == 0)
402           return TRUE;
403
404      for (i = 0; i < length; i++)
405            if (child_interface_p (obj, ifaces [i], ev))
406                 return FALSE;
407      
408      return TRUE;
409 }
410
411 static gboolean
412 match_interfaces_lookup (Accessibility_Accessible child, 
413                          MatchRulePrivate *mrp, 
414                          CORBA_Environment *ev){
415
416      switch (mrp->interfacematchtype){
417
418      case Accessibility_Collection_MATCH_ALL : 
419           if (match_interfaces_all_p (child, mrp->interfaces, ev))
420                return TRUE;
421           break;
422
423      case  Accessibility_Collection_MATCH_ANY :
424           if (match_interfaces_any_p (child, mrp->interfaces, ev))
425                return TRUE;
426           break;
427
428      case  Accessibility_Collection_MATCH_NONE :
429           if (match_interfaces_none_p (child, mrp->interfaces, ev))
430                return TRUE;
431           break;
432
433       default : break;    
434      }
435
436      return FALSE;     
437 }
438
439 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
440
441 static gboolean 
442 match_attributes_all_p (Accessibility_Accessible child, 
443                         Accessibility_AttributeSet *attributes, 
444                         CORBA_Environment *ev){
445
446      int i, k;
447      Accessibility_AttributeSet *oa ;
448      gboolean flag = FALSE;
449
450      if (attributes->_length == 0 || attributes == NULL)
451           return TRUE;
452      
453      oa =  Accessibility_Accessible_getAttributes (child, ev);
454
455      for (i = 0; i < attributes->_length; i++){
456           for (k = 0; k < oa->_length; k++)
457                if (!g_ascii_strcasecmp (oa->_buffer [k], 
458                                              attributes->_buffer [i])){
459                     flag = TRUE;
460                     break;
461                }
462                else
463                     flag = FALSE;
464           if (!flag) 
465                return FALSE; 
466      }
467      return TRUE;
468 }
469
470 static gboolean 
471 match_attributes_any_p (Accessibility_Accessible child, 
472                         Accessibility_AttributeSet *attributes, 
473                         CORBA_Environment *ev){
474
475      int i, k;
476
477      Accessibility_AttributeSet *oa;
478
479      if (attributes->_length == 0 || attributes == NULL)
480           return TRUE;
481
482      oa =  Accessibility_Accessible_getAttributes (child, ev);
483
484      for (i = 0; i < attributes->_length; i++)
485           for (k = 0; k < oa->_length; k++)
486                if (!g_ascii_strcasecmp (oa->_buffer [k], 
487                                             attributes->_buffer[i]))
488                     return TRUE;
489      return FALSE;
490 }
491
492 static gboolean 
493 match_attributes_none_p (Accessibility_Accessible child, 
494                          Accessibility_AttributeSet *attributes, 
495                          CORBA_Environment *ev){
496
497      int i, k;
498      Accessibility_AttributeSet *oa;
499      gboolean flag = FALSE;
500
501      if (attributes->_length == 0 || attributes == NULL)
502           return TRUE;
503
504      oa =  Accessibility_Accessible_getAttributes (child, ev);
505
506      for (i = 0; i < attributes->_length; i++){
507           for (k = 0; k < oa->_length; k++)
508                if (!g_ascii_strcasecmp (oa->_buffer [k], 
509                                                attributes->_buffer [i]))
510                     return FALSE;
511      }
512      return TRUE;
513 }
514
515 static gboolean
516 match_attributes_lookup (Accessibility_Accessible child, MatchRulePrivate *mrp, CORBA_Environment *ev){
517
518      switch (mrp->attributematchtype){
519
520           case Accessibility_Collection_MATCH_ALL : 
521           if (match_attributes_all_p (child, mrp->attributes, ev))
522                return TRUE;
523           break;
524           
525      case  Accessibility_Collection_MATCH_ANY :
526           if (match_attributes_any_p (child, mrp->attributes, ev))
527                return TRUE;
528           break;
529           
530      case  Accessibility_Collection_MATCH_NONE :
531           if (match_attributes_none_p (child, mrp->attributes, ev))
532                return TRUE;
533           break;
534
535       default : break;    
536      }
537      return FALSE;   
538 }
539
540 static gboolean
541 traverse_p (Accessibility_Accessible child, 
542             const CORBA_boolean traverse,
543             CORBA_Environment *ev){
544
545   if (traverse)
546     return TRUE;
547   else return !child_collection_p (child, ev);
548 }
549
550 static int 
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){
556      gint i = index;
557      glong acount  = Accessibility_Accessible__get_childCount (obj, ev);
558      gboolean prev = pobj? TRUE : FALSE;
559      
560      for (; i < acount && (max == 0 || kount < max); i++){
561           Accessibility_Accessible child = 
562                         Accessibility_Accessible_getChildAtIndex (obj, i, ev);
563
564           if (prev && CORBA_Object_is_equivalent (child, pobj, ev)){
565             return kount;           
566           }
567          
568           if (flag  && match_interfaces_lookup (child, mrp, ev) 
569                     && match_states_lookup (child, mrp, ev)     
570                     && match_roles_lookup (child, mrp, ev)  
571                     && match_attributes_lookup (child, mrp, ev)
572                     ){
573            
574             ls = g_list_append (ls, child);
575             kount++;
576           }
577
578           if (!flag)
579                flag = TRUE;
580
581           if (recurse && traverse_p (child, traverse, ev))
582             kount = sort_order_canonical (mrp, ls,  kount, 
583                                           max, child, 0, TRUE, 
584                                           pobj, recurse, traverse, ev);  
585      }
586      return kount;
587
588
589 static int 
590 sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,                   
591                       gint kount, gint max,
592                       Accessibility_Accessible obj, gboolean flag, 
593                       Accessibility_Accessible pobj, CORBA_Environment *ev){
594     Accessibility_Accessible nextobj;
595     Accessibility_Accessible parent;
596     glong indexinparent;
597
598     /* This breaks us out of the recursion. */
599     if (obj == CORBA_OBJECT_NIL 
600             || CORBA_Object_is_equivalent (obj, pobj, ev))
601     {
602         return kount;           
603     } 
604          
605     /* Add to the list if it matches */
606     if (flag && match_interfaces_lookup (obj, mrp, ev) 
607                && match_states_lookup (obj, mrp, ev)     
608                && match_roles_lookup (obj, mrp, ev)  
609                && match_attributes_lookup (obj, mrp, ev))
610     {
611          ls = g_list_append (ls, obj);
612          kount++;
613     }
614
615     if(!flag) flag = TRUE;
616
617     /* Get the current nodes index in it's parent and the parent object. */
618     indexinparent = Accessibility_Accessible_getIndexInParent (obj, ev);
619     parent = Accessibility_Accessible__get_parent (obj, ev);
620
621     if(indexinparent > 0)
622     {
623          /* there are still some siblings to visit so get the previous sibling
624             and get it's last descendant.
625             First, get the previous sibling */
626          nextobj = Accessibility_Accessible_getChildAtIndex (parent, 
627                                                              indexinparent-1, 
628                                                              ev);
629
630          /* Now, drill down the right side to the last descendant */
631          while(Accessibility_Accessible__get_childCount (nextobj, ev) > 0)
632          {
633               nextobj = Accessibility_Accessible_getChildAtIndex (nextobj, 
634                  Accessibility_Accessible__get_childCount (nextobj, ev)-1, ev);
635
636          } 
637          /* recurse with the last descendant */
638          kount = sort_order_rev_canonical (mrp, ls,  kount, max, 
639                                        nextobj, TRUE, pobj, ev);
640     } 
641     else
642     {
643          /* no more siblings so next node must be the parent */
644          kount = sort_order_rev_canonical (mrp, ls,  kount, max, 
645                                        parent, TRUE, pobj, ev);
646
647     }
648     return kount;
649
650
651 static int
652 query_exec (MatchRulePrivate *mrp,  Accessibility_Collection_SortOrder sortby, 
653             GList *ls, gint kount, gint max, 
654             Accessibility_Accessible obj, glong index, 
655             gboolean flag, 
656             Accessibility_Accessible pobj,
657             CORBA_boolean recurse, CORBA_boolean traverse,
658             CORBA_Environment *ev){
659
660      switch (sortby) {
661      case Accessibility_Collection_SORT_ORDER_CANONICAL :  
662        kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag, 
663                                     pobj, recurse, traverse, ev); 
664        break;
665      case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
666        kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag, 
667                                     pobj, recurse, traverse, ev);    
668        break;
669      default: 
670        kount = 0; 
671        g_warning ("Sort method not implemented yet"); 
672        break; 
673      }
674      
675      return kount;
676
677 }
678
679
680 static Accessibility_AccessibleSet *
681 _accessible_list_to_set (GList *ls, gint kount){
682     Accessibility_AccessibleSet *retval;
683     gint i;
684    
685      retval = Accessibility_AccessibleSet__alloc ();
686      retval->_maximum = kount; 
687      retval->_length = kount; 
688      retval->_buffer = Accessibility_AccessibleSet_allocbuf (kount);
689
690      for (i=0; i < kount; i++){
691        retval->_buffer [i] = ls->data;
692        ls = g_list_next (ls);
693      }
694      
695      CORBA_sequence_set_release (retval, TRUE);
696      
697      return retval;
698 }
699
700 static Accessibility_AccessibleSet *
701 getMatchesFrom (PortableServer_Servant servant,
702                      const Accessibility_Accessible current_object,
703                      const Accessibility_MatchRule rule,
704                      const Accessibility_Collection_SortOrder sortby,
705                      const CORBA_boolean isrestrict,
706                      CORBA_long  count,
707                      const CORBA_boolean traverse,
708                      CORBA_Environment *ev){
709     
710      GList *ls = NULL;
711      Accessibility_Accessible parent; 
712      MatchRulePrivate *mrp;
713      glong index = 
714            Accessibility_Accessible_getIndexInParent (current_object, ev);
715      gint kount = 0;
716
717      ls = g_list_append (ls, current_object);
718      mrp =  get_collection_from_servant (servant)->_mrp;;
719           
720      if (!isrestrict){
721           parent = Accessibility_Accessible__get_parent (current_object, ev);
722           kount = query_exec (mrp,  sortby, ls, 0, count, parent, index, 
723                               FALSE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
724      }
725      else 
726           kount = query_exec (mrp,  sortby, ls, 0, count, 
727                               current_object, 0, FALSE, CORBA_OBJECT_NIL, 
728                               TRUE, traverse, ev);
729
730      ls = g_list_next (ls); 
731
732      if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
733        ls = g_list_reverse (ls);
734  
735      return  _accessible_list_to_set (ls, kount);
736 }
737
738 /*
739   inorder traversal from a given object in the hierarchy
740 */
741
742 static int
743 inorder (Accessibility_Accessible collection, MatchRulePrivate *mrp, 
744         GList *ls, gint kount, gint max,
745         Accessibility_Accessible obj, 
746         gboolean flag,
747         Accessibility_Accessible pobj,
748         CORBA_boolean traverse,
749         CORBA_Environment *ev){
750
751   int i = 0;
752   
753   /* First, look through the children recursively. */
754   kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
755                                 CORBA_OBJECT_NIL, TRUE, TRUE, ev); 
756   
757   /* Next, we look through the right subtree */
758   while ((max == 0 || kount < max) 
759           && ! CORBA_Object_is_equivalent (obj, collection, ev))
760   {
761
762     i = Accessibility_Accessible_getIndexInParent (obj, ev);
763     Accessibility_Accessible parent =  
764                                 Accessibility_Accessible__get_parent (obj, ev);
765     kount  = sort_order_canonical (mrp, ls, kount, max, parent, 
766                                    i+1, TRUE, FALSE, TRUE, TRUE, ev);
767     obj = parent;
768   }
769
770   if (kount < max)
771   {
772      kount = sort_order_canonical (mrp, ls, kount, max, 
773                                    obj, i + 1, TRUE, FALSE, 
774                                    TRUE, TRUE, ev);
775   }
776
777   return kount;
778 }
779
780 /*
781   GetMatchesInOrder: get matches from a given object in an inorder traversal.
782 */
783
784 static Accessibility_AccessibleSet *
785 getMatchesInOrder (PortableServer_Servant servant,
786                    const Accessibility_Accessible current_object,
787                    const Accessibility_MatchRule rule,
788                    const Accessibility_Collection_SortOrder sortby,
789                    const CORBA_boolean recurse,
790                    CORBA_long count,
791                    const CORBA_boolean traverse, 
792                    CORBA_Environment *ev){
793   GList *ls = NULL;
794   AtkObject *aobj;
795   Accessibility_Accessible obj, collection;
796   MatchRulePrivate *mrp;
797   gint kount = 0;
798
799   ls = g_list_append (ls, current_object);
800   mrp = get_collection_from_servant (servant)->_mrp;
801
802   aobj = get_atkobject_from_servant (servant);
803   obj = spi_accessible_new_return (aobj, FALSE, ev);
804   
805   kount = inorder (obj, mrp, ls, 0, count, 
806                    current_object, TRUE, CORBA_OBJECT_NIL, traverse, ev);
807
808   ls = g_list_next (ls);
809
810   if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
811     ls = g_list_reverse (ls);
812
813   return _accessible_list_to_set (ls, kount); 
814 }
815
816 /*
817   GetMatchesInOrder: get matches from a given object in an inorder traversal.
818 */
819
820 static Accessibility_AccessibleSet *
821 getMatchesInBackOrder (PortableServer_Servant servant,
822                    const Accessibility_Accessible current_object,
823                    const Accessibility_MatchRule rule,
824                    const Accessibility_Collection_SortOrder sortby,
825                    CORBA_long count,
826                    CORBA_Environment *ev){
827   GList *ls = NULL;
828   AtkObject *aobj;
829   Accessibility_Accessible collection;
830   MatchRulePrivate *mrp;
831   gint kount = 0;
832
833   ls = g_list_append (ls, current_object);
834   mrp = get_collection_from_servant (servant)->_mrp;
835
836   aobj = get_atkobject_from_servant (servant);
837   collection = spi_accessible_new_return (aobj, FALSE, ev);
838
839   kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object, 
840                                    FALSE, collection, ev);
841
842   ls = g_list_next (ls);
843
844   if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
845     ls = g_list_reverse (ls);
846
847   return _accessible_list_to_set (ls, kount); 
848 }
849
850
851 static Accessibility_AccessibleSet *
852 getMatchesTo (PortableServer_Servant servant,
853               const Accessibility_Accessible current_object,
854               const Accessibility_MatchRule rule,
855               const Accessibility_Collection_SortOrder sortby,
856               const CORBA_boolean recurse, 
857               const CORBA_boolean isrestrict,
858               CORBA_long  count,
859               const CORBA_boolean traverse,
860               CORBA_Environment *ev){
861
862   GList *ls = NULL;
863   AtkObject *aobj;
864   Accessibility_Accessible obj;
865   MatchRulePrivate *mrp;
866   gint kount = 0;
867
868   ls = g_list_append (ls, current_object); 
869   mrp =  get_collection_from_servant (servant)->_mrp;
870     
871   if (recurse){
872     obj = Accessibility_Accessible__get_parent (current_object, ev);
873     kount =  query_exec (mrp,  sortby, ls, 0, count, 
874                          obj, 0, TRUE, current_object, TRUE, traverse, ev);
875   }
876   else{ 
877     aobj = get_atkobject_from_servant (servant);
878     obj = spi_accessible_new_return (aobj, FALSE, ev);
879     kount = query_exec (mrp,  sortby, ls, 0, count,
880                         obj, 0, TRUE, current_object, TRUE, traverse, ev); 
881
882   }
883
884   ls = g_list_next (ls); 
885    
886   if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
887     ls = g_list_reverse (ls);
888
889   return  _accessible_list_to_set (ls, kount);
890   
891 }
892
893 static Accessibility_AccessibleSet *
894 impl_getMatchesFrom (PortableServer_Servant servant,
895                     const Accessibility_Accessible current_object,
896                     const Accessibility_MatchRule rule,
897                     const Accessibility_Collection_SortOrder sortby,
898                     const Accessibility_Collection_TreeTraversalType tree,
899                     CORBA_long  count,
900                     const CORBA_boolean traverse,
901                     CORBA_Environment *ev){
902
903   switch (tree){
904   case Accessibility_Collection_TREE_RESTRICT_CHILDREN : 
905     return getMatchesFrom (servant, current_object, 
906                            rule, sortby, TRUE, count, traverse, ev); 
907     break;
908   case Accessibility_Collection_TREE_RESTRICT_SIBLING :
909     return getMatchesFrom (servant, current_object, 
910                            rule, sortby, FALSE, count, traverse, ev); 
911     break;
912   case Accessibility_Collection_TREE_INORDER :
913     return getMatchesInOrder (servant, current_object, 
914                               rule, sortby, TRUE, count, traverse, ev); 
915     break;
916   default : return CORBA_OBJECT_NIL;
917   }
918 }
919
920 static Accessibility_AccessibleSet *
921 impl_getMatchesTo (PortableServer_Servant servant,
922                    const Accessibility_Accessible current_object,
923                    const Accessibility_MatchRule rule,
924                    const Accessibility_Collection_SortOrder sortby,
925                    const Accessibility_Collection_TreeTraversalType tree,
926                    const CORBA_boolean recurse,
927                    CORBA_long  count,
928                    const CORBA_boolean traverse,
929                    CORBA_Environment *ev){
930
931   switch (tree){
932   case Accessibility_Collection_TREE_RESTRICT_CHILDREN : 
933     return getMatchesTo (servant, current_object, 
934                          rule, sortby, recurse, TRUE, count, traverse, ev); 
935     break;
936   case Accessibility_Collection_TREE_RESTRICT_SIBLING :
937     return getMatchesTo (servant, current_object, 
938                          rule, sortby, recurse, FALSE, count, traverse, ev); 
939     break;
940   case Accessibility_Collection_TREE_INORDER :
941     return getMatchesInBackOrder (servant, current_object, 
942                                   rule, sortby, count, ev); 
943     break;
944   default : return CORBA_OBJECT_NIL;
945   }
946 }
947
948 static Accessibility_AccessibleSet *
949 impl_getMatches (PortableServer_Servant servant,
950                  const Accessibility_MatchRule rule,
951                  const Accessibility_Collection_SortOrder sortby,
952                  CORBA_long  count,
953                  const CORBA_boolean traverse,
954                  CORBA_Environment *ev){
955      GList *ls = NULL;
956      AtkObject *aobj = get_atkobject_from_servant (servant);
957      Accessibility_Accessible obj;
958      MatchRulePrivate *mrp;
959      gint kount = 0;
960     
961      obj = spi_accessible_new_return (aobj, FALSE, ev);
962      ls = g_list_prepend (ls, obj); 
963      mrp =  get_collection_from_servant (servant)->_mrp;
964      
965      kount = query_exec (mrp,  sortby, ls, 0, count, 
966                          obj, 0, TRUE, CORBA_OBJECT_NIL, TRUE, traverse, ev); 
967
968      ls = g_list_next (ls); 
969     
970      if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
971        ls = g_list_reverse (ls);
972
973      return  _accessible_list_to_set (ls, kount);
974 }
975
976 static void
977 spi_collection_class_init (SpiCollectionClass *klass)
978 {
979
980     POA_Accessibility_Collection__epv *epv  = &klass->epv;
981
982     /*    
983       epv->isAncestorOf = impl_isAncestorOf; 
984     */
985
986     epv->createMatchRule = impl_createMatchRule;
987     epv->freeMatchRule   = impl_freeMatchRule;
988     epv->getMatches      = impl_getMatches;
989     epv->getMatchesTo    = impl_getMatchesTo;
990     epv->getMatchesFrom  = impl_getMatchesFrom;
991     
992
993     /*
994       epv->getActiveDescendant = impl_getActiveDescendant;
995     */
996
997 }
998
999 static void
1000 spi_collection_init (SpiCollection *collection)
1001 {
1002
1003   /* collection->_mrp = g_new (MatchRulePrivate, 1); */
1004
1005 }
1006
1007 BONOBO_TYPE_FUNC_FULL (SpiCollection,
1008                        Accessibility_Collection,
1009                        SPI_TYPE_BASE,
1010                        spi_collection)
1011