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