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