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