Changes to introspection generation to remove DOCTYPE and XML
[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
500      if (attributes->_length == 0 || attributes == NULL)
501           return TRUE;
502
503      oa =  Accessibility_Accessible_getAttributes (child, ev);
504
505      for (i = 0; i < attributes->_length; i++){
506           for (k = 0; k < oa->_length; k++)
507                if (!g_ascii_strcasecmp (oa->_buffer [k], 
508                                                attributes->_buffer [i]))
509                     return FALSE;
510      }
511      return TRUE;
512 }
513
514 static gboolean
515 match_attributes_lookup (Accessibility_Accessible child, MatchRulePrivate *mrp, CORBA_Environment *ev){
516
517      switch (mrp->attributematchtype){
518
519           case Accessibility_Collection_MATCH_ALL : 
520           if (match_attributes_all_p (child, mrp->attributes, ev))
521                return TRUE;
522           break;
523           
524      case  Accessibility_Collection_MATCH_ANY :
525           if (match_attributes_any_p (child, mrp->attributes, ev))
526                return TRUE;
527           break;
528           
529      case  Accessibility_Collection_MATCH_NONE :
530           if (match_attributes_none_p (child, mrp->attributes, ev))
531                return TRUE;
532           break;
533
534       default : break;    
535      }
536      return FALSE;   
537 }
538
539 static gboolean
540 traverse_p (Accessibility_Accessible child, 
541             const CORBA_boolean traverse,
542             CORBA_Environment *ev){
543
544   if (traverse)
545     return TRUE;
546   else return !child_collection_p (child, ev);
547 }
548
549 static int 
550 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,                       
551                       gint kount, gint max,
552                       Accessibility_Accessible obj, glong index, gboolean flag,
553                       Accessibility_Accessible pobj, CORBA_boolean recurse, 
554                       CORBA_boolean traverse, CORBA_Environment *ev){
555      gint i = index;
556      glong acount  = Accessibility_Accessible__get_childCount (obj, ev);
557      gboolean prev = pobj? TRUE : FALSE;
558      
559      for (; i < acount && (max == 0 || kount < max); i++){
560           Accessibility_Accessible child = 
561                         Accessibility_Accessible_getChildAtIndex (obj, i, ev);
562
563           if (prev && CORBA_Object_is_equivalent (child, pobj, ev)){
564             return kount;           
565           }
566          
567           if (flag  && match_interfaces_lookup (child, mrp, ev) 
568                     && match_states_lookup (child, mrp, ev)     
569                     && match_roles_lookup (child, mrp, ev)  
570                     && match_attributes_lookup (child, mrp, ev)
571                     ){
572            
573             ls = g_list_append (ls, child);
574             kount++;
575           }
576
577           if (!flag)
578                flag = TRUE;
579
580           if (recurse && traverse_p (child, traverse, ev))
581             kount = sort_order_canonical (mrp, ls,  kount, 
582                                           max, child, 0, TRUE, 
583                                           pobj, recurse, traverse, ev);  
584      }
585      return kount;
586
587
588 static int 
589 sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,                   
590                       gint kount, gint max,
591                       Accessibility_Accessible obj, gboolean flag, 
592                       Accessibility_Accessible pobj, CORBA_Environment *ev){
593     Accessibility_Accessible nextobj;
594     Accessibility_Accessible parent;
595     glong indexinparent;
596
597     /* This breaks us out of the recursion. */
598     if (obj == CORBA_OBJECT_NIL 
599             || CORBA_Object_is_equivalent (obj, pobj, ev))
600     {
601         return kount;           
602     } 
603          
604     /* Add to the list if it matches */
605     if (flag && match_interfaces_lookup (obj, mrp, ev) 
606                && match_states_lookup (obj, mrp, ev)     
607                && match_roles_lookup (obj, mrp, ev)  
608                && match_attributes_lookup (obj, mrp, ev))
609     {
610          ls = g_list_append (ls, obj);
611          kount++;
612     }
613
614     if(!flag) flag = TRUE;
615
616     /* Get the current nodes index in it's parent and the parent object. */
617     indexinparent = Accessibility_Accessible_getIndexInParent (obj, ev);
618     parent = Accessibility_Accessible__get_parent (obj, ev);
619
620     if(indexinparent > 0)
621     {
622          /* there are still some siblings to visit so get the previous sibling
623             and get it's last descendant.
624             First, get the previous sibling */
625          nextobj = Accessibility_Accessible_getChildAtIndex (parent, 
626                                                              indexinparent-1, 
627                                                              ev);
628
629          /* Now, drill down the right side to the last descendant */
630          while(Accessibility_Accessible__get_childCount (nextobj, ev) > 0)
631          {
632               nextobj = Accessibility_Accessible_getChildAtIndex (nextobj, 
633                  Accessibility_Accessible__get_childCount (nextobj, ev)-1, ev);
634
635          } 
636          /* recurse with the last descendant */
637          kount = sort_order_rev_canonical (mrp, ls,  kount, max, 
638                                        nextobj, TRUE, pobj, ev);
639     } 
640     else
641     {
642          /* no more siblings so next node must be the parent */
643          kount = sort_order_rev_canonical (mrp, ls,  kount, max, 
644                                        parent, TRUE, pobj, ev);
645
646     }
647     return kount;
648
649
650 static int
651 query_exec (MatchRulePrivate *mrp,  Accessibility_Collection_SortOrder sortby, 
652             GList *ls, gint kount, gint max, 
653             Accessibility_Accessible obj, glong index, 
654             gboolean flag, 
655             Accessibility_Accessible pobj,
656             CORBA_boolean recurse, CORBA_boolean traverse,
657             CORBA_Environment *ev){
658
659      switch (sortby) {
660      case Accessibility_Collection_SORT_ORDER_CANONICAL :  
661        kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag, 
662                                     pobj, recurse, traverse, ev); 
663        break;
664      case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
665        kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag, 
666                                     pobj, recurse, traverse, ev);    
667        break;
668      default: 
669        kount = 0; 
670        g_warning ("Sort method not implemented yet"); 
671        break; 
672      }
673      
674      return kount;
675
676 }
677
678
679 static Accessibility_AccessibleSet *
680 _accessible_list_to_set (GList *ls, gint kount){
681     Accessibility_AccessibleSet *retval;
682     gint i;
683    
684      retval = Accessibility_AccessibleSet__alloc ();
685      retval->_maximum = kount; 
686      retval->_length = kount; 
687      retval->_buffer = Accessibility_AccessibleSet_allocbuf (kount);
688
689      for (i=0; i < kount; i++){
690        retval->_buffer [i] = ls->data;
691        ls = g_list_next (ls);
692      }
693      
694      CORBA_sequence_set_release (retval, TRUE);
695      
696      return retval;
697 }
698
699 static Accessibility_AccessibleSet *
700 getMatchesFrom (PortableServer_Servant servant,
701                      const Accessibility_Accessible current_object,
702                      const Accessibility_MatchRule rule,
703                      const Accessibility_Collection_SortOrder sortby,
704                      const CORBA_boolean isrestrict,
705                      CORBA_long  count,
706                      const CORBA_boolean traverse,
707                      CORBA_Environment *ev){
708     
709      GList *ls = NULL;
710      Accessibility_Accessible parent; 
711      MatchRulePrivate *mrp;
712      glong index = 
713            Accessibility_Accessible_getIndexInParent (current_object, ev);
714      gint kount = 0;
715
716      ls = g_list_append (ls, current_object);
717      mrp =  get_collection_from_servant (servant)->_mrp;;
718           
719      if (!isrestrict){
720           parent = Accessibility_Accessible__get_parent (current_object, ev);
721           kount = query_exec (mrp,  sortby, ls, 0, count, parent, index, 
722                               FALSE, CORBA_OBJECT_NIL, TRUE, traverse, ev);
723      }
724      else 
725           kount = query_exec (mrp,  sortby, ls, 0, count, 
726                               current_object, 0, FALSE, CORBA_OBJECT_NIL, 
727                               TRUE, traverse, ev);
728
729      ls = g_list_next (ls); 
730
731      if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
732        ls = g_list_reverse (ls);
733  
734      return  _accessible_list_to_set (ls, kount);
735 }
736
737 /*
738   inorder traversal from a given object in the hierarchy
739 */
740
741 static int
742 inorder (Accessibility_Accessible collection, MatchRulePrivate *mrp, 
743         GList *ls, gint kount, gint max,
744         Accessibility_Accessible obj, 
745         gboolean flag,
746         Accessibility_Accessible pobj,
747         CORBA_boolean traverse,
748         CORBA_Environment *ev){
749
750   int i = 0;
751   
752   /* First, look through the children recursively. */
753   kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
754                                 CORBA_OBJECT_NIL, TRUE, TRUE, ev); 
755   
756   /* Next, we look through the right subtree */
757   while ((max == 0 || kount < max) 
758           && ! CORBA_Object_is_equivalent (obj, collection, ev))
759   {
760     Accessibility_Accessible parent =  
761                                 Accessibility_Accessible__get_parent (obj, ev);
762     i = Accessibility_Accessible_getIndexInParent (obj, ev);
763     kount  = sort_order_canonical (mrp, ls, kount, max, parent, 
764                                    i+1, TRUE, FALSE, TRUE, TRUE, ev);
765     obj = parent;
766   }
767
768   if (kount < max)
769   {
770      kount = sort_order_canonical (mrp, ls, kount, max, 
771                                    obj, i + 1, TRUE, FALSE, 
772                                    TRUE, TRUE, ev);
773   }
774
775   return kount;
776 }
777
778 /*
779   GetMatchesInOrder: get matches from a given object in an inorder traversal.
780 */
781
782 static Accessibility_AccessibleSet *
783 getMatchesInOrder (PortableServer_Servant servant,
784                    const Accessibility_Accessible current_object,
785                    const Accessibility_MatchRule rule,
786                    const Accessibility_Collection_SortOrder sortby,
787                    const CORBA_boolean recurse,
788                    CORBA_long count,
789                    const CORBA_boolean traverse, 
790                    CORBA_Environment *ev){
791   GList *ls = NULL;
792   AtkObject *aobj;
793   Accessibility_Accessible obj;
794   MatchRulePrivate *mrp;
795   gint kount = 0;
796
797   ls = g_list_append (ls, current_object);
798   mrp = get_collection_from_servant (servant)->_mrp;
799
800   aobj = get_atkobject_from_servant (servant);
801   obj = spi_accessible_new_return (aobj, FALSE, ev);
802   
803   kount = inorder (obj, mrp, ls, 0, count, 
804                    current_object, TRUE, CORBA_OBJECT_NIL, traverse, ev);
805
806   ls = g_list_next (ls);
807
808   if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
809     ls = g_list_reverse (ls);
810
811   return _accessible_list_to_set (ls, kount); 
812 }
813
814 /*
815   GetMatchesInOrder: get matches from a given object in an inorder traversal.
816 */
817
818 static Accessibility_AccessibleSet *
819 getMatchesInBackOrder (PortableServer_Servant servant,
820                    const Accessibility_Accessible current_object,
821                    const Accessibility_MatchRule rule,
822                    const Accessibility_Collection_SortOrder sortby,
823                    CORBA_long count,
824                    CORBA_Environment *ev){
825   GList *ls = NULL;
826   AtkObject *aobj;
827   Accessibility_Accessible collection;
828   MatchRulePrivate *mrp;
829   gint kount = 0;
830
831   ls = g_list_append (ls, current_object);
832   mrp = get_collection_from_servant (servant)->_mrp;
833
834   aobj = get_atkobject_from_servant (servant);
835   collection = spi_accessible_new_return (aobj, FALSE, ev);
836
837   kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object, 
838                                    FALSE, collection, ev);
839
840   ls = g_list_next (ls);
841
842   if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
843     ls = g_list_reverse (ls);
844
845   return _accessible_list_to_set (ls, kount); 
846 }
847
848
849 static Accessibility_AccessibleSet *
850 getMatchesTo (PortableServer_Servant servant,
851               const Accessibility_Accessible current_object,
852               const Accessibility_MatchRule rule,
853               const Accessibility_Collection_SortOrder sortby,
854               const CORBA_boolean recurse, 
855               const CORBA_boolean isrestrict,
856               CORBA_long  count,
857               const CORBA_boolean traverse,
858               CORBA_Environment *ev){
859
860   GList *ls = NULL;
861   AtkObject *aobj;
862   Accessibility_Accessible obj;
863   MatchRulePrivate *mrp;
864   gint kount = 0;
865
866   ls = g_list_append (ls, current_object); 
867   mrp =  get_collection_from_servant (servant)->_mrp;
868     
869   if (recurse){
870     obj = Accessibility_Accessible__get_parent (current_object, ev);
871     kount =  query_exec (mrp,  sortby, ls, 0, count, 
872                          obj, 0, TRUE, current_object, TRUE, traverse, ev);
873   }
874   else{ 
875     aobj = get_atkobject_from_servant (servant);
876     obj = spi_accessible_new_return (aobj, FALSE, ev);
877     kount = query_exec (mrp,  sortby, ls, 0, count,
878                         obj, 0, TRUE, current_object, TRUE, traverse, ev); 
879
880   }
881
882   ls = g_list_next (ls); 
883    
884   if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
885     ls = g_list_reverse (ls);
886
887   return  _accessible_list_to_set (ls, kount);
888   
889 }
890
891 static Accessibility_AccessibleSet *
892 impl_getMatchesFrom (PortableServer_Servant servant,
893                     const Accessibility_Accessible current_object,
894                     const Accessibility_MatchRule rule,
895                     const Accessibility_Collection_SortOrder sortby,
896                     const Accessibility_Collection_TreeTraversalType tree,
897                     CORBA_long  count,
898                     const CORBA_boolean traverse,
899                     CORBA_Environment *ev){
900
901   switch (tree){
902   case Accessibility_Collection_TREE_RESTRICT_CHILDREN : 
903     return getMatchesFrom (servant, current_object, 
904                            rule, sortby, TRUE, count, traverse, ev); 
905     break;
906   case Accessibility_Collection_TREE_RESTRICT_SIBLING :
907     return getMatchesFrom (servant, current_object, 
908                            rule, sortby, FALSE, count, traverse, ev); 
909     break;
910   case Accessibility_Collection_TREE_INORDER :
911     return getMatchesInOrder (servant, current_object, 
912                               rule, sortby, TRUE, count, traverse, ev); 
913     break;
914   default : return CORBA_OBJECT_NIL;
915   }
916 }
917
918 static Accessibility_AccessibleSet *
919 impl_getMatchesTo (PortableServer_Servant servant,
920                    const Accessibility_Accessible current_object,
921                    const Accessibility_MatchRule rule,
922                    const Accessibility_Collection_SortOrder sortby,
923                    const Accessibility_Collection_TreeTraversalType tree,
924                    const CORBA_boolean recurse,
925                    CORBA_long  count,
926                    const CORBA_boolean traverse,
927                    CORBA_Environment *ev){
928
929   switch (tree){
930   case Accessibility_Collection_TREE_RESTRICT_CHILDREN : 
931     return getMatchesTo (servant, current_object, 
932                          rule, sortby, recurse, TRUE, count, traverse, ev); 
933     break;
934   case Accessibility_Collection_TREE_RESTRICT_SIBLING :
935     return getMatchesTo (servant, current_object, 
936                          rule, sortby, recurse, FALSE, count, traverse, ev); 
937     break;
938   case Accessibility_Collection_TREE_INORDER :
939     return getMatchesInBackOrder (servant, current_object, 
940                                   rule, sortby, count, ev); 
941     break;
942   default : return CORBA_OBJECT_NIL;
943   }
944 }
945
946 static Accessibility_AccessibleSet *
947 impl_getMatches (PortableServer_Servant servant,
948                  const Accessibility_MatchRule rule,
949                  const Accessibility_Collection_SortOrder sortby,
950                  CORBA_long  count,
951                  const CORBA_boolean traverse,
952                  CORBA_Environment *ev){
953      GList *ls = NULL;
954      AtkObject *aobj = get_atkobject_from_servant (servant);
955      Accessibility_Accessible obj;
956      MatchRulePrivate *mrp;
957      gint kount = 0;
958     
959      obj = spi_accessible_new_return (aobj, FALSE, ev);
960      ls = g_list_prepend (ls, obj); 
961      mrp =  get_collection_from_servant (servant)->_mrp;
962      
963      kount = query_exec (mrp,  sortby, ls, 0, count, 
964                          obj, 0, TRUE, CORBA_OBJECT_NIL, TRUE, traverse, ev); 
965
966      ls = g_list_next (ls); 
967     
968      if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
969        ls = g_list_reverse (ls);
970
971      return  _accessible_list_to_set (ls, kount);
972 }
973
974 static void
975 spi_collection_class_init (SpiCollectionClass *klass)
976 {
977
978     POA_Accessibility_Collection__epv *epv  = &klass->epv;
979
980     /*    
981       epv->isAncestorOf = impl_isAncestorOf; 
982     */
983
984     epv->createMatchRule = impl_createMatchRule;
985     epv->freeMatchRule   = impl_freeMatchRule;
986     epv->getMatches      = impl_getMatches;
987     epv->getMatchesTo    = impl_getMatchesTo;
988     epv->getMatchesFrom  = impl_getMatchesFrom;
989     
990
991     /*
992       epv->getActiveDescendant = impl_getActiveDescendant;
993     */
994
995 }
996
997 static void
998 spi_collection_init (SpiCollection *collection)
999 {
1000
1001   /* collection->_mrp = g_new (MatchRulePrivate, 1); */
1002
1003 }
1004
1005 BONOBO_TYPE_FUNC_FULL (SpiCollection,
1006                        Accessibility_Collection,
1007                        SPI_TYPE_BASE,
1008                        spi_collection)
1009