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