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