1 /*************************************************************************
2  *
3  *  The Contents of this file are made available subject to the terms of
4  *  the BSD license.
5  *
6  *  Copyright 2000, 2010 Oracle and/or its affiliates.
7  *  All rights reserved.
8  *
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
18  *     contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  *************************************************************************/
34 
35 import com.sun.star.accessibility.XAccessible;
36 import com.sun.star.accessibility.XAccessibleEventListener;
37 import com.sun.star.accessibility.AccessibleEventObject;
38 import com.sun.star.lang.EventObject;
39 import com.sun.star.awt.XTopWindowListener;
40 import com.sun.star.uno.UnoRuntime;
41 
42 import java.util.LinkedList;
43 
44 /** This class acts as a proxy for the simple screen reader.  It waits for
45     two types of events:
46     1. Accessibility events signal modifications concerning accessibility
47        objects.
48     2. Top window events inform the listener about new or removed windows.
49 
50     This class exists because events had to be handled in a seperate thread
51     to avoid dead locks: The thread that receives an event must no call back
52     to the Office directly.
53 
54     Soon this should not be necessary anymore.  There is now a flag which
55     switches between synchronous and asynchronous callbacks.
56 
57     All reveived events are eventually forwarded to the actual listener.  In
58     this way it decouples the Office from the listener.
59 */
60 class EventListenerProxy
61     implements Runnable, XAccessibleEventListener, XTopWindowListener
62 {
63     public EventListenerProxy (EventHandler aListener)
64     {
65         maListener = aListener;
66         mbAsynchron = true;
67         if (mbAsynchron)
68         {
69             maEventQueue = new LinkedList();
70             new Thread (this, "EventListenerProxy").start();
71         }
72     }
73 
74     private void addEvent (Runnable aEventObject)
75     {
76         if (mbAsynchron)
77             synchronized (maEventQueue)
78             {
79                 maEventQueue.addLast (aEventObject);
80                 // Tell the queue that there is a new event in the queue.
81                 maEventQueue.notify();
82             }
83         else
84         {
85             System.out.println ("running " + aEventObject);
86             aEventObject.run();
87             System.out.println ("  done");
88         }
89     }
90 
91 
92 
93 
94     /** In an infinite loop, check for events to deliver, then wait on lock
95         (which will be notified when new events arrive)
96     */
97     public void run ()
98     {
99         while (true)
100         {
101             // Process all events that are currently in the queue.
102             Runnable aEvent;
103             do
104             {
105                 synchronized (maEventQueue)
106                 {
107                     if (maEventQueue.size() > 0)
108                         aEvent = (Runnable)maEventQueue.removeFirst();
109                     else
110                         aEvent = null;
111                 }
112 
113                 if (aEvent != null)
114                 {
115                     try
116                     {
117                         aEvent.run();
118                     }
119                     catch (Throwable aException)
120                     {
121                         MessageArea.println(
122                             "Exception during event delivery: " + aException);
123                         aException.printStackTrace();
124                     }
125                 }
126             }
127             while (aEvent != null);
128 
129             // Now that the queue is empty go to sleep again.
130             try
131             {
132                 synchronized (maEventQueue)
133                 {
134                     maEventQueue.wait();
135                 }
136             }
137             catch (Exception aException)
138             {
139                 // Ignore this exception since there is not much
140                 // that we can do about it.
141             }
142         }
143     }
144 
145 
146     public void disposing( final EventObject aEvent)
147     {
148         addEvent (new Runnable()
149             {
150                 public void run()
151                 {
152                     maListener.disposing (aEvent);
153                 }
154             } );
155     }
156 
157     public void notifyEvent (final AccessibleEventObject aEvent)
158     {
159         addEvent (
160             new Runnable()
161             {
162                 public void run()
163                 {
164                     maListener.notifyEvent (aEvent);
165                 }
166             } );
167     }
168 
169     public void windowOpened (final com.sun.star.lang.EventObject aEvent)
170     {
171         addEvent (
172             new Runnable()
173             {
174                 public void run()
175                 {
176                     maListener.windowOpened (
177                         (XAccessible) UnoRuntime.queryInterface(
178                             XAccessible.class,
179                             aEvent.Source));
180                 }
181             } );
182     }
183     public void windowClosing (final com.sun.star.lang.EventObject aEvent)
184     {
185         // Ignored.
186     }
187     public void windowClosed (final com.sun.star.lang.EventObject aEvent)
188     {
189         addEvent (
190             new Runnable()
191             {
192                 public void run()
193                 {
194                     maListener.windowClosed (
195                         (XAccessible) UnoRuntime.queryInterface(
196                             XAccessible.class,
197                             aEvent.Source));
198                 }
199                 } );
200     }
201     public void windowMinimized (com.sun.star.lang.EventObject aEvent)
202     {
203         // Ignored.
204     }
205     public void windowNormalized (com.sun.star.lang.EventObject aEvent)
206     {
207         // Ignored.
208     }
209     public void windowActivated (com.sun.star.lang.EventObject aEvent)
210     {
211         // Ignored.
212     }
213     public void windowDeactivated (com.sun.star.lang.EventObject aEvent)
214     {
215         // Ignored.
216     }
217 
218     /** The queue of event objects, LinkedList<Runnable>.
219         The queue object will also serve as lock for the consumer/producer type
220         syncronization.
221     */
222     private LinkedList maEventQueue;
223 
224     /** This is the actual listener that the events will eventually forwarded to.
225     */
226     private EventHandler maListener;
227 
228     /** This flag determines whether event forwarding is done asynchroniously
229         or synchroniously.
230     */
231     private boolean mbAsynchron;
232 }
233