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