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 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 52 ContextChangeEventMultiplexer::~ContextChangeEventMultiplexer (void) 53 { 54 } 55 56 57 58 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 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 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 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 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 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 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 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 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 290 ::rtl::OUString SAL_CALL ContextChangeEventMultiplexer::getImplementationName (void) 291 { 292 return impl_getStaticImplementationName(); 293 } 294 295 296 297 298 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 308 cssu::Sequence<OUString> SAL_CALL ContextChangeEventMultiplexer::getSupportedServiceNames (void) 309 { 310 return static_GetSupportedServiceNames(); 311 } 312 313 314 315 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 337 OUString SAL_CALL ContextChangeEventMultiplexer::impl_getStaticImplementationName (void) 338 { 339 return A2S(IMPLEMENTATION_NAME); 340 } 341 342 343 344 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 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 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