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