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