1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 package ifc.accessibility;
24 
25 import java.util.Vector;
26 
27 import lib.MultiMethodTest;
28 
29 import com.sun.star.accessibility.XAccessible;
30 import com.sun.star.accessibility.XAccessibleComponent;
31 import com.sun.star.accessibility.XAccessibleContext;
32 import com.sun.star.awt.Point;
33 import com.sun.star.awt.Rectangle;
34 import com.sun.star.awt.Size;
35 import com.sun.star.uno.UnoRuntime;
36 
37 
38 /**
39  * Testing <code>com.sun.star.accessibility.XAccessibleComponent</code>
40  * interface methods :
41  * <ul>
42  *  <li><code> containsPoint()</code></li>
43  *  <li><code> getAccessibleAtPoint()</code></li>
44  *  <li><code> getBounds()</code></li>
45  *  <li><code> getLocation()</code></li>
46  *  <li><code> getLocationOnScreen()</code></li>
47  *  <li><code> getSize()</code></li>
48  *  <li><code> grabFocus()</code></li>
49  *  <li><code> getAccessibleKeyBinding()</code></li>
50  * </ul> <p>
51  *
52  * @see com.sun.star.accessibility.XAccessibleComponent
53  */
54 public class _XAccessibleComponent extends MultiMethodTest {
55 
56     public XAccessibleComponent oObj = null;
57     private Rectangle bounds = null;
58     private Vector KnownBounds = new Vector();
59 
60 
61     /**
62      * First checks 4 inner bounds (upper, lower, left and right)
63      * of component bounding box to contain
64      * at least one point of the component. Second 4 outer bounds
65      * are checked to not contain any component points.<p>
66      *
67      * Has <b> OK </b> status if inner bounds contain component points
68      * and outer bounds don't contain any component points. <p>
69      *
70      * The following method tests are to be completed successfully before :
71      * <ul>
72      *  <li> <code> getBounds() </code> : to have size of a component.</li>
73      * </ul>
74      */
75     public void _containsPoint() {
76         requiredMethod("getBounds()");
77 
78         boolean result = true;
79 
80         int curX = 0;
81 
82         //while (!oObj.containsPoint(new Point(curX, bounds.Y)) && curX < bounds.Width+bounds.X) {
83         while (!oObj.containsPoint(new Point(curX, 0)) &&
84                (curX < bounds.Width)) {
85             curX++;
86         }
87 
88         //if ((bounds.X <= curX) && (curX < bounds.Width+bounds.X)) {
89         if (curX < bounds.Width) {
90             log.println("Upper bound of box containsPoint point (" + curX +
91                         ",0) - OK");
92         } else {
93             log.println(
94                     "Upper bound of box containsPoint no component points - FAILED");
95             result = false;
96         }
97 
98         curX = 0;
99 
100         //while (!oObj.containsPoint(new Point(curX, bounds.Y+bounds.Height - 1))
101         while (!oObj.containsPoint(new Point(curX, bounds.Height - 1)) &&
102                (curX < bounds.Width)) {
103             log.println("containsPoint returns false for (" + curX + "," +
104                         bounds.Height + ")");
105             curX++;
106         }
107 
108         //if ((bounds.X <= curX) && (curX < bounds.Width+bounds.X)) {
109         if (curX < bounds.Width) {
110             log.println("Lower bound of box containsPoint point (" + curX +
111                         "," + (bounds.Height - 1) + ") - OK");
112         } else {
113             log.println(
114                     "Lower bound of box containsPoint no component points - FAILED");
115             result = false;
116         }
117 
118         int curY = 0;
119 
120         //while (!oObj.containsPoint(new Point(bounds.X, curY)) && curY < bounds.Height+bounds.Y) {
121         while (!oObj.containsPoint(new Point(0, curY)) &&
122                (curY < bounds.Height)) {
123             curY++;
124         }
125 
126         //if ((bounds.Y <= curY) && (curY < bounds.Height+bounds.Y)) {
127         if (curY < bounds.Height) {
128             log.println("Left bound of box containsPoint point (0," + curY +
129                         ") - OK");
130         } else {
131             log.println(
132                     "Left bound of box containsPoint no component points - FAILED");
133             result = false;
134         }
135 
136         curY = 0;
137 
138         //while (!oObj.containsPoint(new Point(bounds.X+bounds.Width - 1, curY))
139         //       && curY < bounds.Height+bounds.Y) {
140         while (!oObj.containsPoint(new Point(bounds.Width - 1, curY)) &&
141                (curY < bounds.Height)) {
142             curY++;
143         }
144 
145         //if ((bounds.Y <= curY) && (curY < bounds.Height + bounds.Y)) {
146         if (curY < bounds.Height) {
147             log.println("Right bound of box containsPoint point (" +
148                         (bounds.Width - 1) + "," + curY + ") - OK");
149         } else {
150             log.println(
151                     "Right bound of box containsPoint no component points - FAILED");
152             result = false;
153         }
154 
155         boolean locRes = true;
156 
157         for (int x = -1; x <= bounds.Width; x++) {
158             if (oObj.containsPoint(new Point(x, -1))) {
159                 log.println(
160                     "Outer upper and lower bounds CONTAIN some component point"
161                     + " (" + x + ", -1) - FAILED");
162                 locRes = false;
163                 break;
164             }
165             if (oObj.containsPoint(new Point(x, bounds.Height + bounds.Y))) {
166                 log.println(
167                     "Outer upper and lower bounds CONTAIN some component point"
168                     + " (" + x + ", " + bounds.Height + bounds.Y
169                     + ") - FAILED");
170                 locRes = false;
171                 break;
172             }
173         }
174 
175         if (locRes) {
176             log.println("Outer upper and lower bounds contain no component " +
177                         "points - OK");
178         } else {
179             result = false;
180         }
181 
182         locRes = true;
183 
184         for (int y = -1; y <= bounds.Height; y++) {
185             if (oObj.containsPoint(new Point(-1, y))) {
186                 log.println(
187                     "Outer left and right bounds CONTAIN some component point"
188                     + " (-1, " + y + ") - FAILED");
189                 locRes = false;
190                 break;
191             }
192             if (oObj.containsPoint(new Point(bounds.X + bounds.Width, y))) {
193                 log.println(
194                     "Outer left and right bounds CONTAIN some component point"
195                     + " (" + bounds.X + bounds.Width + ", " + y + ") - FAILED");
196                 locRes = false;
197                 break;
198             }
199         }
200 
201         if (locRes) {
202             log.println("Outer left and right bounds contain no component " +
203                         "points - OK");
204         } else {
205             result = false;
206         }
207 
208         tRes.tested("containsPoint()", result);
209     }
210 
211     /**
212      * Iterates through all children which implement
213      * <code>XAccessibleComponent</code> (if they exist) determines their
214      * boundaries and tries to get each child by <code>getAccessibleAtPoint</code>
215      * passing point which belongs to the child.
216      * Also the point is checked which doesn't belong to child boundary
217      * box. <p>
218      *
219      * Has <b> OK </b> status if in the first cases the right children
220      * are returned, and in the second <code>null</code> or
221      * another child is returned.
222      */
223     public void _getAccessibleAtPoint() {
224         boolean result = true;
225         XAccessibleComponent[] children = getChildrenComponents();
226 
227         if (children.length > 0) {
228             for (int i = 0; i < children.length; i++) {
229                 Rectangle chBnd = children[i].getBounds();
230 
231                 if (chBnd.X == -1) {
232                     continue;
233                 }
234 
235                 log.println("Checking child with bounds " + "(" + chBnd.X +
236                             "," + chBnd.Y + "),(" + chBnd.Width + "," +
237                             chBnd.Height + "): " +
238                             util.AccessibilityTools.accessibleToString(
239                                     children[i]));
240 
241                 XAccessibleContext xAc = (XAccessibleContext) UnoRuntime.queryInterface(
242                                                  XAccessibleContext.class,
243                                                  children[i]);
244 
245                 boolean MightBeCovered = false;
246                 boolean isShowing = xAc.getAccessibleStateSet()
247                                        .contains(com.sun.star.accessibility.AccessibleStateType.SHOWING);
248                 log.println("\tStateType containsPoint SHOWING: " +
249                             isShowing);
250 
251                 if (!isShowing) {
252                     log.println("Child is invisible - OK");
253 
254                     continue;
255                 }
256 
257                 log.println("finding the point which lies on the component");
258 
259                 int curX = chBnd.Width / 2;
260                 int curY = chBnd.Height / 2;
261 
262                 while (!children[i].containsPoint(new Point(curX, curY)) &&
263                        (curX > 0) && (curY > 0)) {
264                     curX--;
265                     curY--;
266                 }
267 
268                 if ((curX == chBnd.Width) && isShowing) {
269                     log.println("Couldn't find a point with containsPoint");
270 
271                     continue;
272                 }
273 
274                 // trying the point laying on child
275                 XAccessible xAcc = oObj.getAccessibleAtPoint(
276                                            new Point(chBnd.X + curX,
277                                                      chBnd.Y + curY));
278 
279 
280                 Point p = new Point(chBnd.X + curX,chBnd.X + curX);
281 
282                 if (isCovered(p) && isShowing) {
283                     log.println(
284                             "Child might be covered by another and can't be reached");
285                     MightBeCovered = true;
286                 }
287 
288                 KnownBounds.add(chBnd);
289 
290                 if (xAcc == null) {
291                     log.println("The child not found at point (" +
292                                 (chBnd.X + curX) + "," + (chBnd.Y + curY) +
293                                 ") - FAILED");
294 
295                     if (isShowing) {
296                         result = false;
297                     } else {
298                         result &= true;
299                     }
300                 } else {
301                     XAccessible xAccCh = (XAccessible) UnoRuntime.queryInterface(
302                                                  XAccessible.class,
303                                                  children[i]);
304                     XAccessibleContext xAccC = (XAccessibleContext) UnoRuntime.queryInterface(
305                                                        XAccessibleContext.class,
306                                                        children[i]);
307                     log.println("Child found at point (" + (chBnd.X + curX) +
308                                 "," + (chBnd.Y + curY) + ") - OK");
309 
310                     boolean res = false;
311                     int expIndex;
312                     String expName;
313                     String expDesc;
314 
315                     if (xAccCh != null) {
316                         res = util.AccessibilityTools.equals(xAccCh, xAcc);
317                         expIndex = xAccCh.getAccessibleContext()
318                                          .getAccessibleIndexInParent();
319                         expName = xAccCh.getAccessibleContext()
320                                         .getAccessibleName();
321                         expDesc = xAccCh.getAccessibleContext()
322                                         .getAccessibleDescription();
323                     } else {
324                         res = xAccC.getAccessibleName()
325                                    .equals(xAcc.getAccessibleContext()
326                                                .getAccessibleName());
327                         expIndex = xAccC.getAccessibleIndexInParent();
328                         expName = xAccC.getAccessibleName();
329                         expDesc = xAccC.getAccessibleDescription();
330                     }
331 
332                     if (!res) {
333                         int gotIndex = xAcc.getAccessibleContext()
334                                            .getAccessibleIndexInParent();
335 
336                         if (expIndex < gotIndex) {
337                             log.println("The children found is not the same");
338                             log.println("The expected child " + expName);
339                             log.print("is hidden behind the found Child ");
340                             log.println(xAcc.getAccessibleContext()
341                                             .getAccessibleName() + " - OK");
342                         } else {
343                             log.println(
344                                     "The children found is not the same");
345                             log.println("Expected: " + expName);
346                             log.println("Description:  " + expDesc);
347                             log.println("Found: " +
348                                         xAcc.getAccessibleContext()
349                                             .getAccessibleName());
350                             log.println("Description:  " +
351                                         xAcc.getAccessibleContext()
352                                             .getAccessibleDescription());
353                             if (MightBeCovered) {
354                                 log.println("... Child is covered by another - OK");
355                             } else {
356                                 log.println("... FAILED");
357                                 result = false;
358                             }
359 
360                         }
361                     }
362                 }
363 
364 
365                 // trying the point NOT laying on child
366                 xAcc = oObj.getAccessibleAtPoint(
367                                new Point(chBnd.X - 1, chBnd.Y - 1));
368 
369                 if (xAcc == null) {
370                     log.println("No children found at point (" +
371                                 (chBnd.X - 1) + "," + (chBnd.Y - 1) +
372                                 ") - OK");
373                     result &= true;
374                 } else {
375                     XAccessible xAccCh = (XAccessible) UnoRuntime.queryInterface(
376                                                  XAccessible.class,
377                                                  children[i]);
378                     boolean res = util.AccessibilityTools.equals(xAccCh, xAcc);
379 
380                     if (res) {
381                         log.println("The same child found outside " +
382                                     "its bounds at (" + (chBnd.X - 1) + "," +
383                                     (chBnd.Y - 1) + ") - FAILED");
384                         result = false;
385                     }
386                 }
387             }
388         } else {
389             log.println("There are no children supporting " +
390                         "XAccessibleComponent");
391         }
392 
393         tRes.tested("getAccessibleAtPoint()", result);
394     }
395 
396     /**
397      * Retrieves the component bounds and stores it. <p>
398      *
399      * Has <b> OK </b> status if boundary position (x,y) is not negative
400      * and size (Width, Height) is greater than 0.
401      */
402     public void _getBounds() {
403         boolean result = true;
404 
405         bounds = oObj.getBounds();
406         result &= ((bounds != null) && (bounds.X >= 0) && (bounds.Y >= 0) && (bounds.Width > 0) && (bounds.Height > 0));
407 
408         log.println("Bounds = " +
409                     ((bounds != null)
410                      ? ("(" + bounds.X + "," + bounds.Y + "),(" +
411                                bounds.Width + "," + bounds.Height + ")") : "null"));
412 
413         tRes.tested("getBounds()", result);
414     }
415 
416     /**
417      * Gets the location. <p>
418      *
419      * Has <b> OK </b> status if the location is the same as location
420      * of boundary obtained by <code>getBounds()</code> method.
421      *
422      * The following method tests are to be completed successfully before :
423      * <ul>
424      *  <li> <code> getBounds() </code> : to have bounds </li>
425      * </ul>
426      */
427     public void _getLocation() {
428         requiredMethod("getBounds()");
429 
430         boolean result = true;
431         Point loc = oObj.getLocation();
432 
433         result &= ((loc.X == bounds.X) && (loc.Y == bounds.Y));
434 
435         tRes.tested("getLocation()", result);
436     }
437 
438     /**
439      * Get the screen location of the component and its parent
440      * (if it exists and supports <code>XAccessibleComponent</code>). <p>
441      *
442      * Has <b> OK </b> status if component screen location equals
443      * to screen location of its parent plus location of the component
444      * relative to the parent. <p>
445      *
446      * The following method tests are to be completed successfully before :
447      * <ul>
448      *  <li> <code> getBounds() </code> : to have location of the component
449      *      relative to its parent</li>
450      * </ul>
451      */
452     public void _getLocationOnScreen() {
453         requiredMethod("getBounds()");
454 
455         XAccessibleComponent parent = getParentComponent();
456 
457         boolean result = true;
458         Point loc = oObj.getLocationOnScreen();
459         log.println("Location is (" + loc.X + "," + loc.Y + ")");
460 
461         if (parent != null) {
462             Point parLoc = parent.getLocationOnScreen();
463             log.println("Parent location is (" + parLoc.X + "," + parLoc.Y +
464                         ")");
465 
466             result &= ((parLoc.X + bounds.X) == loc.X);
467             result &= ((parLoc.Y + bounds.Y) == loc.Y);
468         }
469 
470         tRes.tested("getLocationOnScreen()", result);
471     }
472 
473     /**
474      * Obtains the size of the component. <p>
475      *
476      * Has <b> OK </b> status if the size is the same as in bounds. <p>
477      *
478      * The following method tests are to be completed successfully before :
479      * <ul>
480      *  <li> <code> getBounds() </code>  </li>
481      * </ul>
482      */
483     public void _getSize() {
484         requiredMethod("getBounds()");
485 
486         boolean result = true;
487         Size size = oObj.getSize();
488 
489         result &= (size.Width == bounds.Width);
490         result &= (size.Height == bounds.Height);
491 
492         tRes.tested("getSize()", result);
493     }
494 
495     /**
496      * Just calls the method. <p>
497      *
498      * Has <b> OK </b> status if no runtime exceptions occured.
499      */
500     public void _grabFocus() {
501         boolean result = true;
502         oObj.grabFocus();
503 
504         tRes.tested("grabFocus()", result);
505     }
506 
507     /**
508      * Retrieves all children (not more than 50) of the current
509      * component which support <code>XAccessibleComponent</code>.
510      *
511      * @return The array of children. Empty array returned if
512      * such children were not found or some error occured.
513      */
514     private XAccessibleComponent[] getChildrenComponents() {
515         XAccessible xAcc = (XAccessible) UnoRuntime.queryInterface(
516                                    XAccessible.class, oObj);
517 
518         if (xAcc == null) {
519             log.println("Component doesn't support XAccessible.");
520 
521             return new XAccessibleComponent[0];
522         }
523 
524         XAccessibleContext xAccCon = xAcc.getAccessibleContext();
525         int cnt = xAccCon.getAccessibleChildCount();
526 
527         // for cases when too many children exist checking only first 50
528         if (cnt > 50) {
529             cnt = 50;
530         }
531 
532         Vector childComp = new Vector();
533 
534         for (int i = 0; i < cnt; i++) {
535             try {
536                 XAccessible child = xAccCon.getAccessibleChild(i);
537                 XAccessibleContext xAccConCh = child.getAccessibleContext();
538                 XAccessibleComponent xChAccComp = (XAccessibleComponent) UnoRuntime.queryInterface(
539                                                           XAccessibleComponent.class,
540                                                           xAccConCh);
541 
542                 if (xChAccComp != null) {
543                     childComp.add(xChAccComp);
544                 }
545             } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
546             }
547         }
548 
549         return (XAccessibleComponent[]) childComp.toArray(
550                          new XAccessibleComponent[childComp.size()]);
551     }
552 
553     /**
554      * Gets the parent of the current component which support
555      * <code>XAccessibleComponent</code>.
556      *
557      * @return The parent or <code>null</code> if the component
558      * has no parent or some errors occured.
559      */
560     private XAccessibleComponent getParentComponent() {
561         XAccessible xAcc = (XAccessible) UnoRuntime.queryInterface(
562                                    XAccessible.class, oObj);
563 
564         if (xAcc == null) {
565             log.println("Component doesn't support XAccessible.");
566 
567             return null;
568         }
569 
570         XAccessibleContext xAccCon = xAcc.getAccessibleContext();
571         XAccessible xAccPar = xAccCon.getAccessibleParent();
572 
573         if (xAccPar == null) {
574             log.println("Component has no accessible parent.");
575 
576             return null;
577         }
578 
579         XAccessibleContext xAccConPar = xAccPar.getAccessibleContext();
580         XAccessibleComponent parent = (XAccessibleComponent) UnoRuntime.queryInterface(
581                                               XAccessibleComponent.class,
582                                               xAccConPar);
583 
584         if (parent == null) {
585             log.println(
586                     "Accessible parent doesn't support XAccessibleComponent");
587 
588             return null;
589         }
590 
591         return parent;
592     }
593 
594     /**
595      * Just calls the method.
596      */
597     public void _getForeground() {
598         int forColor = oObj.getForeground();
599         log.println("getForeground(): " + forColor);
600         tRes.tested("getForeground()", true);
601     }
602 
603     /**
604      * Just calls the method.
605      */
606     public void _getBackground() {
607         int backColor = oObj.getBackground();
608         log.println("getBackground(): " + backColor);
609         tRes.tested("getBackground()", true);
610     }
611 
612     /**
613      * Restores initial component text.
614      */
615     protected void after() {
616         if (tEnv.getObjRelation("Destroy") != null) {
617             disposeEnvironment();
618         }
619     }
620 
621     private boolean isCovered(Point p) {
622         int elements = KnownBounds.size();
623         boolean Covered = false;
624         for (int k=0;k<elements;k++) {
625             Rectangle known = (Rectangle) KnownBounds.get(k);
626             Covered = (known.X < p.X);
627             Covered &= (known.Y < p.Y);
628             Covered &= (p.Y < known.Y+known.Height);
629             Covered &= (p.X < known.X+known.Width);
630 
631             if (Covered) {
632                 break;
633             }
634         }
635         return Covered;
636     }
637 }
638