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