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