1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 package complex.XUserInputInterception;
29 
30 import com.sun.star.accessibility.AccessibleRole;
31 import com.sun.star.accessibility.XAccessible;
32 import com.sun.star.accessibility.XAccessibleComponent;
33 import com.sun.star.accessibility.XAccessibleContext;
34 import com.sun.star.awt.KeyEvent;
35 import com.sun.star.awt.MouseEvent;
36 import com.sun.star.awt.Point;
37 import com.sun.star.awt.Rectangle;
38 import com.sun.star.awt.XKeyHandler;
39 import com.sun.star.awt.XMouseClickHandler;
40 import com.sun.star.awt.XUserInputInterception;
41 import com.sun.star.awt.XWindow;
42 import com.sun.star.chart.XChartDocument;
43 import com.sun.star.frame.*;
44 import com.sun.star.lang.*;
45 import com.sun.star.lang.EventObject;
46 import com.sun.star.sheet.XSpreadsheetDocument;
47 import com.sun.star.text.XTextDocument;
48 import com.sun.star.uno.UnoRuntime;
49 import com.sun.star.uno.XInterface;
50 import com.sun.star.util.*;
51 import java.awt.Robot;
52 import java.awt.event.InputEvent;
53 
54 import util.AccessibilityTools;
55 import util.SOfficeFactory;
56 
57 // ---------- junit imports -----------------
58 import org.junit.After;
59 import org.junit.AfterClass;
60 import org.junit.Before;
61 import org.junit.BeforeClass;
62 import org.junit.Test;
63 import org.openoffice.test.OfficeConnection;
64 import static org.junit.Assert.*;
65 // ------------------------------------------
66 //-----------------------------------------------
67 /**
68  * This <CODE>ComplexTest</CODE> checks the interface
69  * <CODE>XUserInputInterception</CODE>. Therefore it creates a document,
70  * adds a mouse and a key listener onto the interface and fire the
71  * correspond events. If all listener works as expected the test resluts in
72  * <CODE>OK</CODE> status.
73  * @short Check the interface XUserInputIntercaption
74  * @descr checks is a simple way the interface XUserInputInteraction
75  */
76 public class EventTest {
77     //-------------------------------------------
78     // some const
79 
80     //-------------------------------------------
81     // member
82 
83     /** points to the global uno service manager. */
84     private XMultiServiceFactory m_xMSF = null;
85 
86     /** indicates if the mousePressed event was called*/
87     private boolean m_mousePressed = false;
88     /** indicates if the mouseReleased event was called*/
89     private boolean m_mouseReleased = false;
90 
91     /** indicates if the mousePressed event was called*/
92     private boolean m_keyPressed = false;
93     /** indicates if the mouseReleased event was called*/
94     private boolean m_keyReleased = false;
95 
96     /** points to a global StarOffice factory */
97     private SOfficeFactory m_SOF = null;
98 
99     /**
100      * define the miliseconds to wait until a <CODE>EventTrigger</CODE> thread should
101      * be finished with its work
102      */
103     final int m_threadWait = 3000;
104 
105     //-------------------------------------------
106     // test environment
107 
108     //-------------------------------------------
109     /**
110      * The test methods are:
111      * <ul>
112      *    <li><CODE>checkTextDocument</CODE></LI>
113      *    <li><CODE>checkCalcDocument</CODE></LI>
114      *    <li><CODE>checkDrawDocument</CODE></LI>
115      *    <li><CODE>checkImpressDocument</CODE></LI>
116      *    <li><CODE>checkChartDocument</CODE></LI>
117      *    <li><CODE>checkMathDocument</CODE></li>
118      * </ul>
119      * @short A function to tell the framework,
120      * which test functions are available.
121      * @return All test methods.
122      * @todo Think about selection of tests from outside ...
123      */
124 //    public String[] getTestMethodNames() {
125 //        return new String[]
126 //        { "checkTextDocument",
127 //          "checkCalcDocument",
128 //          "checkDrawDocument",
129 //          "checkImpressDocument",
130 //          "checkChartDocument",
131 //          "checkMathDocument",
132 //        };
133 //    }
134 
135     //-------------------------------------------
136     /**
137      * creates the mebmer <CODE>m_xMSF</CODE> and <CODE>m_SOF</CODE>
138      * @short Create the environment for following tests.
139      * @descr create an empty test frame, where we can load
140      * different components inside.
141      */
142 @Before public void before() {
143         // get uno service manager from global test environment
144         m_xMSF = getMSF();
145 
146         // create frame instance
147         try {
148             // get a soffice factory object
149             m_SOF = SOfficeFactory.getFactory(getMSF());
150 
151         } catch(java.lang.Throwable ex) {
152             fail("Could not create the XUserInputInterception instance.");
153         }
154     }
155 
156     //-------------------------------------------
157     /**
158      * closes the document
159      * @short close the document.
160      * @param xDoc the document to close
161      */
162     public void closeDoc(XInterface xDoc) {
163         XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xDoc);
164         try {
165             xClose.close(false);
166         } catch(com.sun.star.util.CloseVetoException exVeto) {
167             System.out.println("document couldn't be closed successfully.");
168         }
169     }
170 
171     /**
172      * creates a text document and check the <CODE>XMouseClickHandler</CODE> and
173      * <CODE>XKeyHandler</CODE>
174      * @see com.sun.star.awt.XKeyHandler
175      * @see com.sun.star.awt.XMouseClickHandler
176      */
177     @Test public void checkTextDocument(){
178 
179         XTextDocument xDoc = null;
180 
181         try{
182             xDoc = m_SOF.createTextDoc("WriterTest");
183         } catch (com.sun.star.uno.Exception e){
184             fail("Could not create a text document: " +e.toString());
185         }
186 
187         checkListener(xDoc);
188 
189         closeDoc(xDoc);
190     }
191 
192     /**
193      * creates an impress document and check the <CODE>XMouseClickHandler</CODE> and
194      * <CODE>XKeyHandler</CODE>
195      * @see com.sun.star.awt.XKeyHandler
196      * @see com.sun.star.awt.XMouseClickHandler
197      */
198     @Test public void checkImpressDocument(){
199 
200         XComponent xDoc = null;
201 
202         try{
203             xDoc = m_SOF.createImpressDoc("ImpressTest");
204         } catch (com.sun.star.uno.Exception e){
205             fail("Could not create an impress document: " +e.toString());
206         }
207 
208         checkListener(xDoc);
209 
210         closeDoc(xDoc);
211     }
212 
213     /**
214      * creates a chart document and check the <CODE>XMouseClickHandler</CODE> and
215      * <CODE>XKeyHandler</CODE>
216      * @see com.sun.star.awt.XKeyHandler
217      * @see com.sun.star.awt.XMouseClickHandler
218      */
219 // TODO!
220 //    @Test public void checkChartDocument(){
221 //
222 //        XChartDocument xDoc = null;
223 //
224 //        try{
225 //            xDoc = m_SOF.createChartDoc("ChartTest");
226 //        } catch (com.sun.star.uno.Exception e){
227 //            fail("Could not create a chart document: " +e.toString());
228 //        }
229 //
230 //        checkListener(xDoc);
231 //
232 //        closeDoc(xDoc);
233 //    }
234 
235     /**
236      * creates a math document and check the <CODE>XMouseClickHandler</CODE> and
237      * <CODE>XKeyHandler</CODE>
238      * @see com.sun.star.awt.XKeyHandler
239      * @see com.sun.star.awt.XMouseClickHandler
240      */
241     @Test public void checkMathDocument(){
242 
243         XComponent xDoc = null;
244 
245         try{
246             xDoc = m_SOF.createMathDoc("MathTest");
247         } catch (com.sun.star.uno.Exception e){
248             fail("Could not create a math document: " +e.toString());
249         }
250 
251         checkListener(xDoc);
252 
253         closeDoc(xDoc);
254     }
255 
256     /**
257      * creates a draw document and check the <CODE>XMouseClickHandler</CODE> and
258      * <CODE>XKeyHandler</CODE>
259      * @see com.sun.star.awt.XKeyHandler
260      * @see com.sun.star.awt.XMouseClickHandler
261      */
262     @Test public void checkDrawDocument(){
263 
264         XComponent xDoc = null;
265 
266         try{
267             xDoc = m_SOF.createDrawDoc("DrawTest");
268         } catch (com.sun.star.uno.Exception e){
269             fail("Could not create a draw document: " +e.toString());
270         }
271 
272         checkListener(xDoc);
273 
274         closeDoc(xDoc);
275     }
276 
277     /**
278      * creates a calc document and check the <CODE>XMouseClickHandler</CODE> and
279      * <CODE>XKeyHandler</CODE>
280      * @see com.sun.star.awt.XKeyHandler
281      * @see com.sun.star.awt.XMouseClickHandler
282      */
283     @Test public void checkCalcDocument(){
284 
285         XSpreadsheetDocument xDoc = null;
286 
287         try{
288             xDoc = m_SOF.createCalcDoc("CalcTest");
289         } catch (com.sun.star.uno.Exception e){
290             fail("Could not create a calc document: " +e.toString());
291         }
292 
293         checkListener(xDoc);
294         closeDoc(xDoc);
295     }
296 
297     /**
298      * This is the central test method. It is called by ceck[DOCTYPE]Document. It
299      * creates the <CODE>XUserInputInterception</CODE> from the document and call the
300      * <CODE>checkMouseListener</CODE> test and the <CODE>checkKeyListener</CODE> test
301      * @param xDoc the document to test
302      */
303     private void checkListener(XInterface xDoc){
304 
305         XModel xModel = UnoRuntime.queryInterface(XModel.class, xDoc);
306 
307         XUserInputInterception xUII = getUII(xModel);
308 
309         checkMouseListener(xUII, xModel);
310         checkKeyListener(xUII, xModel);
311     }
312 
313     /**
314      * Creates a <CODE>MyKeyHandler</CODE> and adds it to the
315      * <CODE>XUserInputInterception</CODE>. Then an <CODE>EventTrigger</CODE> thread
316      * was created and started.
317      * Has <CODE>OK</CODE> if the members <CODE>m_keyPressed</CODE> and
318      * <CODE>m_keyReleased</CODE> are <CODE>TRUE</CODE>
319      * @param xUII the XUserInputInterception
320      * @param xModel the XModel of a document
321      * @see EventTest.MyKeyHander
322      * @see EventTest.EventTrigger
323      */
324     private void checkKeyListener(XUserInputInterception xUII, XModel xModel) {
325         m_keyPressed = false;
326         m_keyReleased = false;
327 
328         MyKeyHandler keyListener = new MyKeyHandler();
329 
330         xUII.addKeyHandler(keyListener);
331 
332         System.out.println("starting thread to check the key listener...");
333         EventTrigger et = new EventTrigger(xModel, EventTriggerType.KEY_TEXT_INTO_DOC);
334 
335         et.run();
336 
337         util.utils.shortWait(m_threadWait);
338         System.out.println("key listener thread should be finished.");
339 
340         assertTrue("key event does not work!", m_keyPressed && m_keyReleased);
341         xUII.removeKeyHandler(keyListener);
342 
343     }
344 
345     /**
346      * Creates a <CODE>MyMouseClickHandler</CODE> and adds it to the
347      * <CODE>XUserInputInterception</CODE>. Then an <CODE>EventTrigger</CODE> thread
348      * was created and started.
349      * Has <CODE>OK</CODE> if the members <CODE>m_mousePressed</CODE> and
350      * <CODE>m_mouseReleased</CODE> are <CODE>TRUE</CODE>
351      * @param xUII the XUserInputInterception
352      * @param xModel the XModel of a document
353      * @see EventTest.MyMouseClickHander
354      * @see EventTest.EventTrigger
355      */
356 
357     private void checkMouseListener(XUserInputInterception xUII, XModel xModel) {
358 
359         m_mousePressed = false;
360         m_mouseReleased = false;
361 
362         MyMouseClickHandler mouseListener = new MyMouseClickHandler();
363 
364         xUII.addMouseClickHandler(mouseListener);
365 
366         System.out.println("starting thread to check the mouse listener...");
367         EventTrigger et = new EventTrigger(xModel, EventTriggerType.MOUSE_KLICK_INTO_DOC);
368 
369         et.run();
370 
371         util.utils.shortWait(m_threadWait);
372         System.out.println("mouse listener thread should be finished.");
373 
374         assertTrue("mouse event does not work!", m_mousePressed && m_mouseReleased);
375         xUII.removeMouseClickHandler(mouseListener);
376     }
377 
378     /**
379      * returns the <CODE>XUserInputInterception</CODE> from the <CODE>XMdoel</CODE>
380      * @param xModel the XModel of a document
381      * @return the <CODE>XUserInputInterception</CODE> of the document
382      */
383     private XUserInputInterception getUII(XModel xModel){
384 
385         XController xController = xModel.getCurrentController();
386 
387         XUserInputInterception xUII = UnoRuntime.queryInterface(XUserInputInterception.class, xController);
388         if (xUII == null) {
389             fail("could not get XUserInputInterception from XContoller");
390         }
391          return xUII;
392     }
393 
394     /**
395      * Listener which added and its method must be called
396      * on <code>keyPressed</code> and <code>keyReleased</code> call.
397      */
398     public class MyKeyHandler implements XKeyHandler {
399         /**
400          * This event sets the member <code>m_keyPressed</coed> to
401          *  <code>true</code>
402          * @param oEvent The key event informs about the pressed key.
403          * @return returns <CODE>TRUE</CODE> in erery case
404          */
405         public boolean keyPressed( KeyEvent oEvent ){
406             System.out.println("XKeyHandler: keyPressed-Event");
407             m_keyPressed = true;
408             return true;
409         }
410         /**
411          * This event sets the member <code>m_keyReleased</coed> to
412          *  <code>true</code>
413          * @param oEvent The key event informs about the pressed key.
414          * @return returns <CODE>TRUE</CODE> in erery case
415          */
416         public boolean keyReleased( KeyEvent oEvent ){
417             System.out.println("XKeyHandler: keyReleased-Event");
418             m_keyReleased = true;
419             return true;
420         }
421         /**
422          * This event does nothing usefull
423          * @param oEvent refers to the object that fired the event.
424          */
425         public void disposing( EventObject oEvent ){
426             System.out.println("XKeyHandler: disposing-Event");
427         }
428     }
429 
430     /**
431      * Listener which added and its method must be called
432      * on <code>mousePressed</code> and <code>mouseReleased</code> call.
433      */
434     public class MyMouseClickHandler implements XMouseClickHandler {
435         /**
436          * This event sets the member <code>m_mousePressed</coed> to
437          *  <code>true</code>
438          * @param oEvent The mouse event informs about the kind of mouse event.
439          * @return returns <CODE>TRUE</CODE> in erery case
440          */
441         public boolean mousePressed( MouseEvent oEvent ){
442             System.out.println("XMouseClickHandler: mousePressed-Event");
443             m_mousePressed = true;
444             return true;
445         }
446         /**
447          * This event sets the member <code>m_mouseReleased</coed> to
448          *  <code>true</code>
449          * @param oEvent The mouse event informs about the kind of mouse event.
450          * @return returns <CODE>TRUE</CODE> in erery case
451          */
452         public boolean mouseReleased( MouseEvent oEvent ){
453             System.out.println("XMouseClickHandler: mouseReleased-Event");
454             m_mouseReleased = true;
455             return true;
456         }
457         /**
458          * This event does nothing usefull
459          * @param oEvent refers to the object that fired the event.
460          */
461         public void disposing( EventObject oEvent ){
462             System.out.println("XMouseClickHandler: disposing-Event");
463         }
464     };
465 
466     /**
467      * To check the events this class is a thread which click a mouse button and
468      * press a key with the <CODE>Robot</CODE> class
469      * @see java.awt.Robot
470      */
471     private class EventTrigger extends Thread{
472 
473         /**
474          * represents a <CODE>AccessibilityTools</CODE>
475          */
476         private final AccessibilityTools at = new AccessibilityTools();
477         /**
478          * represents an <CODE>EventType</CODE>
479          * @see EventTest.EventTriggerType
480          */
481         private int eventType = 0;
482         /**
483          * represents a <CODE>XModel</CODE> of a document
484          */
485         private XModel xModel = null;
486 
487         /**
488          * Creates an instacne of this class. The parameter <CODE>eType</CODE> represents
489          * the kind of event wich will be triggert at <CODE>run()</CODE>
490          * @param model the model of a document
491          * @param eType the kind of event which should be trigger
492          */
493         public EventTrigger(XModel model, int eType)
494         {
495             this.xModel = model;
496             this.eventType = eType;
497         }
498 
499         /**
500          * Triggers the event wich is represented by <CODE>eventType</CODE>
501          * The scenarios are:
502          * <ul>
503          *    <li>EventTest.EventTriggerType.MOUSE_KLICK_INTO_DOC
504          *        which calls
505          *        <li><CODE>clickIntoDoc</CODE></LI>
506          *        </LI>
507          *    <li>EventTest.EventTriggerType.KEY_TEXT_INTO_DOC
508          *        which calls
509          *            <li><CODE>clickIntodoc</CODE></LI>
510          *            <li><CODE>keyIntoDoc</CODE></LI>
511          *    </LI>
512          * </UL>
513          */
514         public void run(){
515 
516             switch (this.eventType){
517 
518                 case EventTriggerType.MOUSE_KLICK_INTO_DOC:
519                     clickIntoDoc();
520                     break;
521                 case EventTriggerType.KEY_TEXT_INTO_DOC:
522                     clickIntoDoc();
523                     keyIntoDoc();
524                     break;
525 
526             }
527         }
528         /**
529          * This method cklicks into the middel of a document. It uses Accessibility
530          * to get the document and query for its position and its range to calculate
531          * the middle. This values was used for <CODE>Robot</CODE> Class. This
532          * Robot class is able to move the mouse and to cklick a mouse button
533          * @see java.awt.Robot
534         */
535         private void clickIntoDoc(){
536             try{
537                 // get the position and the range of a scroll bar
538 
539                 XWindow xWindow = at.getCurrentWindow(
540                                           getMSF(),
541                                           xModel);
542 
543                 XAccessible xRoot = at.getAccessibleObject(xWindow);
544 
545 
546 
547                 XAccessibleContext xPanel = at.getAccessibleObjectForRole(xRoot, AccessibleRole.PANEL);
548                 XAccessibleComponent xPanelCont = UnoRuntime.queryInterface(XAccessibleComponent.class, xPanel);
549 
550                 // the position of the panel
551                 Point point = xPanelCont.getLocationOnScreen();
552 
553                 // the range of the panel
554                 Rectangle rect = xPanelCont.getBounds();
555 
556                 try {
557                     Robot rob = new Robot();
558                     int x = point.X + (rect.Width / 2);
559                     int y = point.Y + (rect.Height / 2);
560                     System.out.println("try to klick into the middle of the document");
561                     rob.mouseMove(x, y);
562                     rob.mousePress(InputEvent.BUTTON1_MASK);
563                     rob.mouseRelease(InputEvent.BUTTON1_MASK);
564                 } catch (java.awt.AWTException e) {
565                     System.out.println("couldn't press mouse button");
566                 }
567             } catch (java.lang.Exception e){
568                 System.out.println("could not click into the scroll bar: " + e.toString());
569             }
570         }
571 
572         /**
573          * This method press the "A" key. Therefore it uses the <CODE>Robot</CODE>
574          * class.
575          * @see java.awt.Robot
576         */
577         private void keyIntoDoc(){
578             try {
579                 Robot rob = new Robot();
580                 System.out.println("try to press 'A'");
581                 rob.keyPress(java.awt.event.KeyEvent.VK_A);
582                 rob.keyRelease(java.awt.event.KeyEvent.VK_A);
583             } catch (java.awt.AWTException e) {
584                 System.out.println("couldn't press key");
585             }
586 
587         }
588     }
589 
590     /** This interface represents all possible actions which could be used
591      * in the <CODE>EventTrigger</CODE> class.
592      * @see EventTest.EventTrigger
593     */
594     private interface EventTriggerType{
595 
596         /** klick the mouse into the scroll bar*/
597         final public static int MOUSE_KLICK_INTO_DOC = 1;
598 
599         /** write some text into a spread sheet*/
600         final public static int KEY_TEXT_INTO_DOC = 2;
601     }
602 
603 
604 
605 
606     private XMultiServiceFactory getMSF()
607     {
608         final XMultiServiceFactory xMSF1 = UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
609         return xMSF1;
610     }
611 
612     // setup and close connections
613     @BeforeClass public static void setUpConnection() throws Exception {
614         System.out.println("setUpConnection()");
615         connection.setUp();
616     }
617 
618     @AfterClass public static void tearDownConnection()
619         throws InterruptedException, com.sun.star.uno.Exception
620     {
621         System.out.println("tearDownConnection()");
622         connection.tearDown();
623     }
624 
625     private static final OfficeConnection connection = new OfficeConnection();
626 
627 }