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.java.accessibility; 25 26 import com.sun.star.uno.*; 27 import com.sun.star.accessibility.*; 28 29 public class Window extends java.awt.Window implements javax.accessibility.Accessible, NativeFrame { 30 protected XAccessibleComponent unoAccessibleComponent; 31 32 boolean opened = false; 33 boolean visible = false; 34 35 java.awt.EventQueue eventQueue = null; 36 Window(java.awt.Window owner, XAccessibleComponent xAccessibleComponent)37 public Window(java.awt.Window owner, XAccessibleComponent xAccessibleComponent) { 38 super(owner); 39 initialize(xAccessibleComponent); 40 } 41 initialize(XAccessibleComponent xAccessibleComponent)42 private void initialize(XAccessibleComponent xAccessibleComponent) { 43 unoAccessibleComponent = xAccessibleComponent; 44 eventQueue = java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue(); 45 XAccessibleEventBroadcaster broadcaster = (XAccessibleEventBroadcaster) 46 UnoRuntime.queryInterface(XAccessibleEventBroadcaster.class, 47 unoAccessibleComponent); 48 if (broadcaster != null) { 49 broadcaster.addEventListener(new AccessibleWindowListener()); 50 } 51 } 52 53 java.awt.Component initialComponent = null; 54 getInitialComponent()55 public java.awt.Component getInitialComponent() { 56 if (Build.DEBUG) { 57 System.err.println("returning initial component object of class: " + initialComponent.getClass().getName()); 58 } 59 return initialComponent; 60 } 61 setInitialComponent(java.awt.Component c)62 public void setInitialComponent(java.awt.Component c) { 63 initialComponent = c; 64 } 65 getHWND()66 public Integer getHWND() { 67 return null; 68 } 69 70 /** 71 * Determines whether this <code>Component</code> is showing on screen. 72 * This means that the component must be visible, and it must be in a 73 * <code>container</code> that is visible and showing. 74 * @see #addNotify 75 * @see #removeNotify 76 * @since JDK1.0 77 */ isShowing()78 public boolean isShowing() { 79 if (isVisible()) { 80 java.awt.Container parent = getParent(); 81 return (parent == null) || parent.isShowing(); 82 } 83 return false; 84 } 85 86 /** 87 * Makes this <code>Component</code> displayable by connecting it to a 88 * native screen resource. 89 * This method is called internally by the toolkit and should 90 * not be called directly by programs. 91 * @see #isDisplayable 92 * @see #removeNotify 93 * @since JDK1.0 94 */ addNotify()95 public void addNotify() { 96 // createHierarchyEvents(0, null, null, 0, false); 97 } 98 99 /** 100 * Makes this <code>Component</code> undisplayable by destroying it native 101 * screen resource. 102 * This method is called by the toolkit internally and should 103 * not be called directly by programs. 104 * @see #isDisplayable 105 * @see #addNotify 106 * @since JDK1.0 107 */ removeNotify()108 public void removeNotify() { 109 } 110 111 /** 112 * Determines if the object is visible. Note: this means that the 113 * object intends to be visible; however, it may not in fact be 114 * showing on the screen because one of the objects that this object 115 * is contained by is not visible. To determine if an object is 116 * showing on the screen, use <code>isShowing</code>. 117 * 118 * @return true if object is visible; otherwise, false 119 */ isVisible()120 public boolean isVisible(){ 121 return visible; 122 } 123 124 /** 125 * Shows or hides this component depending on the value of parameter 126 * <code>b</code>. 127 * @param b if <code>true</code>, shows this component; 128 * otherwise, hides this component 129 * @see #isVisible 130 * @since JDK1.1 131 */ setVisible(boolean b)132 public void setVisible(boolean b) { 133 if (visible != b){ 134 visible = b; 135 if (b) { 136 // If it is the first show, fire WINDOW_OPENED event 137 if (!opened) { 138 postWindowEvent(java.awt.event.WindowEvent.WINDOW_OPENED); 139 opened = true; 140 } 141 postComponentEvent(java.awt.event.ComponentEvent.COMPONENT_SHOWN); 142 } else { 143 postComponentEvent(java.awt.event.ComponentEvent.COMPONENT_HIDDEN); 144 } 145 } 146 } 147 dispose()148 public void dispose() { 149 setVisible(false); 150 postWindowEvent(java.awt.event.WindowEvent.WINDOW_CLOSED); 151 152 // Transfer window focus back to the owner window if it is still the active frame 153 if ((getOwner() instanceof Frame && ((Frame) getOwner()).active) || 154 (getOwner() instanceof Dialog && ((Dialog) getOwner()).active)) { 155 eventQueue.postEvent(new java.awt.event.WindowEvent(getOwner(), 156 java.awt.event.WindowEvent.WINDOW_GAINED_FOCUS)); 157 } 158 } 159 postWindowEvent(int i)160 protected void postWindowEvent(int i) { 161 eventQueue.postEvent(new java.awt.event.WindowEvent(this, i)); 162 } 163 postComponentEvent(int i)164 protected void postComponentEvent(int i) { 165 eventQueue.postEvent(new java.awt.event.ComponentEvent(this, i)); 166 } 167 168 /** 169 * Update the proxy objects appropriately on property change events 170 */ 171 protected class AccessibleWindowListener implements XAccessibleEventListener { 172 AccessibleWindowListener()173 protected AccessibleWindowListener() { 174 } 175 176 // The only expected state changes are ACTIVE and VISIBLE setComponentState(short state, boolean enable)177 protected void setComponentState(short state, boolean enable) { 178 switch (state) { 179 case AccessibleStateType.ICONIFIED: 180 postWindowEvent(enable ? 181 java.awt.event.WindowEvent.WINDOW_ICONIFIED : 182 java.awt.event.WindowEvent.WINDOW_DEICONIFIED); 183 break; 184 case AccessibleStateType.SHOWING: 185 case AccessibleStateType.VISIBLE: 186 setVisible(enable); 187 break; 188 default: 189 if (Build.DEBUG) { 190 // System.err.println("[frame]: " + getTitle() + "unexpected state change " + state); 191 } 192 break; 193 } 194 } 195 196 /** Updates the accessible name and fires the appropriate PropertyChangedEvent */ handleNameChangedEvent(Object any)197 protected void handleNameChangedEvent(Object any) { 198 try { 199 // This causes the property change event to be fired in the VCL thread 200 // context. If this causes problems, it has to be deligated to the java 201 // dispatch thread .. 202 javax.accessibility.AccessibleContext ac = accessibleContext; 203 if (ac!= null) { 204 ac.setAccessibleName(AnyConverter.toString(any)); 205 } 206 } catch (com.sun.star.lang.IllegalArgumentException e) { 207 } 208 } 209 210 /** Updates the accessible description and fires the appropriate PropertyChangedEvent */ handleDescriptionChangedEvent(Object any)211 protected void handleDescriptionChangedEvent(Object any) { 212 try { 213 // This causes the property change event to be fired in the VCL thread 214 // context. If this causes problems, it has to be deligated to the java 215 // dispatch thread .. 216 if (accessibleContext != null) { 217 accessibleContext.setAccessibleDescription(AnyConverter.toString(any)); 218 } 219 } catch (com.sun.star.lang.IllegalArgumentException e) { 220 } 221 } 222 223 /** Updates the internal states and fires the appropriate PropertyChangedEvent */ handleStateChangedEvent(Object any1, Object any2)224 protected void handleStateChangedEvent(Object any1, Object any2) { 225 try { 226 if (AnyConverter.isShort(any1)) { 227 setComponentState(AnyConverter.toShort(any1), false); 228 } 229 230 if (AnyConverter.isShort(any2)) { 231 setComponentState(AnyConverter.toShort(any2), true); 232 } 233 } catch (com.sun.star.lang.IllegalArgumentException e) { 234 } 235 } 236 237 /** Fires a visible data property change event */ handleVisibleDataEvent()238 protected void handleVisibleDataEvent() { 239 javax.accessibility.AccessibleContext ac = accessibleContext; 240 if (ac != null) { 241 ac.firePropertyChange(javax.accessibility.AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY, null, null); 242 } 243 } 244 245 /** Called by OpenOffice process to notify property changes */ notifyEvent(AccessibleEventObject event)246 public void notifyEvent(AccessibleEventObject event) { 247 switch (event.EventId) { 248 case AccessibleEventId.NAME_CHANGED: 249 // Set the accessible name for the corresponding context, which will fire a property 250 // change event itself 251 handleNameChangedEvent(event.NewValue); 252 break; 253 case AccessibleEventId.DESCRIPTION_CHANGED: 254 // Set the accessible description for the corresponding context, which will fire a property 255 // change event itself - so do not set propertyName ! 256 handleDescriptionChangedEvent(event.NewValue); 257 break; 258 case AccessibleEventId.STATE_CHANGED: 259 // Update the internal state set and fire the appropriate PropertyChangedEvent 260 handleStateChangedEvent(event.OldValue, event.NewValue); 261 break; 262 case AccessibleEventId.CHILD: 263 if (AnyConverter.isObject(event.OldValue)) { 264 AccessibleObjectFactory.removeChild(Window.this, event.OldValue); 265 } else if (AnyConverter.isObject(event.NewValue)) { 266 AccessibleObjectFactory.addChild(Window.this, event.NewValue); 267 } 268 break; 269 case AccessibleEventId.VISIBLE_DATA_CHANGED: 270 case AccessibleEventId.BOUNDRECT_CHANGED: 271 handleVisibleDataEvent(); 272 break; 273 default: 274 // Warn about unhandled events 275 if(Build.DEBUG) { 276 System.out.println(this + ": unhandled accessibility event id=" + event.EventId); 277 } 278 } 279 } 280 281 /** Called by OpenOffice process to notify that the UNO component is disposing */ disposing(com.sun.star.lang.EventObject eventObject)282 public void disposing(com.sun.star.lang.EventObject eventObject) { 283 } 284 } 285 286 protected javax.accessibility.AccessibleContext accessibleContext = null; 287 288 /** Returns the AccessibleContext associated with this object */ getAccessibleContext()289 public javax.accessibility.AccessibleContext getAccessibleContext() { 290 if (accessibleContext == null) { 291 accessibleContext = new AccessibleWindow(); 292 // accessibleContext.setAccessibleName(getTitle()); 293 } 294 return accessibleContext; 295 } 296 297 protected class AccessibleWindow extends java.awt.Window.AccessibleAWTWindow { AccessibleWindow()298 protected AccessibleWindow() { 299 super(); 300 } 301 302 protected java.awt.event.ComponentListener accessibleComponentHandler = null; 303 304 /** 305 * Fire PropertyChange listener, if one is registered, 306 * when shown/hidden.. 307 */ 308 protected class AccessibleComponentHandler implements java.awt.event.ComponentListener { componentHidden(java.awt.event.ComponentEvent e)309 public void componentHidden(java.awt.event.ComponentEvent e) { 310 AccessibleWindow.this.firePropertyChange( 311 javax.accessibility.AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 312 javax.accessibility.AccessibleState.VISIBLE, null); 313 } 314 componentShown(java.awt.event.ComponentEvent e)315 public void componentShown(java.awt.event.ComponentEvent e) { 316 AccessibleWindow.this.firePropertyChange( 317 javax.accessibility.AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 318 null, javax.accessibility.AccessibleState.VISIBLE); 319 } 320 componentMoved(java.awt.event.ComponentEvent e)321 public void componentMoved(java.awt.event.ComponentEvent e) { 322 } 323 componentResized(java.awt.event.ComponentEvent e)324 public void componentResized(java.awt.event.ComponentEvent e) { 325 } 326 } // inner class AccessibleComponentHandler 327 328 protected java.awt.event.ContainerListener accessibleContainerHandler = null; 329 330 /** 331 * Fire PropertyChange listener, if one is registered, 332 * when children added/removed. 333 */ 334 335 protected class AccessibleContainerHandler implements java.awt.event.ContainerListener { componentAdded(java.awt.event.ContainerEvent e)336 public void componentAdded(java.awt.event.ContainerEvent e) { 337 java.awt.Component c = e.getChild(); 338 if (c != null && c instanceof javax.accessibility.Accessible) { 339 AccessibleWindow.this.firePropertyChange( 340 javax.accessibility.AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 341 null, ((javax.accessibility.Accessible) c).getAccessibleContext()); 342 } 343 } componentRemoved(java.awt.event.ContainerEvent e)344 public void componentRemoved(java.awt.event.ContainerEvent e) { 345 java.awt.Component c = e.getChild(); 346 if (c != null && c instanceof javax.accessibility.Accessible) { 347 AccessibleWindow.this.firePropertyChange( 348 javax.accessibility.AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 349 ((javax.accessibility.Accessible) c).getAccessibleContext(), null); 350 } 351 } 352 } 353 354 protected int propertyChangeListenerCount = 0; 355 356 /** 357 * Add a PropertyChangeListener to the listener list. 358 * 359 * @param listener The PropertyChangeListener to be added 360 */ addPropertyChangeListener(java.beans.PropertyChangeListener listener)361 public void addPropertyChangeListener(java.beans.PropertyChangeListener listener) { 362 if (propertyChangeListenerCount++ == 0) { 363 accessibleContainerHandler = new AccessibleContainerHandler(); 364 Window.this.addContainerListener(accessibleContainerHandler); 365 366 accessibleComponentHandler = new AccessibleComponentHandler(); 367 Window.this.addComponentListener(accessibleComponentHandler); 368 } 369 super.addPropertyChangeListener(listener); 370 } 371 372 /** 373 * Remove a PropertyChangeListener from the listener list. 374 * This removes a PropertyChangeListener that was registered 375 * for all properties. 376 * 377 * @param listener The PropertyChangeListener to be removed 378 */ removePropertyChangeListener(java.beans.PropertyChangeListener listener)379 public void removePropertyChangeListener(java.beans.PropertyChangeListener listener) { 380 if (--propertyChangeListenerCount == 0) { 381 Window.this.removeComponentListener(accessibleComponentHandler); 382 accessibleComponentHandler = null; 383 384 Window.this.removeContainerListener(accessibleContainerHandler); 385 accessibleContainerHandler = null; 386 } 387 super.removePropertyChangeListener(listener); 388 } 389 390 /* 391 * AccessibleComponent 392 */ 393 394 /** Returns the background color of the object */ getBackground()395 public java.awt.Color getBackground() { 396 try { 397 return new java.awt.Color(unoAccessibleComponent.getBackground()); 398 } catch (com.sun.star.uno.RuntimeException e) { 399 return null; 400 } 401 } 402 setBackground(java.awt.Color c)403 public void setBackground(java.awt.Color c) { 404 // Not supported by UNO accessibility API 405 } 406 407 /** Returns the foreground color of the object */ getForeground()408 public java.awt.Color getForeground() { 409 try { 410 return new java.awt.Color(unoAccessibleComponent.getForeground()); 411 } catch (com.sun.star.uno.RuntimeException e) { 412 return null; 413 } 414 } 415 setForeground(java.awt.Color c)416 public void setForeground(java.awt.Color c) { 417 // Not supported by UNO accessibility API 418 } 419 getCursor()420 public java.awt.Cursor getCursor() { 421 // Not supported by UNO accessibility API 422 return null; 423 } 424 setCursor(java.awt.Cursor cursor)425 public void setCursor(java.awt.Cursor cursor) { 426 // Not supported by UNO accessibility API 427 } 428 getFont()429 public java.awt.Font getFont() { 430 // FIXME 431 return null; 432 } 433 setFont(java.awt.Font f)434 public void setFont(java.awt.Font f) { 435 // Not supported by UNO accessibility API 436 } 437 getFontMetrics(java.awt.Font f)438 public java.awt.FontMetrics getFontMetrics(java.awt.Font f) { 439 // FIXME 440 return null; 441 } 442 isEnabled()443 public boolean isEnabled() { 444 return Window.this.isEnabled(); 445 } 446 setEnabled(boolean b)447 public void setEnabled(boolean b) { 448 // Not supported by UNO accessibility API 449 } 450 isVisible()451 public boolean isVisible() { 452 return Window.this.isVisible(); 453 } 454 setVisible(boolean b)455 public void setVisible(boolean b) { 456 // Not supported by UNO accessibility API 457 } 458 isShowing()459 public boolean isShowing() { 460 return Window.this.isShowing(); 461 } 462 contains(java.awt.Point p)463 public boolean contains(java.awt.Point p) { 464 try { 465 return unoAccessibleComponent.containsPoint(new com.sun.star.awt.Point(p.x, p.y)); 466 } catch (com.sun.star.uno.RuntimeException e) { 467 return false; 468 } 469 } 470 471 /** Returns the location of the object on the screen. */ getLocationOnScreen()472 public java.awt.Point getLocationOnScreen() { 473 try { 474 com.sun.star.awt.Point unoPoint = unoAccessibleComponent.getLocationOnScreen(); 475 return new java.awt.Point(unoPoint.X, unoPoint.Y); 476 } catch (com.sun.star.uno.RuntimeException e) { 477 return null; 478 } 479 } 480 481 /** Gets the location of this component in the form of a point specifying the component's top-left corner */ getLocation()482 public java.awt.Point getLocation() { 483 try { 484 com.sun.star.awt.Point unoPoint = unoAccessibleComponent.getLocationOnScreen(); 485 return new java.awt.Point( unoPoint.X, unoPoint.Y ); 486 } catch (com.sun.star.uno.RuntimeException e) { 487 return null; 488 } 489 } 490 491 /** Moves this component to a new location */ setLocation(java.awt.Point p)492 public void setLocation(java.awt.Point p) { 493 // Not supported by UNO accessibility API 494 } 495 496 /** Gets the bounds of this component in the form of a Rectangle object */ getBounds()497 public java.awt.Rectangle getBounds() { 498 try { 499 com.sun.star.awt.Rectangle unoRect = unoAccessibleComponent.getBounds(); 500 return new java.awt.Rectangle(unoRect.X, unoRect.Y, unoRect.Width, unoRect.Height); 501 } catch (com.sun.star.uno.RuntimeException e) { 502 return null; 503 } 504 } 505 506 /** Moves and resizes this component to conform to the new bounding rectangle r */ setBounds(java.awt.Rectangle r)507 public void setBounds(java.awt.Rectangle r) { 508 // Not supported by UNO accessibility API 509 } 510 511 /** Returns the size of this component in the form of a Dimension object */ getSize()512 public java.awt.Dimension getSize() { 513 try { 514 com.sun.star.awt.Size unoSize = unoAccessibleComponent.getSize(); 515 return new java.awt.Dimension(unoSize.Width, unoSize.Height); 516 } catch (com.sun.star.uno.RuntimeException e) { 517 return null; 518 } 519 } 520 521 /** Resizes this component so that it has width d.width and height d.height */ setSize(java.awt.Dimension d)522 public void setSize(java.awt.Dimension d) { 523 // Not supported by UNO accessibility API 524 } 525 526 /** Returns the Accessible child, if one exists, contained at the local coordinate Point */ getAccessibleAt(java.awt.Point p)527 public javax.accessibility.Accessible getAccessibleAt(java.awt.Point p) { 528 try { 529 java.awt.Component c = AccessibleObjectFactory.getAccessibleComponent( 530 unoAccessibleComponent.getAccessibleAtPoint(new com.sun.star.awt.Point(p.x, p.y))); 531 532 return (javax.accessibility.Accessible) c; 533 } catch (com.sun.star.uno.RuntimeException e) { 534 return null; 535 } 536 } 537 isFocusTraversable()538 public boolean isFocusTraversable() { 539 return Window.this.isFocusable(); 540 } 541 requestFocus()542 public void requestFocus() { 543 unoAccessibleComponent.grabFocus(); 544 } 545 } 546 547 /** 548 * Determines whether this component is displayable. A component is 549 * displayable when it is connected to a native screen resource. 550 * <p> 551 * A component is made displayable either when it is added to 552 * a displayable containment hierarchy or when its containment 553 * hierarchy is made displayable. 554 * A containment hierarchy is made displayable when its ancestor 555 * window is either packed or made visible. 556 * <p> 557 * A component is made undisplayable either when it is removed from 558 * a displayable containment hierarchy or when its containment hierarchy 559 * is made undisplayable. A containment hierarchy is made 560 * undisplayable when its ancestor window is disposed. 561 * 562 * @return <code>true</code> if the component is displayable 563 */ 564 @Override isDisplayable()565 public boolean isDisplayable() { 566 return true; 567 } 568 569 } 570 571