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 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 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 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 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 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 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 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 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 296 ::rtl::OUString SAL_CALL ContextChangeEventMultiplexer::getImplementationName (void) 297 throw(cssu::RuntimeException) 298 { 299 return impl_getStaticImplementationName(); 300 } 301 302 303 304 305 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 316 cssu::Sequence<OUString> SAL_CALL ContextChangeEventMultiplexer::getSupportedServiceNames (void) 317 throw (cssu::RuntimeException) 318 { 319 return static_GetSupportedServiceNames(); 320 } 321 322 323 324 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 347 OUString SAL_CALL ContextChangeEventMultiplexer::impl_getStaticImplementationName (void) 348 { 349 return A2S(IMPLEMENTATION_NAME); 350 } 351 352 353 354 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 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 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