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