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 #include "precompiled_framework.hxx"
23 
24 #include "services/ContextChangeEventMultiplexer.hxx"
25 #include "services.h"
26 
27 using ::rtl::OUString;
28 
29 #define A2S(s) ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
30 
31 namespace framework {
32 
33 #define IMPLEMENTATION_NAME "org.apache.openoffice.comp.framework.ContextChangeEventMultiplexer"
34 #define SERVICE_NAME "com.sun.star.ui.ContextChangeEventMultiplexer"
35 #define SINGLETON_NAME "org.apache.openoffice.comp.framework.ContextChangeEventMultiplexerSigleton"
36 
37 
38 ContextChangeEventMultiplexer::ContextChangeEventMultiplexer (
39     const cssu::Reference<cssu::XComponentContext>& rxContext)
40     : ContextChangeEventMultiplexerInterfaceBase(m_aMutex),
41       maListeners()
42 {
43     (void)rxContext;
44 }
45 
46 
47 
48 
49 ContextChangeEventMultiplexer::~ContextChangeEventMultiplexer (void)
50 {
51 }
52 
53 
54 
55 
56 void SAL_CALL ContextChangeEventMultiplexer::disposing (void)
57 {
58     ListenerMap aListeners;
59     aListeners.swap(maListeners);
60 
61     cssu::Reference<cssu::XInterface> xThis (static_cast<XWeak*>(this));
62     css::lang::EventObject aEvent (xThis);
63     for (ListenerMap::const_iterator iContainer(aListeners.begin()), iEnd(aListeners.end());
64          iContainer!=iEnd;
65          ++iContainer)
66     {
67         for (ListenerContainer::const_iterator
68                  iListener(iContainer->second.maListeners.begin()),
69                  iContainerEnd(iContainer->second.maListeners.end());
70              iListener!=iContainerEnd;
71              ++iListener)
72         {
73             (*iListener)->disposing(aEvent);
74         }
75     }
76 }
77 
78 
79 
80 
81 // XContextChangeEventMultiplexer
82 
83 void SAL_CALL ContextChangeEventMultiplexer::addContextChangeEventListener (
84     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener,
85     const cssu::Reference<cssu::XInterface>& rxEventFocus)
86     throw(cssu::RuntimeException,cssl::IllegalArgumentException)
87 {
88     if ( ! rxListener.is())
89         throw css::lang::IllegalArgumentException(
90             A2S("can not add an empty reference"),
91             static_cast<XWeak*>(this),
92             0);
93 
94     ListenerMap::iterator iDescriptor (maListeners.find(rxEventFocus));
95     if (iDescriptor == maListeners.end())
96     {
97         // Create a new listener container for the event focus.
98         iDescriptor = maListeners.insert(
99             ListenerMap::value_type(
100                 rxEventFocus,
101                 FocusDescriptor())).first;
102     }
103     if (iDescriptor != maListeners.end())
104     {
105         ListenerContainer& rContainer (iDescriptor->second.maListeners);
106         if (::std::find(rContainer.begin(), rContainer.end(), rxListener) == rContainer.end())
107             rContainer.push_back(rxListener);
108         else
109         {
110             // The listener was added for the same event focus
111             // previously.  That is an error.
112             throw cssl::IllegalArgumentException(A2S("listener added twice"), static_cast<XWeak*>(this), 0);
113         }
114     }
115 
116     // Send out an initial event that informs the new listener about
117     // the current context.
118     if (rxEventFocus.is() && iDescriptor != maListeners.end())
119     {
120         css::ui::ContextChangeEventObject aEvent (
121             NULL,
122             iDescriptor->second.msCurrentApplicationName,
123             iDescriptor->second.msCurrentContextName);
124         rxListener->notifyContextChangeEvent(aEvent);
125     }
126 }
127 
128 
129 
130 
131 void SAL_CALL ContextChangeEventMultiplexer::removeContextChangeEventListener (
132     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener,
133     const cssu::Reference<cssu::XInterface>& rxEventFocus)
134     throw(cssu::RuntimeException,cssl::IllegalArgumentException)
135 {
136     if ( ! rxListener.is())
137         throw cssl::IllegalArgumentException(
138             A2S("can not remove an empty reference"),
139             static_cast<XWeak*>(this), 0);
140 
141     ListenerMap::iterator iDescriptor (maListeners.find(rxEventFocus));
142     if (iDescriptor != maListeners.end())
143     {
144         ListenerContainer& rContainer (iDescriptor->second.maListeners);
145         const ListenerContainer::iterator iListener (
146             ::std::find(rContainer.begin(), rContainer.end(), rxListener));
147         if (iListener != rContainer.end())
148         {
149             rContainer.erase(iListener);
150 
151             // Remove the listener container as well when its last
152             // listener was just removed.  This prevents us from
153             // holding the focus alive.
154             if (rContainer.empty())
155                 maListeners.erase(iDescriptor);
156         }
157     }
158 
159 }
160 
161 
162 
163 
164 void SAL_CALL ContextChangeEventMultiplexer::removeAllContextChangeEventListeners (
165     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener)
166     throw(cssu::RuntimeException,cssl::IllegalArgumentException)
167 {
168     if ( ! rxListener.is())
169         throw cssl::IllegalArgumentException(
170             A2S("can not remove an empty reference"),
171             static_cast<XWeak*>(this), 0);
172 
173     ::std::vector<cssu::Reference<cssu::XInterface> > aContainersToRemove;
174     for (ListenerMap::iterator
175              iContainer(maListeners.begin()),
176              iEnd(maListeners.end());
177          iContainer!=iEnd;
178          ++iContainer)
179     {
180         const ListenerContainer::iterator iListener (
181             ::std::find(iContainer->second.maListeners.begin(), iContainer->second.maListeners.end(), rxListener));
182         if (iListener != iContainer->second.maListeners.end())
183         {
184             iContainer->second.maListeners.erase(iListener);
185 
186             // When we just removed the last listener then mark the
187             // container as to be removed.
188             if (iContainer->second.maListeners.empty())
189                 aContainersToRemove.push_back(iContainer->first);
190         }
191     }
192 
193     for (::std::vector<cssu::Reference<cssu::XInterface> >::iterator
194              iFocus(aContainersToRemove.begin()),
195              iEnd(aContainersToRemove.end());
196          iFocus!=iEnd;
197          ++iFocus)
198     {
199         maListeners.erase(*iFocus);
200     }
201 }
202 
203 
204 
205 
206 void SAL_CALL ContextChangeEventMultiplexer::broadcastContextChangeEvent (
207     const css::ui::ContextChangeEventObject& rEventObject,
208     const cssu::Reference<cssu::XInterface>& rxEventFocus)
209     throw(cssu::RuntimeException)
210 {
211     // Remember the current context.
212     if (rxEventFocus.is())
213     {
214         ListenerMap::iterator iDescriptor (maListeners.find(rxEventFocus));
215         if (iDescriptor != maListeners.end())
216         {
217             iDescriptor->second.msCurrentApplicationName = rEventObject.ApplicationName;
218             iDescriptor->second.msCurrentContextName = rEventObject.ContextName;
219         }
220     }
221 
222     BroadcastEventToSingleContainer(rEventObject, rxEventFocus);
223     if (rxEventFocus.is())
224         BroadcastEventToSingleContainer(rEventObject, NULL);
225 }
226 
227 
228 
229 
230 void ContextChangeEventMultiplexer::BroadcastEventToSingleContainer (
231     const css::ui::ContextChangeEventObject& rEventObject,
232     const cssu::Reference<cssu::XInterface>& rxEventFocus)
233 {
234     ListenerMap::iterator iDescriptor (maListeners.find(rxEventFocus));
235     if (iDescriptor != maListeners.end())
236     {
237         // Create a copy of the listener container to avoid problems
238         // when one of the called listeners calls add... or remove...
239         ListenerContainer aContainer (iDescriptor->second.maListeners);
240         for (ListenerContainer::const_iterator
241                  iListener(aContainer.begin()),
242                  iEnd(aContainer.end());
243              iListener!=iEnd;
244              ++iListener)
245         {
246             (*iListener)->notifyContextChangeEvent(rEventObject);
247         }
248     }
249 }
250 
251 
252 
253 
254 // XSingleComponentFactory
255 
256 cssu::Reference<cssu::XInterface> SAL_CALL ContextChangeEventMultiplexer::createInstanceWithContext (
257     const cssu::Reference<cssu::XComponentContext>& rxContext)
258     throw (cssu::Exception, cssu::RuntimeException)
259 {
260     (void)rxContext;
261     return cssu::Reference<cssu::XInterface>();
262 }
263 
264 
265 
266 
267 cssu::Reference<cssu::XInterface > SAL_CALL ContextChangeEventMultiplexer::createInstanceWithArgumentsAndContext (
268     const cssu::Sequence<cssu::Any>& rArguments,
269     const cssu::Reference<cssu::XComponentContext>& rxContext)
270     throw (cssu::Exception, cssu::RuntimeException)
271 {
272     (void)rArguments;
273     (void)rxContext;
274     return cssu::Reference<cssu::XInterface>();
275 }
276 
277 
278 
279 
280 // XServiceInfo
281 
282 ::rtl::OUString SAL_CALL ContextChangeEventMultiplexer::getImplementationName (void)
283     throw(cssu::RuntimeException)
284 {
285     return impl_getStaticImplementationName();
286 }
287 
288 
289 
290 
291 
292 sal_Bool SAL_CALL ContextChangeEventMultiplexer::supportsService (
293     const ::rtl::OUString& rsServiceName)
294     throw (cssu::RuntimeException)
295 {
296     return ::comphelper::findValue(static_GetSupportedServiceNames(), rsServiceName, sal_True).getLength() != 0;
297 }
298 
299 
300 
301 
302 cssu::Sequence<OUString> SAL_CALL ContextChangeEventMultiplexer::getSupportedServiceNames (void)
303     throw (cssu::RuntimeException)
304 {
305     return static_GetSupportedServiceNames();
306 }
307 
308 
309 
310 
311 // Local and static methods.
312 
313 OUString SAL_CALL ContextChangeEventMultiplexer::impl_getStaticImplementationName (void)
314 {
315     return A2S(IMPLEMENTATION_NAME);
316 }
317 
318 
319 
320 
321 cssu::Sequence<OUString> SAL_CALL ContextChangeEventMultiplexer::static_GetSupportedServiceNames (void)
322 {
323     cssu::Sequence<OUString> aServiceNames (2);
324     aServiceNames[0] = A2S(SERVICE_NAME);
325     aServiceNames[1] = A2S(SINGLETON_NAME);
326     return aServiceNames;
327 }
328 
329 
330 
331 
332 cssu::Reference<cssu::XInterface> ContextChangeEventMultiplexer::impl_createFactory (
333     const cssu::Reference<cssl::XMultiServiceFactory>& rxServiceManager)
334 {
335     (void)rxServiceManager;
336     return cppu::createSingleComponentFactory(
337         ContextChangeEventMultiplexer::static_CreateInstance,
338         ContextChangeEventMultiplexer::impl_getStaticImplementationName(),
339         ContextChangeEventMultiplexer::static_GetSupportedServiceNames()
340         );
341 }
342 
343 
344 
345 
346 cssu::Reference<cssu::XInterface> SAL_CALL ContextChangeEventMultiplexer::static_CreateInstance (
347     const cssu::Reference<cssu::XComponentContext>& rxComponentContext)
348     throw (cssu::Exception)
349 {
350     ContextChangeEventMultiplexer* pObject = new ContextChangeEventMultiplexer(rxComponentContext);
351     cssu::Reference<cssu::XInterface> xService (static_cast<XWeak*>(pObject), cssu::UNO_QUERY);
352     return xService;
353 }
354 
355 }  // end of namespace framework
356