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 
24 package org.openoffice.accessibility.awb.tree;
25 
26 import com.sun.star.accessibility.AccessibleRole;
27 import com.sun.star.accessibility.XAccessible;
28 import com.sun.star.accessibility.XAccessibleContext;
29 
30 import com.sun.star.awt.XExtendedToolkit;
31 import com.sun.star.awt.XTopWindow;
32 
33 import com.sun.star.uno.UnoRuntime;
34 
35 import javax.swing.SwingUtilities;
36 import javax.swing.tree.DefaultMutableTreeNode;
37 
38 /**
39  *
40  */
41 public class ToolkitNode extends DefaultMutableTreeNode
42         implements com.sun.star.awt.XTopWindowListener {
43 
44     protected XExtendedToolkit xToolkit;
45 
46     private AccessibilityModel treeModel;
47 
48     /** Creates a new instance of TopWindowListener */
ToolkitNode(XExtendedToolkit xToolkit, AccessibilityModel treeModel)49     public ToolkitNode(XExtendedToolkit xToolkit, AccessibilityModel treeModel) {
50         super("<connected>");
51         this.xToolkit = xToolkit;
52         this.treeModel = treeModel;
53 
54         // Initially fill the child list
55         try {
56             for (int i=0,j=xToolkit.getTopWindowCount(); i<j; i++) {
57                 XTopWindow xTopWindow = xToolkit.getTopWindow(i);
58                 if (xTopWindow != null) {
59                     AccessibilityNode an = getTopWindowNode(xTopWindow);
60                     if (an != null) {
61                         add(an);
62                         // Calling oneway methods from an UNO thread may cause
63                         // deadlocks, so adding the listeners here.
64                         an.setAttached(true);
65                     }
66                 }
67             }
68         } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
69             // This should never happen since we properly check the count
70             // before - anyway returning what we got so far.
71         }
72     }
73 
74     /** Returns an AccessibilityNode if xAccessible has a valid toplevel */
getTopWindowNode(XAccessible xAccessible)75     private AccessibilityNode getTopWindowNode(XAccessible xAccessible) {
76         XAccessibleContext xAC = xAccessible.getAccessibleContext();
77         if (xAC != null) {
78             short role = xAC.getAccessibleRole();
79             if ((role == AccessibleRole.FRAME) || (role == AccessibleRole.DIALOG) || (role == AccessibleRole.WINDOW)) {
80                 return treeModel.createWindowNode(xAccessible, xAC);
81             }
82         }
83         return null;
84     }
85 
86     /** Returns an AccessibilityNode if xAccessible has a valid toplevel */
getTopWindowNode(XAccessible xAccessible, XAccessibleContext xAC)87     private AccessibilityNode getTopWindowNode(XAccessible xAccessible, XAccessibleContext xAC) {
88         if (xAC != null) {
89             short role = xAC.getAccessibleRole();
90             if ((role == AccessibleRole.FRAME) || (role == AccessibleRole.DIALOG) || (role == AccessibleRole.WINDOW)) {
91                 AccessibilityNode parent = treeModel.createWindowNode(xAccessible, xAC);
92                 if (parent != null) {
93                     try {
94                         int n = xAC.getAccessibleChildCount();
95                         for (int i=0; i<n; i++) {
96                             AccessibilityNode child = treeModel.createNode(xAC.getAccessibleChild(i));
97                             if (child != null) {
98                                 parent.add(child);
99                             }
100                         }
101                     } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
102 
103                     }
104                 }
105                 return parent;
106             }
107         }
108         return null;
109     }
110 
111     /** Returns the XAccessible interface corresponding to the toplevel window */
getTopWindowNode(XTopWindow w)112     private AccessibilityNode getTopWindowNode(XTopWindow w) {
113         XAccessible xAccessible = (XAccessible)
114             UnoRuntime.queryInterface(XAccessible.class, w);
115         if (xAccessible != null) {
116             // XTopWindows usually have an accessible parent, which is the
117             // native container window ..
118             XAccessibleContext xAC = xAccessible.getAccessibleContext();
119             if (xAC != null) {
120                 XAccessible xParent = xAC.getAccessibleParent();
121                 if (xParent != null) {
122                     AccessibilityNode parent = getTopWindowNode(xParent);
123                     AccessibilityNode child = treeModel.createNode(xAccessible);
124                     if (parent != null && child != null) {
125                         parent.add(child);
126                     }
127                     return parent;
128                 } else {
129                     return getTopWindowNode(xAccessible, xAC);
130                 }
131             }
132         }
133         return null;
134     }
135 
disposing(com.sun.star.lang.EventObject eventObject)136     public void disposing(com.sun.star.lang.EventObject eventObject) {
137         // FIXME : message
138         // prevent setRoot from removing this as event listener
139         xToolkit = null;
140         treeModel.setRoot(treeModel.disconnectedRootNode);
141     }
142 
windowActivated(com.sun.star.lang.EventObject eventObject)143     public void windowActivated(com.sun.star.lang.EventObject eventObject) {
144     }
145 
windowClosed(com.sun.star.lang.EventObject eventObject)146     public void windowClosed(com.sun.star.lang.EventObject eventObject) {
147         XAccessible xAccessible = (XAccessible) UnoRuntime.queryInterface(
148             XAccessible.class, eventObject.Source);
149         if (xAccessible != null) {
150             AccessibilityNode node = treeModel.findNode(xAccessible);
151 
152             // The object implementing XTopWindow is often not the toplevel
153             // accessible object.
154             if (node != null && node.getParent() != this) {
155                 node = (AccessibilityNode) node.getParent();
156             }
157 
158             if (node != null) {
159                 final AccessibilityNode an = node;
160                 Runnable removeRun = new Runnable() {
161                     public void run() {
162                         try {
163                             treeModel.removeNodeFromParent(an);
164                             // Calling oneway methods from an UNO thread may cause
165                             // deadlocks, so removing the listeners here.
166                             an.setAttached(false);
167                         } catch (IllegalArgumentException e) {
168                             // for some toplevel we get more than one event -
169                             // ignoring
170                         }
171                     }
172                 };
173                 SwingUtilities.invokeLater(removeRun);
174             }
175         }
176     }
177 
windowClosing(com.sun.star.lang.EventObject eventObject)178     public void windowClosing(com.sun.star.lang.EventObject eventObject) {
179     }
180 
windowDeactivated(com.sun.star.lang.EventObject eventObject)181     public void windowDeactivated(com.sun.star.lang.EventObject eventObject) {
182     }
183 
windowMinimized(com.sun.star.lang.EventObject eventObject)184     public void windowMinimized(com.sun.star.lang.EventObject eventObject) {
185     }
186 
windowNormalized(com.sun.star.lang.EventObject eventObject)187     public void windowNormalized(com.sun.star.lang.EventObject eventObject) {
188     }
189 
windowOpened(com.sun.star.lang.EventObject eventObject)190     public void windowOpened(com.sun.star.lang.EventObject eventObject) {
191         final XTopWindow xTopWindow = (XTopWindow) UnoRuntime.queryInterface(
192             XTopWindow.class, eventObject.Source);
193         if (xTopWindow != null) {
194             final ToolkitNode tn = this;
195             Runnable addNodeRun = new Runnable() {
196                 public void run() {
197                     // Note: UNO does not allow to make synchronous callbacks
198                     // to oneway calls, so we have to fetch the node here.
199                     AccessibilityNode an = getTopWindowNode(xTopWindow);
200                     if (an != null) {
201                         treeModel.addNodeInto(an, tn);
202                         // Calling oneway methods from an UNO thread may cause
203                         // deadlocks, so adding the listeners here.
204                         an.setAttached(true);
205                     }
206                 }
207             };
208             SwingUtilities.invokeLater(addNodeRun);
209         }
210     }
211 }
212