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