1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski import javax.swing.event.TreeModelEvent;
23*b1cdbd2cSJim Jagielski import javax.swing.event.TreeModelListener;
24*b1cdbd2cSJim Jagielski import javax.swing.tree.TreePath;
25*b1cdbd2cSJim Jagielski 
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski import java.util.Vector;
28*b1cdbd2cSJim Jagielski import java.util.HashMap;
29*b1cdbd2cSJim Jagielski import java.util.Enumeration;
30*b1cdbd2cSJim Jagielski 
31*b1cdbd2cSJim Jagielski import com.sun.star.accessibility.*;
32*b1cdbd2cSJim Jagielski 
33*b1cdbd2cSJim Jagielski import com.sun.star.uno.UnoRuntime;
34*b1cdbd2cSJim Jagielski import com.sun.star.uno.XInterface;
35*b1cdbd2cSJim Jagielski import com.sun.star.uno.Any;
36*b1cdbd2cSJim Jagielski import com.sun.star.lang.EventObject;
37*b1cdbd2cSJim Jagielski import com.sun.star.lang.XServiceInfo;
38*b1cdbd2cSJim Jagielski import com.sun.star.lang.XServiceName;
39*b1cdbd2cSJim Jagielski 
40*b1cdbd2cSJim Jagielski public class AccessibilityTreeModel
41*b1cdbd2cSJim Jagielski     extends AccessibilityTreeModelBase
42*b1cdbd2cSJim Jagielski {
43*b1cdbd2cSJim Jagielski     public boolean mbVerbose = false;
44*b1cdbd2cSJim Jagielski 
AccessibilityTreeModel(AccessibleTreeNode aRoot)45*b1cdbd2cSJim Jagielski     public AccessibilityTreeModel (AccessibleTreeNode aRoot)
46*b1cdbd2cSJim Jagielski     {
47*b1cdbd2cSJim Jagielski         // create default node (unless we have a 'proper' node)
48*b1cdbd2cSJim Jagielski         if( ! (aRoot instanceof AccessibleTreeNode) )
49*b1cdbd2cSJim Jagielski             aRoot = new StringNode ("Root", null);
50*b1cdbd2cSJim Jagielski         setRoot (aRoot);
51*b1cdbd2cSJim Jagielski 
52*b1cdbd2cSJim Jagielski         maNodeMap = new NodeMap();
53*b1cdbd2cSJim Jagielski 
54*b1cdbd2cSJim Jagielski         maEventListener = new EventListener (this);
55*b1cdbd2cSJim Jagielski         mxListener = new QueuedListener (maEventListener);
56*b1cdbd2cSJim Jagielski     }
57*b1cdbd2cSJim Jagielski 
clear()58*b1cdbd2cSJim Jagielski     public void clear ()
59*b1cdbd2cSJim Jagielski     {
60*b1cdbd2cSJim Jagielski         maNodeMap.Clear();
61*b1cdbd2cSJim Jagielski     }
62*b1cdbd2cSJim Jagielski 
63*b1cdbd2cSJim Jagielski     /** Lock the tree.  While the tree is locked, events from the outside are
64*b1cdbd2cSJim Jagielski         not processed.  Lock the tree when you change its internal structure.
65*b1cdbd2cSJim Jagielski     */
lock()66*b1cdbd2cSJim Jagielski     public void lock ()
67*b1cdbd2cSJim Jagielski     {
68*b1cdbd2cSJim Jagielski         mnLockCount += 1;
69*b1cdbd2cSJim Jagielski     }
70*b1cdbd2cSJim Jagielski 
71*b1cdbd2cSJim Jagielski     /** Unlock the tree.  After unlocking the tree as many times as locking
72*b1cdbd2cSJim Jagielski         it, a treeStructureChange event is sent to the event listeners.
73*b1cdbd2cSJim Jagielski         @param aNodeHint
74*b1cdbd2cSJim Jagielski             If not null and treeStructureChange events are thrown then this
75*b1cdbd2cSJim Jagielski             node is used as root of the modified subtree.
76*b1cdbd2cSJim Jagielski     */
unlock(AccessibleTreeNode aNodeHint)77*b1cdbd2cSJim Jagielski     public void unlock (AccessibleTreeNode aNodeHint)
78*b1cdbd2cSJim Jagielski     {
79*b1cdbd2cSJim Jagielski         mnLockCount -= 1;
80*b1cdbd2cSJim Jagielski         if (mnLockCount == 0)
81*b1cdbd2cSJim Jagielski             fireTreeStructureChanged (
82*b1cdbd2cSJim Jagielski                 new TreeModelEvent (this,
83*b1cdbd2cSJim Jagielski                     new TreePath (aNodeHint.createPath())));
84*b1cdbd2cSJim Jagielski     }
85*b1cdbd2cSJim Jagielski 
86*b1cdbd2cSJim Jagielski 
87*b1cdbd2cSJim Jagielski 
88*b1cdbd2cSJim Jagielski 
89*b1cdbd2cSJim Jagielski     /** Inform all listeners (especially the renderer) of a change of the
90*b1cdbd2cSJim Jagielski         tree's structure.
91*b1cdbd2cSJim Jagielski         @param aNode This node specifies the sub tree in which all changes
92*b1cdbd2cSJim Jagielski         take place.
93*b1cdbd2cSJim Jagielski     */
FireTreeStructureChanged(AccessibleTreeNode aNode)94*b1cdbd2cSJim Jagielski     public void FireTreeStructureChanged (AccessibleTreeNode aNode)
95*b1cdbd2cSJim Jagielski     {
96*b1cdbd2cSJim Jagielski     }
97*b1cdbd2cSJim Jagielski 
98*b1cdbd2cSJim Jagielski 
99*b1cdbd2cSJim Jagielski 
100*b1cdbd2cSJim Jagielski 
101*b1cdbd2cSJim Jagielski 
setRoot(AccessibleTreeNode aRoot)102*b1cdbd2cSJim Jagielski     public synchronized void setRoot (AccessibleTreeNode aRoot)
103*b1cdbd2cSJim Jagielski     {
104*b1cdbd2cSJim Jagielski         if (getRoot() == null)
105*b1cdbd2cSJim Jagielski             super.setRoot (aRoot);
106*b1cdbd2cSJim Jagielski         else
107*b1cdbd2cSJim Jagielski         {
108*b1cdbd2cSJim Jagielski             lock ();
109*b1cdbd2cSJim Jagielski             maNodeMap.ForEach (new NodeMapCallback () {
110*b1cdbd2cSJim Jagielski                     public void Apply (AccTreeNode aNode)
111*b1cdbd2cSJim Jagielski                     {
112*b1cdbd2cSJim Jagielski                         if (maCanvas != null)
113*b1cdbd2cSJim Jagielski                             maCanvas.removeNode (aNode);
114*b1cdbd2cSJim Jagielski                         removeAccListener ((AccTreeNode)aNode);
115*b1cdbd2cSJim Jagielski                     }
116*b1cdbd2cSJim Jagielski                 });
117*b1cdbd2cSJim Jagielski             maNodeMap.Clear ();
118*b1cdbd2cSJim Jagielski 
119*b1cdbd2cSJim Jagielski             setRoot (aRoot);
120*b1cdbd2cSJim Jagielski             unlock (aRoot);
121*b1cdbd2cSJim Jagielski         }
122*b1cdbd2cSJim Jagielski     }
123*b1cdbd2cSJim Jagielski 
124*b1cdbd2cSJim Jagielski 
125*b1cdbd2cSJim Jagielski     //
126*b1cdbd2cSJim Jagielski     // child management:
127*b1cdbd2cSJim Jagielski     //
128*b1cdbd2cSJim Jagielski 
129*b1cdbd2cSJim Jagielski 
130*b1cdbd2cSJim Jagielski 
131*b1cdbd2cSJim Jagielski     /** Delegate the request to the parent and then register listeners at
132*b1cdbd2cSJim Jagielski         the child and add the child to the canvas.
133*b1cdbd2cSJim Jagielski     */
getChild(Object aParent, int nIndex)134*b1cdbd2cSJim Jagielski     public Object getChild (Object aParent, int nIndex)
135*b1cdbd2cSJim Jagielski     {
136*b1cdbd2cSJim Jagielski         AccessibleTreeNode aChild = (AccessibleTreeNode)super.getChild (aParent, nIndex);
137*b1cdbd2cSJim Jagielski 
138*b1cdbd2cSJim Jagielski         if (aChild == null)
139*b1cdbd2cSJim Jagielski             System.out.println ("getChild: child not found");
140*b1cdbd2cSJim Jagielski         else
141*b1cdbd2cSJim Jagielski             // Keep translation table up-to-date.
142*b1cdbd2cSJim Jagielski             addNode (aChild);
143*b1cdbd2cSJim Jagielski 
144*b1cdbd2cSJim Jagielski         return aChild;
145*b1cdbd2cSJim Jagielski     }
146*b1cdbd2cSJim Jagielski 
getChildNoCreate(Object aParent, int nIndex)147*b1cdbd2cSJim Jagielski     public Object getChildNoCreate (Object aParent, int nIndex)
148*b1cdbd2cSJim Jagielski     {
149*b1cdbd2cSJim Jagielski         AccessibleTreeNode aChild = (AccessibleTreeNode)super.getChildNoCreate (aParent, nIndex);
150*b1cdbd2cSJim Jagielski 
151*b1cdbd2cSJim Jagielski         return aChild;
152*b1cdbd2cSJim Jagielski     }
153*b1cdbd2cSJim Jagielski 
154*b1cdbd2cSJim Jagielski 
155*b1cdbd2cSJim Jagielski 
156*b1cdbd2cSJim Jagielski 
157*b1cdbd2cSJim Jagielski     /** Remove a node (and all children) from the tree model.
158*b1cdbd2cSJim Jagielski     */
removeChild(AccessibleTreeNode aNode)159*b1cdbd2cSJim Jagielski     protected boolean removeChild (AccessibleTreeNode aNode)
160*b1cdbd2cSJim Jagielski     {
161*b1cdbd2cSJim Jagielski         try
162*b1cdbd2cSJim Jagielski         {
163*b1cdbd2cSJim Jagielski             if( aNode == null )
164*b1cdbd2cSJim Jagielski             {
165*b1cdbd2cSJim Jagielski                 System.out.println ("can't remove null node");
166*b1cdbd2cSJim Jagielski                 return false;
167*b1cdbd2cSJim Jagielski             }
168*b1cdbd2cSJim Jagielski             else
169*b1cdbd2cSJim Jagielski             {
170*b1cdbd2cSJim Jagielski                 // depth-first removal of children
171*b1cdbd2cSJim Jagielski                 while (aNode.getChildCount() > 0)
172*b1cdbd2cSJim Jagielski                     if ( ! removeChild (aNode.getChildNoCreate (0)))
173*b1cdbd2cSJim Jagielski                         break;
174*b1cdbd2cSJim Jagielski 
175*b1cdbd2cSJim Jagielski                 // Remove node from its parent.
176*b1cdbd2cSJim Jagielski                 AccessibleTreeNode aParent = aNode.getParent();
177*b1cdbd2cSJim Jagielski                 if (aParent != null)
178*b1cdbd2cSJim Jagielski                 {
179*b1cdbd2cSJim Jagielski                     int nIndex = aParent.indexOf(aNode);
180*b1cdbd2cSJim Jagielski                     aParent.removeChild (nIndex);
181*b1cdbd2cSJim Jagielski                 }
182*b1cdbd2cSJim Jagielski 
183*b1cdbd2cSJim Jagielski                 maNodeMap.RemoveNode (aNode);
184*b1cdbd2cSJim Jagielski             }
185*b1cdbd2cSJim Jagielski         }
186*b1cdbd2cSJim Jagielski         catch (Exception e)
187*b1cdbd2cSJim Jagielski         {
188*b1cdbd2cSJim Jagielski             System.out.println ("caught exception while removing child "
189*b1cdbd2cSJim Jagielski                 + aNode + " : " + e);
190*b1cdbd2cSJim Jagielski             e.printStackTrace ();
191*b1cdbd2cSJim Jagielski             return false;
192*b1cdbd2cSJim Jagielski         }
193*b1cdbd2cSJim Jagielski         return true;
194*b1cdbd2cSJim Jagielski     }
195*b1cdbd2cSJim Jagielski 
removeNode(XAccessibleContext xNode)196*b1cdbd2cSJim Jagielski     public void removeNode (XAccessibleContext xNode)
197*b1cdbd2cSJim Jagielski     {
198*b1cdbd2cSJim Jagielski         if (xNode != null)
199*b1cdbd2cSJim Jagielski         {
200*b1cdbd2cSJim Jagielski             AccessibleTreeNode aNode = maNodeMap.GetNode (xNode);
201*b1cdbd2cSJim Jagielski             AccessibleTreeNode aRootNode = (AccessibleTreeNode)getRoot();
202*b1cdbd2cSJim Jagielski             TreeModelEvent aEvent = createEvent (aRootNode, aNode);
203*b1cdbd2cSJim Jagielski             removeChild (aNode);
204*b1cdbd2cSJim Jagielski             if (mbVerbose)
205*b1cdbd2cSJim Jagielski                 System.out.println (aNode);
206*b1cdbd2cSJim Jagielski             fireTreeNodesRemoved (aEvent);
207*b1cdbd2cSJim Jagielski             maCanvas.repaint ();
208*b1cdbd2cSJim Jagielski         }
209*b1cdbd2cSJim Jagielski     }
210*b1cdbd2cSJim Jagielski 
211*b1cdbd2cSJim Jagielski 
212*b1cdbd2cSJim Jagielski     /** Add add a new child to a parent.
213*b1cdbd2cSJim Jagielski         @return
214*b1cdbd2cSJim Jagielski             Returns the new or existing representation of the specified
215*b1cdbd2cSJim Jagielski             accessible object.
216*b1cdbd2cSJim Jagielski     */
addChild(AccTreeNode aParentNode, XAccessible xNewChild)217*b1cdbd2cSJim Jagielski     protected AccessibleTreeNode addChild (AccTreeNode aParentNode, XAccessible xNewChild)
218*b1cdbd2cSJim Jagielski     {
219*b1cdbd2cSJim Jagielski         AccessibleTreeNode aChildNode = null;
220*b1cdbd2cSJim Jagielski         try
221*b1cdbd2cSJim Jagielski         {
222*b1cdbd2cSJim Jagielski             boolean bRet = false;
223*b1cdbd2cSJim Jagielski 
224*b1cdbd2cSJim Jagielski             // First make sure that the accessible object does not already have
225*b1cdbd2cSJim Jagielski             // a representation.
226*b1cdbd2cSJim Jagielski             aChildNode = maNodeMap.GetNode(xNewChild);
227*b1cdbd2cSJim Jagielski             if (aChildNode == null)
228*b1cdbd2cSJim Jagielski                 aChildNode = aParentNode.addAccessibleChild (xNewChild);
229*b1cdbd2cSJim Jagielski             else
230*b1cdbd2cSJim Jagielski                 System.out.println ("node already present");
231*b1cdbd2cSJim Jagielski         }
232*b1cdbd2cSJim Jagielski         catch (Exception e)
233*b1cdbd2cSJim Jagielski         {
234*b1cdbd2cSJim Jagielski             System.out.println ("caught exception while adding child "
235*b1cdbd2cSJim Jagielski                 + xNewChild + " to parent " + aParentNode + ": " + e);
236*b1cdbd2cSJim Jagielski             e.printStackTrace ();
237*b1cdbd2cSJim Jagielski         }
238*b1cdbd2cSJim Jagielski         return aChildNode;
239*b1cdbd2cSJim Jagielski     }
240*b1cdbd2cSJim Jagielski 
addChild(XAccessibleContext xParent, XAccessible xChild)241*b1cdbd2cSJim Jagielski     public void addChild (XAccessibleContext xParent, XAccessible xChild)
242*b1cdbd2cSJim Jagielski     {
243*b1cdbd2cSJim Jagielski         AccessibleTreeNode aParentNode = maNodeMap.GetNode (xParent);
244*b1cdbd2cSJim Jagielski         if (aParentNode instanceof AccTreeNode)
245*b1cdbd2cSJim Jagielski         {
246*b1cdbd2cSJim Jagielski             AccessibleTreeNode aChild = addChild ((AccTreeNode)aParentNode, xChild);
247*b1cdbd2cSJim Jagielski             if (addNode (aChild))
248*b1cdbd2cSJim Jagielski             {
249*b1cdbd2cSJim Jagielski                 if (maCanvas != null)
250*b1cdbd2cSJim Jagielski                     maCanvas.updateNode ((AccTreeNode)aParentNode);
251*b1cdbd2cSJim Jagielski 
252*b1cdbd2cSJim Jagielski                 // A call to fireTreeNodesInserted for xNew
253*b1cdbd2cSJim Jagielski                 // should be sufficient but at least the
254*b1cdbd2cSJim Jagielski                 // StringNode object that contains the number of
255*b1cdbd2cSJim Jagielski                 // children also changes and we do not know its
256*b1cdbd2cSJim Jagielski                 // index relative to its parent.  Therefore the
257*b1cdbd2cSJim Jagielski                 // more expensive fireTreeStructureChanged is
258*b1cdbd2cSJim Jagielski                 // necessary.
259*b1cdbd2cSJim Jagielski                 fireTreeNodesInserted (createEvent (xParent, xChild));
260*b1cdbd2cSJim Jagielski                 updateNode (xParent, AccessibleTreeHandler.class);
261*b1cdbd2cSJim Jagielski             }
262*b1cdbd2cSJim Jagielski             maCanvas.repaint ();
263*b1cdbd2cSJim Jagielski         }
264*b1cdbd2cSJim Jagielski     }
265*b1cdbd2cSJim Jagielski 
266*b1cdbd2cSJim Jagielski 
267*b1cdbd2cSJim Jagielski     /** Add the child node to the internal tree structure.
268*b1cdbd2cSJim Jagielski         @param aNode
269*b1cdbd2cSJim Jagielski             The node to insert into the internal tree structure.
270*b1cdbd2cSJim Jagielski     */
addNode(AccessibleTreeNode aNode)271*b1cdbd2cSJim Jagielski     protected boolean addNode (AccessibleTreeNode aNode)
272*b1cdbd2cSJim Jagielski     {
273*b1cdbd2cSJim Jagielski         boolean bRet = false;
274*b1cdbd2cSJim Jagielski         try
275*b1cdbd2cSJim Jagielski         {
276*b1cdbd2cSJim Jagielski             if ( ! maNodeMap.ValueIsMember (aNode))
277*b1cdbd2cSJim Jagielski             {
278*b1cdbd2cSJim Jagielski                 if (aNode instanceof AccTreeNode)
279*b1cdbd2cSJim Jagielski                 {
280*b1cdbd2cSJim Jagielski                     AccTreeNode aChild = (AccTreeNode)aNode;
281*b1cdbd2cSJim Jagielski                     XAccessibleContext xChild = aChild.getContext();
282*b1cdbd2cSJim Jagielski                     registerAccListener (aChild);
283*b1cdbd2cSJim Jagielski                     if (maCanvas != null)
284*b1cdbd2cSJim Jagielski                         maCanvas.addNode (aChild);
285*b1cdbd2cSJim Jagielski                     maNodeMap.InsertNode (xChild, aChild);
286*b1cdbd2cSJim Jagielski                 }
287*b1cdbd2cSJim Jagielski                 bRet = true;
288*b1cdbd2cSJim Jagielski             }
289*b1cdbd2cSJim Jagielski 
290*b1cdbd2cSJim Jagielski         }
291*b1cdbd2cSJim Jagielski         catch (Exception e)
292*b1cdbd2cSJim Jagielski         {
293*b1cdbd2cSJim Jagielski             System.out.println ("caught exception while adding node "
294*b1cdbd2cSJim Jagielski                 + aNode + ": " + e);
295*b1cdbd2cSJim Jagielski             e.printStackTrace ();
296*b1cdbd2cSJim Jagielski         }
297*b1cdbd2cSJim Jagielski         return bRet;
298*b1cdbd2cSJim Jagielski     }
299*b1cdbd2cSJim Jagielski 
300*b1cdbd2cSJim Jagielski 
301*b1cdbd2cSJim Jagielski 
302*b1cdbd2cSJim Jagielski 
303*b1cdbd2cSJim Jagielski     /** create path to node, suitable for TreeModelEvent constructor
304*b1cdbd2cSJim Jagielski      * @see javax.swing.event.TreeModelEvent#TreeModelEvent
305*b1cdbd2cSJim Jagielski      */
createPath(AccessibleTreeNode aNode)306*b1cdbd2cSJim Jagielski     protected Object[] createPath (AccessibleTreeNode aNode)
307*b1cdbd2cSJim Jagielski     {
308*b1cdbd2cSJim Jagielski         Vector aPath = new Vector();
309*b1cdbd2cSJim Jagielski         aNode.createPath (aPath);
310*b1cdbd2cSJim Jagielski         return aPath.toArray();
311*b1cdbd2cSJim Jagielski     }
312*b1cdbd2cSJim Jagielski 
313*b1cdbd2cSJim Jagielski     //
314*b1cdbd2cSJim Jagielski     // listeners (and helper methods)
315*b1cdbd2cSJim Jagielski     //
316*b1cdbd2cSJim Jagielski     // We are registered with listeners as soon as objects are in the
317*b1cdbd2cSJim Jagielski     // tree cache, and we should get removed as soon as they are out.
318*b1cdbd2cSJim Jagielski     //
319*b1cdbd2cSJim Jagielski 
fireTreeNodesChanged(TreeModelEvent e)320*b1cdbd2cSJim Jagielski     protected void fireTreeNodesChanged(TreeModelEvent e)
321*b1cdbd2cSJim Jagielski     {
322*b1cdbd2cSJim Jagielski         for(int i = 0; i < maTMListeners.size(); i++)
323*b1cdbd2cSJim Jagielski         {
324*b1cdbd2cSJim Jagielski             ((TreeModelListener)maTMListeners.get(i)).treeNodesChanged(e);
325*b1cdbd2cSJim Jagielski         }
326*b1cdbd2cSJim Jagielski     }
327*b1cdbd2cSJim Jagielski 
fireTreeNodesInserted(final TreeModelEvent e)328*b1cdbd2cSJim Jagielski     protected void fireTreeNodesInserted(final TreeModelEvent e)
329*b1cdbd2cSJim Jagielski     {
330*b1cdbd2cSJim Jagielski         for(int i = 0; i < maTMListeners.size(); i++)
331*b1cdbd2cSJim Jagielski         {
332*b1cdbd2cSJim Jagielski             ((TreeModelListener)maTMListeners.get(i)).treeNodesInserted(e);
333*b1cdbd2cSJim Jagielski         }
334*b1cdbd2cSJim Jagielski     }
335*b1cdbd2cSJim Jagielski 
fireTreeNodesRemoved(final TreeModelEvent e)336*b1cdbd2cSJim Jagielski     protected void fireTreeNodesRemoved(final TreeModelEvent e)
337*b1cdbd2cSJim Jagielski     {
338*b1cdbd2cSJim Jagielski         for(int i = 0; i < maTMListeners.size(); i++)
339*b1cdbd2cSJim Jagielski         {
340*b1cdbd2cSJim Jagielski             ((TreeModelListener)maTMListeners.get(i)).treeNodesRemoved(e);
341*b1cdbd2cSJim Jagielski         }
342*b1cdbd2cSJim Jagielski     }
343*b1cdbd2cSJim Jagielski 
fireTreeStructureChanged(final TreeModelEvent e)344*b1cdbd2cSJim Jagielski     protected void fireTreeStructureChanged(final TreeModelEvent e)
345*b1cdbd2cSJim Jagielski     {
346*b1cdbd2cSJim Jagielski         for(int i = 0; i < maTMListeners.size(); i++)
347*b1cdbd2cSJim Jagielski         {
348*b1cdbd2cSJim Jagielski             ((TreeModelListener)maTMListeners.get(i)).treeStructureChanged(e);
349*b1cdbd2cSJim Jagielski         }
350*b1cdbd2cSJim Jagielski     }
351*b1cdbd2cSJim Jagielski 
createEvent(XAccessibleContext xParent)352*b1cdbd2cSJim Jagielski     protected TreeModelEvent createEvent (XAccessibleContext xParent)
353*b1cdbd2cSJim Jagielski     {
354*b1cdbd2cSJim Jagielski         AccessibleTreeNode aParentNode = maNodeMap.GetNode (xParent);
355*b1cdbd2cSJim Jagielski         return new TreeModelEvent (this, createPath (aParentNode));
356*b1cdbd2cSJim Jagielski     }
357*b1cdbd2cSJim Jagielski 
358*b1cdbd2cSJim Jagielski     /** Create a TreeModelEvent object that informs listeners that one child
359*b1cdbd2cSJim Jagielski         has been removed from or inserted into its parent.
360*b1cdbd2cSJim Jagielski     */
createEvent(XAccessibleContext xParent, XAccessible xChild)361*b1cdbd2cSJim Jagielski     public TreeModelEvent createEvent (XAccessibleContext xParent, XAccessible xChild)
362*b1cdbd2cSJim Jagielski     {
363*b1cdbd2cSJim Jagielski         AccessibleTreeNode aParentNode = maNodeMap.GetNode (xParent);
364*b1cdbd2cSJim Jagielski         return createEvent (aParentNode, xParent);
365*b1cdbd2cSJim Jagielski     }
366*b1cdbd2cSJim Jagielski 
createEvent(AccessibleTreeNode aParentNode, XAccessibleContext xChild)367*b1cdbd2cSJim Jagielski     public TreeModelEvent createEvent (AccessibleTreeNode aParentNode, XAccessibleContext xChild)
368*b1cdbd2cSJim Jagielski     {
369*b1cdbd2cSJim Jagielski         AccessibleTreeNode aChildNode = null;
370*b1cdbd2cSJim Jagielski         if (xChild != null)
371*b1cdbd2cSJim Jagielski             aChildNode = maNodeMap.GetNode (xChild);
372*b1cdbd2cSJim Jagielski         return createEvent (aParentNode, aChildNode);
373*b1cdbd2cSJim Jagielski     }
374*b1cdbd2cSJim Jagielski 
375*b1cdbd2cSJim Jagielski 
376*b1cdbd2cSJim Jagielski 
createEvent( AccessibleTreeNode aParentNode, AccessibleTreeNode aChildNode)377*b1cdbd2cSJim Jagielski     protected TreeModelEvent createEvent (
378*b1cdbd2cSJim Jagielski         AccessibleTreeNode aParentNode,
379*b1cdbd2cSJim Jagielski         AccessibleTreeNode aChildNode)
380*b1cdbd2cSJim Jagielski     {
381*b1cdbd2cSJim Jagielski         Object[] aPathToParent = createPath (aParentNode);
382*b1cdbd2cSJim Jagielski 
383*b1cdbd2cSJim Jagielski         int nIndexInParent = -1;
384*b1cdbd2cSJim Jagielski         if (aChildNode != null)
385*b1cdbd2cSJim Jagielski             nIndexInParent = aParentNode.indexOf (aChildNode);
386*b1cdbd2cSJim Jagielski         if (mbVerbose)
387*b1cdbd2cSJim Jagielski             System.out.println (aChildNode + " " + nIndexInParent);
388*b1cdbd2cSJim Jagielski 
389*b1cdbd2cSJim Jagielski         if (nIndexInParent == -1)
390*b1cdbd2cSJim Jagielski             // This event may be passed only to treeStructureChanged of the listeners.
391*b1cdbd2cSJim Jagielski             return new TreeModelEvent (this,
392*b1cdbd2cSJim Jagielski                 aPathToParent);
393*b1cdbd2cSJim Jagielski         else
394*b1cdbd2cSJim Jagielski             // General purpose event for removing or inserting known nodes.
395*b1cdbd2cSJim Jagielski             return new TreeModelEvent (this,
396*b1cdbd2cSJim Jagielski                 aPathToParent,
397*b1cdbd2cSJim Jagielski                 new int[] {nIndexInParent},
398*b1cdbd2cSJim Jagielski                 new Object[] {aChildNode} );
399*b1cdbd2cSJim Jagielski     }
400*b1cdbd2cSJim Jagielski 
401*b1cdbd2cSJim Jagielski 
402*b1cdbd2cSJim Jagielski 
403*b1cdbd2cSJim Jagielski 
404*b1cdbd2cSJim Jagielski     /** Create a TreeModelEvent that indicates changes at those children of
405*b1cdbd2cSJim Jagielski         the specified node with the specified indices.
406*b1cdbd2cSJim Jagielski     */
createChangeEvent(AccTreeNode aNode, Vector aChildIndices)407*b1cdbd2cSJim Jagielski     protected TreeModelEvent createChangeEvent (AccTreeNode aNode, Vector aChildIndices)
408*b1cdbd2cSJim Jagielski     {
409*b1cdbd2cSJim Jagielski         // Build a list of child objects that are indicated by the given indices.
410*b1cdbd2cSJim Jagielski         int nCount = aChildIndices.size();
411*b1cdbd2cSJim Jagielski         Object aChildObjects[] = new Object[nCount];
412*b1cdbd2cSJim Jagielski         int nChildIndices[] = new int[nCount];
413*b1cdbd2cSJim Jagielski         for (int i=0; i<nCount; i++)
414*b1cdbd2cSJim Jagielski         {
415*b1cdbd2cSJim Jagielski             int nIndex = ((Integer)aChildIndices.elementAt(i)).intValue();
416*b1cdbd2cSJim Jagielski             aChildObjects[i] = aNode.getChild (nIndex);
417*b1cdbd2cSJim Jagielski             nChildIndices[i] = nIndex;
418*b1cdbd2cSJim Jagielski         }
419*b1cdbd2cSJim Jagielski 
420*b1cdbd2cSJim Jagielski         return new TreeModelEvent (this,
421*b1cdbd2cSJim Jagielski             createPath(aNode),
422*b1cdbd2cSJim Jagielski             nChildIndices,
423*b1cdbd2cSJim Jagielski             aChildObjects);
424*b1cdbd2cSJim Jagielski     }
425*b1cdbd2cSJim Jagielski 
426*b1cdbd2cSJim Jagielski 
427*b1cdbd2cSJim Jagielski 
428*b1cdbd2cSJim Jagielski     /**
429*b1cdbd2cSJim Jagielski      * broadcast a tree event in a seperate Thread
430*b1cdbd2cSJim Jagielski      * must override fire method
431*b1cdbd2cSJim Jagielski      */
432*b1cdbd2cSJim Jagielski     class EventRunner implements Runnable
433*b1cdbd2cSJim Jagielski     {
run()434*b1cdbd2cSJim Jagielski         public void run()
435*b1cdbd2cSJim Jagielski         {
436*b1cdbd2cSJim Jagielski             for(int i = 0; i < maTMListeners.size(); i++)
437*b1cdbd2cSJim Jagielski             {
438*b1cdbd2cSJim Jagielski                 fire( (TreeModelListener)maTMListeners.get(i) );
439*b1cdbd2cSJim Jagielski             }
440*b1cdbd2cSJim Jagielski         }
441*b1cdbd2cSJim Jagielski 
fire( TreeModelListener l)442*b1cdbd2cSJim Jagielski         protected void fire( TreeModelListener l) { }
443*b1cdbd2cSJim Jagielski     }
444*b1cdbd2cSJim Jagielski 
445*b1cdbd2cSJim Jagielski 
446*b1cdbd2cSJim Jagielski 
getBroadcaster(Object aObject)447*b1cdbd2cSJim Jagielski     protected XAccessibleEventBroadcaster getBroadcaster (Object aObject)
448*b1cdbd2cSJim Jagielski     {
449*b1cdbd2cSJim Jagielski         if (aObject instanceof AccTreeNode)
450*b1cdbd2cSJim Jagielski             return (XAccessibleEventBroadcaster) UnoRuntime.queryInterface (
451*b1cdbd2cSJim Jagielski                 XAccessibleEventBroadcaster.class, ((AccTreeNode)aObject).getContext());
452*b1cdbd2cSJim Jagielski         else
453*b1cdbd2cSJim Jagielski             return null;
454*b1cdbd2cSJim Jagielski     }
455*b1cdbd2cSJim Jagielski 
registerAccListener( Object aObject )456*b1cdbd2cSJim Jagielski     protected void registerAccListener( Object aObject )
457*b1cdbd2cSJim Jagielski     {
458*b1cdbd2cSJim Jagielski         // register this as listener for XAccessibleEventBroadcaster
459*b1cdbd2cSJim Jagielski         // implementations
460*b1cdbd2cSJim Jagielski         XAccessibleEventBroadcaster xBroadcaster = getBroadcaster( aObject );
461*b1cdbd2cSJim Jagielski         if (xBroadcaster != null)
462*b1cdbd2cSJim Jagielski         {
463*b1cdbd2cSJim Jagielski             xBroadcaster.addEventListener( mxListener );
464*b1cdbd2cSJim Jagielski         }
465*b1cdbd2cSJim Jagielski     }
466*b1cdbd2cSJim Jagielski 
removeAccListener( Object aObject )467*b1cdbd2cSJim Jagielski     protected void removeAccListener( Object aObject )
468*b1cdbd2cSJim Jagielski     {
469*b1cdbd2cSJim Jagielski         XAccessibleEventBroadcaster xBroadcaster = getBroadcaster( aObject );
470*b1cdbd2cSJim Jagielski         if (xBroadcaster != null)
471*b1cdbd2cSJim Jagielski         {
472*b1cdbd2cSJim Jagielski             xBroadcaster.removeEventListener( mxListener );
473*b1cdbd2cSJim Jagielski         }
474*b1cdbd2cSJim Jagielski     }
475*b1cdbd2cSJim Jagielski 
476*b1cdbd2cSJim Jagielski 
477*b1cdbd2cSJim Jagielski 
setCanvas(Canvas aCanvas)478*b1cdbd2cSJim Jagielski     public void setCanvas (Canvas aCanvas)
479*b1cdbd2cSJim Jagielski     {
480*b1cdbd2cSJim Jagielski         maCanvas = aCanvas;
481*b1cdbd2cSJim Jagielski     }
482*b1cdbd2cSJim Jagielski 
getCanvas()483*b1cdbd2cSJim Jagielski     public Canvas getCanvas ()
484*b1cdbd2cSJim Jagielski     {
485*b1cdbd2cSJim Jagielski         return maCanvas;
486*b1cdbd2cSJim Jagielski     }
487*b1cdbd2cSJim Jagielski 
updateNode(XAccessibleContext xSource, java.lang.Class class1)488*b1cdbd2cSJim Jagielski     public void updateNode (XAccessibleContext xSource, java.lang.Class class1)
489*b1cdbd2cSJim Jagielski     {
490*b1cdbd2cSJim Jagielski         updateNode (xSource, class1,null);
491*b1cdbd2cSJim Jagielski     }
492*b1cdbd2cSJim Jagielski 
493*b1cdbd2cSJim Jagielski     /** Get a list of children of the node associated with xSource that are
494*b1cdbd2cSJim Jagielski         affected by the given handlers.  Fire events that these children may
495*b1cdbd2cSJim Jagielski         have changed in the tree view.  Update the canvas representation of
496*b1cdbd2cSJim Jagielski         xSource.
497*b1cdbd2cSJim Jagielski     */
updateNode(XAccessibleContext xSource, java.lang.Class class1, java.lang.Class class2)498*b1cdbd2cSJim Jagielski     public AccTreeNode updateNode (XAccessibleContext xSource,
499*b1cdbd2cSJim Jagielski         java.lang.Class class1, java.lang.Class class2)
500*b1cdbd2cSJim Jagielski     {
501*b1cdbd2cSJim Jagielski         AccessibleTreeNode aTreeNode = maNodeMap.GetNode (xSource);
502*b1cdbd2cSJim Jagielski         AccTreeNode aNode = null;
503*b1cdbd2cSJim Jagielski         if (mbVerbose)
504*b1cdbd2cSJim Jagielski             System.out.println ("updating node " + xSource + "  " + aTreeNode);
505*b1cdbd2cSJim Jagielski         if (aTreeNode instanceof AccTreeNode)
506*b1cdbd2cSJim Jagielski         {
507*b1cdbd2cSJim Jagielski             aNode = (AccTreeNode) aTreeNode;
508*b1cdbd2cSJim Jagielski             // Get list of affected children.
509*b1cdbd2cSJim Jagielski             Vector aChildIndices = (aNode).updateChildren (
510*b1cdbd2cSJim Jagielski                 class1, class2);
511*b1cdbd2cSJim Jagielski             // Fire events that these children may have changed.
512*b1cdbd2cSJim Jagielski             fireTreeNodesChanged (
513*b1cdbd2cSJim Jagielski                 createChangeEvent (aNode, aChildIndices));
514*b1cdbd2cSJim Jagielski         }
515*b1cdbd2cSJim Jagielski         return aNode;
516*b1cdbd2cSJim Jagielski     }
517*b1cdbd2cSJim Jagielski 
518*b1cdbd2cSJim Jagielski     /** The listener to be registered with the accessible objects.
519*b1cdbd2cSJim Jagielski      * Could be set to 'this' for same-thread event delivery, or to an
520*b1cdbd2cSJim Jagielski      * instance of QueuedListener for multi-threaded delivery.  May
521*b1cdbd2cSJim Jagielski      * not be changed, since this would trip the
522*b1cdbd2cSJim Jagielski      * register/removeAccListener logic. */
523*b1cdbd2cSJim Jagielski     private final XAccessibleEventListener mxListener;
524*b1cdbd2cSJim Jagielski 
525*b1cdbd2cSJim Jagielski     // Map to translate from accessible object to corresponding tree node.
526*b1cdbd2cSJim Jagielski     private NodeMap maNodeMap;
527*b1cdbd2cSJim Jagielski 
528*b1cdbd2cSJim Jagielski     // If the lock count is higher then zero, then no events are processed.
529*b1cdbd2cSJim Jagielski     private int mnLockCount;
530*b1cdbd2cSJim Jagielski 
531*b1cdbd2cSJim Jagielski     private Canvas maCanvas;
532*b1cdbd2cSJim Jagielski 
533*b1cdbd2cSJim Jagielski     private EventListener maEventListener;
534*b1cdbd2cSJim Jagielski }
535