xref: /trunk/main/framework/source/services/ContextChangeEventMultiplexer.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
97     if ( ! rxListener.is())
98         throw css::lang::IllegalArgumentException(
99             A2S("can not add an empty reference"),
100             static_cast<XWeak*>(this),
101             0);
102 
103     FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, true);
104     if (pFocusDescriptor != NULL)
105     {
106         ListenerContainer& rContainer (pFocusDescriptor->maListeners);
107         if (::std::find(rContainer.begin(), rContainer.end(), rxListener) == rContainer.end())
108             rContainer.push_back(rxListener);
109         else
110         {
111             // The listener was added for the same event focus
112             // previously.  That is an error.
113             throw cssl::IllegalArgumentException(A2S("listener added twice"), static_cast<XWeak*>(this), 0);
114         }
115     }
116 
117     // Send out an initial event that informs the new listener about
118     // the current context.
119     if (rxEventFocus.is() && pFocusDescriptor!=NULL)
120     {
121         css::ui::ContextChangeEventObject aEvent (
122             NULL,
123             pFocusDescriptor->msCurrentApplicationName,
124             pFocusDescriptor->msCurrentContextName);
125         rxListener->notifyContextChangeEvent(aEvent);
126     }
127 }
128 
129 
130 
131 
removeContextChangeEventListener(const cssu::Reference<css::ui::XContextChangeEventListener> & rxListener,const cssu::Reference<cssu::XInterface> & rxEventFocus)132 void SAL_CALL ContextChangeEventMultiplexer::removeContextChangeEventListener (
133     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener,
134     const cssu::Reference<cssu::XInterface>& rxEventFocus)
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     FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, false);
142     if (pFocusDescriptor != NULL)
143     {
144         ListenerContainer& rContainer (pFocusDescriptor->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             // We hold on to the focus descriptor even when the last listener has been removed.
152             // This allows us to keep track of the current context and send it to new listeners.
153         }
154     }
155 
156 }
157 
158 
159 
160 
removeAllContextChangeEventListeners(const cssu::Reference<css::ui::XContextChangeEventListener> & rxListener)161 void SAL_CALL ContextChangeEventMultiplexer::removeAllContextChangeEventListeners (
162     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener)
163 {
164     if ( ! rxListener.is())
165         throw cssl::IllegalArgumentException(
166             A2S("can not remove an empty reference"),
167             static_cast<XWeak*>(this), 0);
168 
169     for (ListenerMap::iterator
170              iContainer(maListeners.begin()),
171              iEnd(maListeners.end());
172          iContainer!=iEnd;
173          ++iContainer)
174     {
175         const ListenerContainer::iterator iListener (
176             ::std::find(iContainer->second.maListeners.begin(), iContainer->second.maListeners.end(), rxListener));
177         if (iListener != iContainer->second.maListeners.end())
178         {
179             iContainer->second.maListeners.erase(iListener);
180 
181             // We hold on to the focus descriptor even when the last listener has been removed.
182             // This allows us to keep track of the current context and send it to new listeners.
183         }
184     }
185 }
186 
187 
188 
189 
broadcastContextChangeEvent(const css::ui::ContextChangeEventObject & rEventObject,const cssu::Reference<cssu::XInterface> & rxEventFocus)190 void SAL_CALL ContextChangeEventMultiplexer::broadcastContextChangeEvent (
191     const css::ui::ContextChangeEventObject& rEventObject,
192     const cssu::Reference<cssu::XInterface>& rxEventFocus)
193 {
194     // Remember the current context.
195     if (rxEventFocus.is())
196     {
197         FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, true);
198         if (pFocusDescriptor != NULL)
199         {
200             pFocusDescriptor->msCurrentApplicationName = rEventObject.ApplicationName;
201             pFocusDescriptor->msCurrentContextName = rEventObject.ContextName;
202         }
203     }
204 
205     BroadcastEventToSingleContainer(rEventObject, rxEventFocus);
206     if (rxEventFocus.is())
207         BroadcastEventToSingleContainer(rEventObject, NULL);
208 }
209 
210 
211 
212 
BroadcastEventToSingleContainer(const css::ui::ContextChangeEventObject & rEventObject,const cssu::Reference<cssu::XInterface> & rxEventFocus)213 void ContextChangeEventMultiplexer::BroadcastEventToSingleContainer (
214     const css::ui::ContextChangeEventObject& rEventObject,
215     const cssu::Reference<cssu::XInterface>& rxEventFocus)
216 {
217     FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, false);
218     if (pFocusDescriptor != NULL)
219     {
220         // Create a copy of the listener container to avoid problems
221         // when one of the called listeners calls add... or remove...
222         ListenerContainer aContainer (pFocusDescriptor->maListeners);
223         for (ListenerContainer::const_iterator
224                  iListener(aContainer.begin()),
225                  iEnd(aContainer.end());
226              iListener!=iEnd;
227              ++iListener)
228         {
229             (*iListener)->notifyContextChangeEvent(rEventObject);
230         }
231     }
232 }
233 
234 
235 
236 
GetFocusDescriptor(const cssu::Reference<cssu::XInterface> & rxEventFocus,const bool bCreateWhenMissing)237 ContextChangeEventMultiplexer::FocusDescriptor* ContextChangeEventMultiplexer::GetFocusDescriptor (
238     const cssu::Reference<cssu::XInterface>& rxEventFocus,
239     const bool bCreateWhenMissing)
240 {
241     ListenerMap::iterator iDescriptor (maListeners.find(rxEventFocus));
242     if (iDescriptor == maListeners.end() && bCreateWhenMissing)
243     {
244         // Listen for the focus being disposed.
245         Reference<lang::XComponent> xComponent (rxEventFocus, UNO_QUERY);
246         if (xComponent.is())
247             xComponent->addEventListener(this);
248 
249         // Create a new listener container for the event focus.
250         iDescriptor = maListeners.insert(
251             ListenerMap::value_type(
252                 rxEventFocus,
253                 FocusDescriptor())).first;
254     }
255     if (iDescriptor != maListeners.end())
256         return &iDescriptor->second;
257     else
258         return NULL;
259 }
260 
261 
262 
263 
264 // XSingleComponentFactory
265 
createInstanceWithContext(const cssu::Reference<cssu::XComponentContext> & rxContext)266 cssu::Reference<cssu::XInterface> SAL_CALL ContextChangeEventMultiplexer::createInstanceWithContext (
267     const cssu::Reference<cssu::XComponentContext>& rxContext)
268 {
269     (void)rxContext;
270     return cssu::Reference<cssu::XInterface>();
271 }
272 
273 
274 
275 
createInstanceWithArgumentsAndContext(const cssu::Sequence<cssu::Any> & rArguments,const cssu::Reference<cssu::XComponentContext> & rxContext)276 cssu::Reference<cssu::XInterface > SAL_CALL ContextChangeEventMultiplexer::createInstanceWithArgumentsAndContext (
277     const cssu::Sequence<cssu::Any>& rArguments,
278     const cssu::Reference<cssu::XComponentContext>& rxContext)
279 {
280     (void)rArguments;
281     (void)rxContext;
282     return cssu::Reference<cssu::XInterface>();
283 }
284 
285 
286 
287 
288 // XServiceInfo
289 
getImplementationName(void)290 ::rtl::OUString SAL_CALL ContextChangeEventMultiplexer::getImplementationName (void)
291 {
292     return impl_getStaticImplementationName();
293 }
294 
295 
296 
297 
298 
supportsService(const::rtl::OUString & rsServiceName)299 sal_Bool SAL_CALL ContextChangeEventMultiplexer::supportsService (
300     const ::rtl::OUString& rsServiceName)
301 {
302     return ::comphelper::findValue(static_GetSupportedServiceNames(), rsServiceName, sal_True).getLength() != 0;
303 }
304 
305 
306 
307 
getSupportedServiceNames(void)308 cssu::Sequence<OUString> SAL_CALL ContextChangeEventMultiplexer::getSupportedServiceNames (void)
309 {
310     return static_GetSupportedServiceNames();
311 }
312 
313 
314 
315 
disposing(const css::lang::EventObject & rEvent)316 void SAL_CALL ContextChangeEventMultiplexer::disposing (
317     const css::lang::EventObject& rEvent)
318 {
319     ListenerMap::iterator iDescriptor (maListeners.find(rEvent.Source));
320 
321     if (iDescriptor == maListeners.end())
322     {
323         OSL_ASSERT(iDescriptor != maListeners.end());
324         return;
325     }
326 
327     // Should we notify the remaining listeners?
328 
329     maListeners.erase(iDescriptor);
330 }
331 
332 
333 
334 
335 // Local and static methods.
336 
impl_getStaticImplementationName(void)337 OUString SAL_CALL ContextChangeEventMultiplexer::impl_getStaticImplementationName (void)
338 {
339     return A2S(IMPLEMENTATION_NAME);
340 }
341 
342 
343 
344 
static_GetSupportedServiceNames(void)345 cssu::Sequence<OUString> SAL_CALL ContextChangeEventMultiplexer::static_GetSupportedServiceNames (void)
346 {
347     cssu::Sequence<OUString> aServiceNames (2);
348     aServiceNames[0] = A2S(SERVICE_NAME);
349     aServiceNames[1] = A2S(SINGLETON_NAME);
350     return aServiceNames;
351 }
352 
353 
354 
355 
impl_createFactory(const cssu::Reference<cssl::XMultiServiceFactory> & rxServiceManager)356 cssu::Reference<cssu::XInterface> ContextChangeEventMultiplexer::impl_createFactory (
357     const cssu::Reference<cssl::XMultiServiceFactory>& rxServiceManager)
358 {
359     (void)rxServiceManager;
360     return cppu::createSingleComponentFactory(
361         ContextChangeEventMultiplexer::static_CreateInstance,
362         ContextChangeEventMultiplexer::impl_getStaticImplementationName(),
363         ContextChangeEventMultiplexer::static_GetSupportedServiceNames()
364         );
365 }
366 
367 
368 
369 
static_CreateInstance(const cssu::Reference<cssu::XComponentContext> & rxComponentContext)370 cssu::Reference<cssu::XInterface> SAL_CALL ContextChangeEventMultiplexer::static_CreateInstance (
371     const cssu::Reference<cssu::XComponentContext>& rxComponentContext)
372 {
373     ContextChangeEventMultiplexer* pObject = new ContextChangeEventMultiplexer(rxComponentContext);
374     cssu::Reference<cssu::XInterface> xService (static_cast<XWeak*>(pObject), cssu::UNO_QUERY);
375     return xService;
376 }
377 
378 }  // end of namespace framework
379