1 import com.sun.star.awt.XWindow; 2 import com.sun.star.beans.XPropertySet; 3 import com.sun.star.beans.XPropertyChangeListener; 4 import com.sun.star.beans.PropertyChangeEvent; 5 import com.sun.star.container.XEnumerationAccess; 6 import com.sun.star.container.XEnumeration; 7 import com.sun.star.document.XEventListener; 8 import com.sun.star.drawing.XDrawPage; 9 import com.sun.star.drawing.XDrawView; 10 import com.sun.star.frame.XController; 11 import com.sun.star.frame.XFrame; 12 import com.sun.star.frame.XFrameActionListener; 13 import com.sun.star.frame.FrameActionEvent; 14 import com.sun.star.frame.FrameAction; 15 import com.sun.star.lang.XComponent; 16 import com.sun.star.lang.XMultiServiceFactory; 17 import com.sun.star.lang.XServiceInfo; 18 import com.sun.star.frame.XDesktop; 19 import com.sun.star.frame.XModel; 20 import com.sun.star.frame.XTerminateListener; 21 import com.sun.star.uno.UnoRuntime; 22 23 import com.sun.star.accessibility.XAccessible; 24 import com.sun.star.accessibility.XAccessibleContext; 25 import com.sun.star.accessibility.XAccessibleComponent; 26 import com.sun.star.accessibility.XAccessibleExtendedComponent; 27 import com.sun.star.accessibility.XAccessibleRelationSet; 28 import com.sun.star.accessibility.XAccessibleStateSet; 29 30 import com.sun.star.awt.XExtendedToolkit; 31 32 import java.util.Vector; 33 import java.awt.*; 34 import java.awt.event.*; 35 import javax.swing.*; 36 import javax.swing.tree.*; 37 import javax.swing.event.TreeSelectionListener; 38 import javax.swing.event.TreeSelectionEvent; 39 import java.io.*; 40 41 import ov.ObjectViewContainer; 42 43 /** This class manages the GUI of the work bench. 44 @see AccessibilityTreeModel 45 for the implementation of the tree view on the left side which also 46 manages the registration of accessibility listeners. 47 @see Canvas 48 for the graphical view of the accessible objects. 49 */ 50 public class AccessibilityWorkBench 51 extends JFrame 52 implements ActionListener, XTerminateListener, TreeSelectionListener 53 54 { 55 public static final String msVersion = "v1.7.2"; 56 public String msOptionsFileName = ".AWBrc"; 57 58 public static void main (String args[]) 59 { 60 int nPortNumber = 5678; 61 62 for (int i=0; i<args.length; i++) 63 { 64 if (args[i].equals ("-h") || args[i].equals ("--help") || args[i].equals ("-?")) 65 { 66 System.out.println ("usage: AccessibilityWorkBench <option>*"); 67 System.out.println ("options:"); 68 System.out.println (" -p <port-number> Port on which to connect to StarOffice."); 69 System.out.println (" Defaults to 5678."); 70 System.exit (0); 71 } 72 else if (args[i].equals ("-p")) 73 { 74 nPortNumber = Integer.parseInt (args[++i]); 75 } 76 } 77 78 saWorkBench = new AccessibilityWorkBench (nPortNumber); 79 } 80 81 82 83 84 /** Return the one instance of the AccessibilityWorkBench 85 @return 86 Returns null when the AccessibilityWorkBench could not be 87 created successfully. 88 */ 89 public static AccessibilityWorkBench Instance () 90 { 91 return saWorkBench; 92 } 93 94 95 96 /** Create an accessibility work bench that listens at the specified 97 port to Office applications. 98 */ 99 private AccessibilityWorkBench (int nPortNumber) 100 { 101 mbInitialized = false; 102 103 Layout (); 104 105 MessageArea.println (System.getProperty ("os.name") + " / " 106 + System.getProperty ("os.arch") + " / " 107 + System.getProperty ("os.version")); 108 MessageArea.println ("Using port " + nPortNumber); 109 office = new SimpleOffice (nPortNumber); 110 info = new InformationWriter (); 111 112 maAccessibilityTree.getComponent().addTreeSelectionListener (this); 113 114 addWindowListener (new WindowAdapter () 115 { public void windowClosing (WindowEvent e) 116 { System.exit(0); } 117 }); 118 119 initialize (); 120 } 121 122 123 124 125 /** Create and arrange the widgets of the GUI. 126 */ 127 public void Layout () 128 { 129 setSize (new Dimension (8000,600)); 130 131 JScrollPane aScrollPane; 132 GridBagConstraints constraints; 133 134 // Create new layout. 135 GridBagLayout aLayout = new GridBagLayout (); 136 getContentPane().setLayout (aLayout); 137 138 // Accessible Tree. 139 maAccessibilityTree = new AccessibilityTree (); 140 // maAccessibilityTree.getComponent().setMinimumSize (new Dimension (250,300)); 141 JScrollPane aTreeScrollPane = new JScrollPane( 142 maAccessibilityTree.getComponent(), 143 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 144 JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 145 aTreeScrollPane.setPreferredSize (new Dimension (400,300)); 146 147 // Object view shows details about the currently selected accessible 148 // object. 149 maObjectViewContainer = new ObjectViewContainer (); 150 // maObjectViewContainer.setPreferredSize (new Dimension (300,100)); 151 JScrollPane aObjectViewContainerScrollPane = new JScrollPane( 152 maObjectViewContainer, 153 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 154 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 155 aObjectViewContainerScrollPane.setPreferredSize (new Dimension (400,300)); 156 157 // Split pane for tree view and object view. 158 JSplitPane aLeftViewSplitPane = new JSplitPane ( 159 JSplitPane.VERTICAL_SPLIT, 160 aTreeScrollPane, 161 aObjectViewContainerScrollPane 162 ); 163 aLeftViewSplitPane.setDividerLocation (300); 164 165 // Canvas. 166 maCanvas = new Canvas (); 167 maCanvas.setTree (maAccessibilityTree.getComponent()); 168 maAccessibilityTree.SetCanvas (maCanvas); 169 JScrollPane aScrolledCanvas = new JScrollPane(maCanvas, 170 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 171 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 172 aScrolledCanvas.getViewport().setBackground (Color.RED); 173 aScrolledCanvas.setPreferredSize (new Dimension(600,400)); 174 175 // Split pane for tree view and canvas. 176 JSplitPane aViewSplitPane = new JSplitPane ( 177 JSplitPane.HORIZONTAL_SPLIT, 178 aLeftViewSplitPane, 179 aScrolledCanvas 180 ); 181 aViewSplitPane.setOneTouchExpandable(true); 182 aViewSplitPane.setDividerLocation (400); 183 184 // Text output area. 185 maMessageArea = MessageArea.Instance (); 186 // maMessageArea.setPreferredSize (new Dimension (300,50)); 187 188 // Split pane for the two views and the message area. 189 JSplitPane aSplitPane = new JSplitPane (JSplitPane.VERTICAL_SPLIT, 190 aViewSplitPane, maMessageArea); 191 aSplitPane.setOneTouchExpandable(true); 192 addGridElement (aViewSplitPane, 0,0, 2,1, 3,3, 193 GridBagConstraints.CENTER, GridBagConstraints.BOTH); 194 195 // Button bar. 196 maButtonBar = new JPanel(); 197 GridBagLayout aButtonLayout = new GridBagLayout (); 198 maButtonBar.setLayout (new FlowLayout()); 199 addGridElement (maButtonBar, 0,3, 2,1, 1,0, 200 GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL); 201 202 // Buttons. 203 aConnectButton = createButton ("Connect", "connect"); 204 aUpdateButton = createButton ("Update", "update"); 205 aShapesButton = createButton ("Expand Shapes", "shapes"); 206 aExpandButton = createButton ("Expand All", "expand"); 207 aQuitButton = createButton ("Quit", "quit"); 208 UpdateButtonStates (); 209 210 Options.Instance().Load (msOptionsFileName); 211 212 setJMenuBar (CreateMenuBar ()); 213 214 setTitle("Accessibility Workbench " + msVersion); 215 216 pack (); 217 setVisible (true); 218 validate (); 219 repaint(); 220 } 221 222 223 224 225 /** Shortcut method for adding an object to a GridBagLayout. 226 */ 227 void addGridElement (JComponent object, 228 int x, int y, int width, int height, int weightx, int weighty, 229 int anchor, int fill) 230 { 231 GridBagConstraints constraints = new GridBagConstraints (); 232 constraints.gridx = x; 233 constraints.gridy = y; 234 constraints.gridwidth = width; 235 constraints.gridheight = height; 236 constraints.weightx = weightx; 237 constraints.weighty = weighty; 238 constraints.anchor = anchor; 239 constraints.fill = fill; 240 getContentPane().add (object, constraints); 241 } 242 243 244 245 246 /** Create a new button and place at the right most position into the 247 button bar. 248 */ 249 public JButton createButton (String title, String command) 250 { 251 JButton aButton = new JButton (title); 252 aButton.setEnabled (false); 253 aButton.setActionCommand (command); 254 aButton.addActionListener (this); 255 256 maButtonBar.add (aButton); 257 return aButton; 258 } 259 260 261 262 263 /** Create a menu bar for the application. 264 @return 265 Returns the new menu bar. The returned reference is also 266 remembered in the data member <member>maMenuBar</member>. 267 */ 268 JMenuBar CreateMenuBar () 269 { 270 // Menu bar. 271 maMenuBar = new JMenuBar (); 272 273 // File menu. 274 JMenu aFileMenu = new JMenu ("File"); 275 maMenuBar.add (aFileMenu); 276 JMenuItem aItem; 277 aItem = new JMenuItem ("Quit"); 278 aFileMenu.add (aItem); 279 aItem.addActionListener (this); 280 281 // View menu. 282 JMenu aViewMenu = new JMenu ("View"); 283 maMenuBar.add (aViewMenu); 284 ButtonGroup aGroup = new ButtonGroup (); 285 JRadioButtonMenuItem aRadioButton = new JRadioButtonMenuItem ("Whole Screen"); 286 aGroup.add (aRadioButton); 287 aViewMenu.add (aRadioButton); 288 aRadioButton.addActionListener (this); 289 aRadioButton = new JRadioButtonMenuItem ("200%"); 290 aGroup.add (aRadioButton); 291 aViewMenu.add (aRadioButton); 292 aRadioButton.addActionListener (this); 293 aRadioButton = new JRadioButtonMenuItem ("100%"); 294 aGroup.add (aRadioButton); 295 aViewMenu.add (aRadioButton); 296 aRadioButton.addActionListener (this); 297 aRadioButton = new JRadioButtonMenuItem ("50%"); 298 aGroup.add (aRadioButton); 299 aViewMenu.add (aRadioButton); 300 aRadioButton.addActionListener (this); 301 aRadioButton = new JRadioButtonMenuItem ("25%"); 302 aGroup.add (aRadioButton); 303 aViewMenu.add (aRadioButton); 304 aRadioButton.addActionListener (this); 305 aRadioButton = new JRadioButtonMenuItem ("10%"); 306 aGroup.add (aRadioButton); 307 aViewMenu.add (aRadioButton); 308 aRadioButton.addActionListener (this); 309 310 // Options menu. 311 JMenu aOptionsMenu = new JMenu ("Options"); 312 maMenuBar.add (aOptionsMenu); 313 JCheckBoxMenuItem aCBItem; 314 aCBItem = new JCheckBoxMenuItem ("Show Descriptions", maCanvas.getShowDescriptions()); 315 aOptionsMenu.add (aCBItem); 316 aCBItem.addActionListener (this); 317 318 aCBItem = new JCheckBoxMenuItem ("Show Names", maCanvas.getShowNames()); 319 aOptionsMenu.add (aCBItem); 320 aCBItem.addActionListener (this); 321 322 aCBItem = new JCheckBoxMenuItem ("Show Text", maCanvas.getShowText()); 323 aOptionsMenu.add (aCBItem); 324 aCBItem.addActionListener (this); 325 326 aCBItem = new JCheckBoxMenuItem ("Antialiased Rendering", maCanvas.getAntialiasing()); 327 aOptionsMenu.add (aCBItem); 328 aCBItem.addActionListener (this); 329 330 // Help menu. 331 JMenu aHelpMenu = new JMenu ("Help"); 332 maMenuBar.add (aHelpMenu); 333 334 aItem = new JMenuItem ("Help"); 335 aHelpMenu.add (aItem); 336 aItem.addActionListener (this); 337 338 aItem = new JMenuItem ("News"); 339 aHelpMenu.add (aItem); 340 aItem.addActionListener (this); 341 342 aItem = new JMenuItem ("About"); 343 aHelpMenu.add (aItem); 344 aItem.addActionListener (this); 345 346 return maMenuBar; 347 } 348 349 350 351 352 /** Initialize the AWB. This includes clearing the canvas, add 353 listeners, creation of a new tree model for the tree list box and 354 the update of the button states. 355 356 This method may be called any number of times. Note that all 357 actions will be carried out every time. The main purpose of a 358 second call is that of a re-initialization after a reconnect. 359 */ 360 protected void initialize () 361 { 362 maCanvas.clear(); 363 364 AccessibilityTreeModel aModel = null; 365 aModel = new AccessibilityTreeModel (createTreeModelRoot()); 366 367 aModel.setCanvas (maCanvas); 368 maAccessibilityTree.getComponent().setModel (aModel); 369 370 if (office != null) 371 { 372 // Add terminate listener. 373 if (office.getDesktop() != null) 374 office.getDesktop().addTerminateListener (this); 375 376 XExtendedToolkit xToolkit = office.getExtendedToolkit(); 377 // Remove old top window listener. 378 if (maTopWindowListener != null) 379 xToolkit.removeTopWindowListener (maQueuedTopWindowListener); 380 // Add top window listener. 381 if (xToolkit != null) 382 { 383 MessageArea.println ("registering at extended toolkit"); 384 maTopWindowListener = new TopWindowListener (aModel, office); 385 maQueuedTopWindowListener = new QueuedTopWindowListener (maTopWindowListener); 386 xToolkit.addTopWindowListener (maQueuedTopWindowListener); 387 maTopWindowListener.Initialize (); 388 } 389 else 390 maTopWindowListener = null; 391 } 392 393 mbInitialized = true; 394 UpdateButtonStates (); 395 } 396 397 398 399 400 /** Update the states of the buttons according to the internal state of 401 the AWB. 402 */ 403 protected void UpdateButtonStates () 404 { 405 aConnectButton.setEnabled (mbInitialized); 406 aQuitButton.setEnabled (mbInitialized); 407 aUpdateButton.setEnabled (mbInitialized); 408 aExpandButton.setEnabled (mbInitialized); 409 aShapesButton.setEnabled (mbInitialized); 410 } 411 412 413 414 /** Callback for GUI actions from the buttons. 415 */ 416 public void actionPerformed (java.awt.event.ActionEvent e) 417 { 418 if (e.getActionCommand().equals("connect")) 419 { 420 office.connect(); 421 initialize (); 422 } 423 else if (e.getActionCommand().equals("quit")) 424 { 425 AccessibilityTreeModel aModel = (AccessibilityTreeModel)maAccessibilityTree.getComponent().getModel(); 426 aModel.clear(); 427 System.exit (0); 428 } 429 else if (e.getActionCommand().equals("update")) 430 { 431 initialize (); 432 } 433 else if (e.getActionCommand().equals("shapes")) 434 { 435 Cursor aCursor = getCursor(); 436 setCursor (new Cursor (Cursor.WAIT_CURSOR)); 437 maAccessibilityTree.expandShapes(); 438 setCursor (aCursor); 439 } 440 else if (e.getActionCommand().equals("expand")) 441 { 442 Cursor aCursor = getCursor(); 443 setCursor (new Cursor (Cursor.WAIT_CURSOR)); 444 maAccessibilityTree.expandAll(); 445 setCursor (aCursor); 446 } 447 else if (e.getActionCommand().equals ("Quit")) 448 { 449 System.out.println ("exiting"); 450 System.exit (0); 451 } 452 else if (e.getActionCommand().equals ("Show Descriptions")) 453 { 454 maCanvas.setShowDescriptions ( ! maCanvas.getShowDescriptions()); 455 Options.Instance().Save (msOptionsFileName); 456 } 457 else if (e.getActionCommand().equals ("Show Names")) 458 { 459 maCanvas.setShowNames ( ! maCanvas.getShowNames()); 460 Options.Instance().Save (msOptionsFileName); 461 } 462 else if (e.getActionCommand().equals ("Antialiased Rendering")) 463 { 464 maCanvas.setAntialiasing ( ! maCanvas.getAntialiasing()); 465 Options.Instance().Save (msOptionsFileName); 466 } 467 else if (e.getActionCommand().equals ("Help")) 468 { 469 HelpWindow.Instance().loadFile ("help.html"); 470 } 471 else if (e.getActionCommand().equals ("News")) 472 { 473 try{ 474 HelpWindow.Instance().loadFile ("news.html"); 475 } catch (Exception ex) {} 476 } 477 else if (e.getActionCommand().equals ("About")) 478 { 479 HelpWindow.Instance().loadFile ("about.html"); 480 } 481 else if (e.getActionCommand().equals ("Whole Screen")) 482 { 483 maCanvas.setZoomMode (Canvas.WHOLE_SCREEN); 484 Options.Instance().Save (msOptionsFileName); 485 } 486 else if (e.getActionCommand().equals ("200%")) 487 { 488 maCanvas.setZoomMode (200); 489 Options.Instance().Save (msOptionsFileName); 490 } 491 else if (e.getActionCommand().equals ("100%")) 492 { 493 maCanvas.setZoomMode (100); 494 Options.Instance().Save (msOptionsFileName); 495 } 496 else if (e.getActionCommand().equals ("50%")) 497 { 498 maCanvas.setZoomMode (50); 499 Options.Instance().Save (msOptionsFileName); 500 } 501 else if (e.getActionCommand().equals ("25%")) 502 { 503 maCanvas.setZoomMode (25); 504 Options.Instance().Save (msOptionsFileName); 505 } 506 else if (e.getActionCommand().equals ("10%")) 507 { 508 maCanvas.setZoomMode (10); 509 Options.Instance().Save (msOptionsFileName); 510 } 511 else 512 { 513 System.err.println("unknown command " + e.getActionCommand()); 514 } 515 } 516 517 518 519 520 /** Create an AccessibilityTreeModel root which contains the documents 521 (top windows) that are present at the moment. 522 */ 523 private AccessibleTreeNode createTreeModelRoot() 524 { 525 // create root node 526 VectorNode aRoot = new VectorNode ("Accessibility Tree", null); 527 if (maTopWindowListener != null) 528 maTopWindowListener.Initialize (); 529 return aRoot; 530 } 531 532 533 // TreeSelectionListener 534 public void valueChanged (TreeSelectionEvent aEvent) 535 { 536 TreePath aPath = aEvent.getPath(); 537 Object aObject = aPath.getLastPathComponent(); 538 if (aObject instanceof AccTreeNode) 539 { 540 AccTreeNode aNode = (AccTreeNode) aObject; 541 XAccessibleContext xContext = aNode.getContext(); 542 maObjectViewContainer.SetObject (xContext); 543 } 544 } 545 546 547 548 549 // XEventListener 550 public void disposing( com.sun.star.lang.EventObject aSourceObj ) 551 { 552 XFrame xFrame = (XFrame)UnoRuntime.queryInterface(XFrame.class, aSourceObj.Source); 553 554 if( xFrame != null ) 555 System.out.println("frame disposed"); 556 else 557 System.out.println("controller disposed"); 558 } 559 560 561 562 563 // XTerminateListener 564 public void queryTermination (final com.sun.star.lang.EventObject aEvent) throws RuntimeException 565 { 566 System.out.println ("Terminate Event : " + aEvent); 567 } 568 569 570 571 572 // XTerminateListener 573 public void notifyTermination (final com.sun.star.lang.EventObject aEvent) throws RuntimeException 574 { 575 System.out.println ("Notifiy Termination Event : " + aEvent); 576 } 577 578 579 580 /// The Singleton Workbench object. 581 private static AccessibilityWorkBench 582 saWorkBench = null; 583 584 protected SimpleOffice 585 office; 586 protected InformationWriter 587 info; 588 589 private XModel 590 mxModel; 591 private JPanel 592 maMainPanel, 593 maButtonBar; 594 private Canvas 595 maCanvas; 596 private AccessibilityTree 597 maAccessibilityTree; 598 private ObjectViewContainer 599 maObjectViewContainer; 600 private JScrollPane 601 maScrollPane; 602 private MessageArea 603 maMessageArea; 604 private JButton 605 aConnectButton, 606 aQuitButton, 607 aUpdateButton, 608 aExpandButton, 609 aShapesButton; 610 private JMenuBar 611 maMenuBar; 612 private String 613 msMessage; 614 private boolean 615 mbInitialized; 616 private TopWindowListener 617 maTopWindowListener; 618 private QueuedTopWindowListener 619 maQueuedTopWindowListener; 620 } 621