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 
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 
22 import com.sun.star.accessibility.XAccessible;
23 import com.sun.star.accessibility.XAccessibleComponent;
24 import com.sun.star.accessibility.XAccessibleContext;
25 import com.sun.star.accessibility.XAccessibleEditableText;
26 import com.sun.star.accessibility.XAccessibleSelection;
27 import com.sun.star.accessibility.XAccessibleTable;
28 import com.sun.star.accessibility.XAccessibleText;
29 import com.sun.star.uno.UnoRuntime;
30 
31 /**
32  * The node type for the AccessibleTreeModel.
33  * This implements all the child-handling based on the appropriate
34  * NodeHandlers. Trivial nodes can be implemented by any Object
35  * type.
36  */
37 class AccTreeNode
38     extends AccessibleTreeNode
39 {
40     private class HandlerDescriptor
41     {
HandlerDescriptor(NodeHandler aHandler)42         private HandlerDescriptor (NodeHandler aHandler)
43         {
44             maHandler = aHandler;
45             mnChildCount = -1;
46         }
47         private NodeHandler maHandler;
48         private int mnChildCount;
49     }
50     /// NodeHandlers for this node
51     private ArrayList<HandlerDescriptor> maHandlers;
52 
53     // The accessible context of this node.
54     private XAccessibleContext mxContext;
55     private XAccessibleComponent mxComponent;
56     private XAccessibleText mxText;
57     private XAccessibleTable mxTable;
58 
AccTreeNode(XAccessibleContext xContext, Object aDisplay, AccessibleTreeNode aParent)59     public AccTreeNode (XAccessibleContext xContext, Object aDisplay, AccessibleTreeNode aParent)
60     {
61         super (aDisplay, aParent);
62 
63         maHandlers = new ArrayList<HandlerDescriptor>(5);
64         mxContext = xContext;
65     }
66 
67     /** Update the internal data extracted from the corresponding accessible
68         object.  This is done by replacing every handler by a new one.  An
69         update method at each handler would be better of course.
70     */
71     @Override
update()72     public void update ()
73     {
74         for (int i=0; i<maHandlers.size(); i++)
75         {
76             System.out.println ("replacing handler " + i);
77             HandlerDescriptor aDescriptor = maHandlers.get(i);
78             aDescriptor.maHandler = aDescriptor.maHandler.createHandler (mxContext);
79             aDescriptor.mnChildCount =
80                     aDescriptor.maHandler.getChildCount ();
81         }
82     }
83 
getContext()84     public XAccessibleContext getContext ()
85     {
86         return mxContext;
87     }
88 
getComponent()89     public XAccessibleComponent getComponent ()
90     {
91         if (mxComponent == null && mxContext != null)
92             mxComponent = UnoRuntime.queryInterface(
93                 XAccessibleComponent.class, mxContext);
94         return mxComponent;
95     }
96 
getText()97     public XAccessibleText getText ()
98     {
99         if (mxText == null && mxContext != null)
100             mxText = UnoRuntime.queryInterface(
101                 XAccessibleText.class, mxContext);
102         return mxText;
103     }
104 
getEditText()105     public XAccessibleEditableText getEditText ()
106     {
107         return UnoRuntime.queryInterface(
108                 XAccessibleEditableText.class, mxContext);
109     }
110 
getTable()111     public XAccessibleTable getTable ()
112     {
113         if (mxTable == null && mxContext != null)
114             mxTable = UnoRuntime.queryInterface(
115                 XAccessibleTable.class, mxContext);
116         return mxTable;
117     }
118 
119 
getSelection()120     public XAccessibleSelection getSelection ()
121     {
122         return UnoRuntime.queryInterface(
123                 XAccessibleSelection.class, mxContext);
124     }
125 
addHandler( NodeHandler aHandler )126     public void addHandler( NodeHandler aHandler )
127     {
128         if (aHandler != null)
129             maHandlers.add (new HandlerDescriptor (aHandler));
130     }
131 
132 
133     /** iterate over handlers and return child sum */
getHandlerDescriptor(int i)134     private HandlerDescriptor getHandlerDescriptor (int i)
135     {
136         HandlerDescriptor aDescriptor = maHandlers.get(i);
137         if (aDescriptor.mnChildCount < 0)
138             aDescriptor.mnChildCount =
139                     aDescriptor.maHandler.getChildCount ();
140         return aDescriptor;
141     }
142 
143     @Override
getChildCount()144     public int getChildCount()
145     {
146         int nChildCount = 0;
147         for (int i = 0; i < maHandlers.size(); i++)
148         {
149             HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
150             nChildCount += aDescriptor.mnChildCount;
151         }
152         return nChildCount;
153     }
154 
155     /** iterate over handlers until the child is found */
156     @Override
getChild(int nIndex)157     public AccessibleTreeNode getChild (int nIndex)
158         throws IndexOutOfBoundsException
159     {
160         if( nIndex >= 0 )
161         {
162             for(int i = 0; i < maHandlers.size(); i++)
163             {
164                 // check if this handler has the child, and if not
165                 // search with next handler
166                 HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
167                 if (nIndex < aDescriptor.mnChildCount)
168                     return aDescriptor.maHandler.getChild (this, nIndex);
169                 else
170                     nIndex -= aDescriptor.mnChildCount;
171             }
172         }
173         else
174             throw new IndexOutOfBoundsException();
175 
176         // nothing found?
177         return null;
178     }
179 
180     @Override
getChildNoCreate(int nIndex)181     public AccessibleTreeNode getChildNoCreate (int nIndex)
182         throws IndexOutOfBoundsException
183     {
184         if( nIndex >= 0 )
185         {
186             for(int i = 0; i < maHandlers.size(); i++)
187             {
188                 // check if this handler has the child, and if not
189                 // search with next handler
190                 HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
191                 if (nIndex < aDescriptor.mnChildCount)
192                     return aDescriptor.maHandler.getChildNoCreate (nIndex);
193                 else
194                     nIndex -= aDescriptor.mnChildCount;
195             }
196         }
197         else
198             throw new IndexOutOfBoundsException();
199 
200         // nothing found?
201         return null;
202     }
203 
204     @Override
removeChild(int nIndex)205     public boolean removeChild (int nIndex)
206         throws IndexOutOfBoundsException
207     {
208         boolean bStatus = false;
209         if (nIndex >= 0)
210         {
211             for (int i=0; i<maHandlers.size(); i++)
212             {
213                 // check if this handler has the child, and if not
214                 // search with next handler
215                 HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
216                 if (nIndex < aDescriptor.mnChildCount)
217                 {
218                     bStatus = aDescriptor.maHandler.removeChild (nIndex);
219                     aDescriptor.mnChildCount = aDescriptor.maHandler.getChildCount ();
220                     break;
221                 }
222                 else
223                     nIndex -= aDescriptor.mnChildCount;
224             }
225         }
226         else
227             throw new IndexOutOfBoundsException();
228 
229         return bStatus;
230     }
231 
232 
233     @Override
indexOf(AccessibleTreeNode aNode)234     public int indexOf (AccessibleTreeNode aNode)
235     {
236         int nBaseIndex = 0;
237         if (aNode != null)
238         {
239             for (int i=0; i<maHandlers.size(); i++)
240             {
241                 HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
242                 int nIndex = aDescriptor.maHandler.indexOf (aNode);
243                 if (nIndex >= 0)
244                     return nBaseIndex + nIndex;
245                 else
246                     nBaseIndex += aDescriptor.mnChildCount;
247             }
248         }
249 
250         return -1;
251     }
252 
253     /** this node is a leaf if have no handlers, or is those
254             handlers show no children */
255     @Override
isLeaf()256     public boolean isLeaf()
257     {
258         return maHandlers.isEmpty();
259     }
260 
261     @Override
equals(Object aOther)262     public boolean equals (Object aOther)
263     {
264         return (this == aOther) || (aOther!=null && aOther.equals(mxContext));
265     }
266 
267 
268     /** iterate over handlers until the child is found */
getActions(java.util.List<String> aActions)269     public void getActions(java.util.List<String> aActions)
270     {
271         for(int i = 0; i < maHandlers.size(); i++)
272         {
273             HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
274             NodeHandler aHandler = aDescriptor.maHandler;
275             String[] aHandlerActions = aHandler.getActions (this);
276             aActions.addAll(Arrays.asList(aHandlerActions));
277         }
278     }
279 
280     @Override
performAction( int nIndex )281     public void performAction( int nIndex )
282     {
283         if( nIndex >= 0 )
284         {
285             for(int i = 0; i < maHandlers.size(); i++)
286             {
287                 // check if this handler has the child, and if not
288                 // search with next handler
289                 HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
290                 NodeHandler aHandler = aDescriptor.maHandler;
291                 int nCount = aHandler.getActions(this).length;
292                 if( nCount > nIndex )
293                 {
294                     aHandler.performAction(this, nIndex );
295                     return;
296                 }
297                 else
298                     nIndex -= nCount;
299             }
300         }
301     }
302 
303     /** Try to add the specified accessible object as new accessible child of the
304         AccessibleTreeHandler.
305         Note that child is used in another context than
306         it is used in the other methods of this class.
307     */
addAccessibleChild(XAccessible xChild)308     public AccessibleTreeNode addAccessibleChild (XAccessible xChild)
309     {
310         for(int i = 0; i < maHandlers.size(); i++)
311         {
312             HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
313             if (aDescriptor.maHandler instanceof AccessibleTreeHandler)
314             {
315                 AccessibleTreeHandler aHandler = (AccessibleTreeHandler)aDescriptor.maHandler;
316                 AccessibleTreeNode aNode = aHandler.addAccessibleChild (this, xChild);
317                 aDescriptor.mnChildCount = aHandler.getChildCount ();
318                 return aNode;
319             }
320         }
321         return null;
322     }
323 
updateChildren(java.lang.Class class1, java.lang.Class<AccessibleExtendedComponentHandler> class2)324     public java.util.List<Integer> updateChildren (java.lang.Class class1, java.lang.Class<AccessibleExtendedComponentHandler> class2)
325     {
326         ArrayList<Integer> aChildIndices = new ArrayList<Integer>();
327         int nOffset = 0;
328         for(int i=0; i < maHandlers.size(); i++)
329         {
330             HandlerDescriptor aDescriptor = getHandlerDescriptor (i);
331             if ((class1.isInstance(aDescriptor.maHandler))
332                 || (class2 !=null && class2.isInstance(aDescriptor.maHandler)))
333             {
334                 aDescriptor.maHandler.update(this);
335                 // Get updated number of children.
336                 int nChildCount = aDescriptor.maHandler.getChildCount ();
337                 aDescriptor.mnChildCount = nChildCount;
338                 // Fill in the indices of the updated children.
339                 for (int j=0; j<nChildCount; j++)
340                     aChildIndices.add(j+nOffset);
341             }
342             nOffset += aDescriptor.mnChildCount;
343         }
344         return aChildIndices;
345     }
346 }
347