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