1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_framework.hxx" 30 31 //_______________________________________________ 32 // my own includes 33 34 #ifndef __FRAMEWORK_DISPATCH_INTERCEPTIONHELPER_HXX_ 35 #include <dispatch/interceptionhelper.hxx> 36 #endif 37 38 //_______________________________________________ 39 // interface includes 40 #include <com/sun/star/frame/XInterceptorInfo.hpp> 41 42 //_______________________________________________ 43 // includes of other projects 44 #include <vcl/svapp.hxx> 45 46 //_______________________________________________ 47 // namespace 48 49 namespace framework{ 50 51 //_______________________________________________ 52 // non exported const 53 54 sal_Bool InterceptionHelper::m_bPreferrFirstInterceptor = sal_True; 55 56 //_______________________________________________ 57 // non exported definitions 58 59 //_______________________________________________ 60 // declarations 61 62 /*----------------------------------------------------------------------------- 63 31.03.2003 09:02 64 -----------------------------------------------------------------------------*/ 65 DEFINE_XINTERFACE_3(InterceptionHelper , 66 OWeakObject , 67 DIRECT_INTERFACE(css::frame::XDispatchProvider ), 68 DIRECT_INTERFACE(css::frame::XDispatchProviderInterception), 69 DIRECT_INTERFACE(css::lang::XEventListener )) 70 71 /*----------------------------------------------------------------------------- 72 31.03.2003 09:02 73 -----------------------------------------------------------------------------*/ 74 InterceptionHelper::InterceptionHelper(const css::uno::Reference< css::frame::XFrame >& xOwner, 75 const css::uno::Reference< css::frame::XDispatchProvider >& xSlave) 76 // Init baseclasses first 77 : ThreadHelpBase(&Application::GetSolarMutex()) 78 , OWeakObject ( ) 79 // Init member 80 , m_xOwnerWeak (xOwner ) 81 , m_xSlave (xSlave ) 82 { 83 } 84 85 /*----------------------------------------------------------------------------- 86 31.03.2003 09:02 87 -----------------------------------------------------------------------------*/ 88 InterceptionHelper::~InterceptionHelper() 89 { 90 } 91 92 /*----------------------------------------------------------------------------- 93 31.03.2003 09:09 94 -----------------------------------------------------------------------------*/ 95 css::uno::Reference< css::frame::XDispatch > SAL_CALL InterceptionHelper::queryDispatch(const css::util::URL& aURL , 96 const ::rtl::OUString& sTargetFrameName, 97 sal_Int32 nSearchFlags ) 98 throw(css::uno::RuntimeException) 99 { 100 // SAFE { 101 ReadGuard aReadLock(m_aLock); 102 103 // a) first search an interceptor, which match to this URL by it's URL pattern registration 104 // Note: if it return NULL - it does not mean an empty interceptor list automaticly! 105 css::uno::Reference< css::frame::XDispatchProvider > xInterceptor; 106 InterceptorList::const_iterator pIt = m_lInterceptionRegs.findByPattern(aURL.Complete); 107 if (pIt != m_lInterceptionRegs.end()) 108 xInterceptor = pIt->xInterceptor; 109 110 // b) No match by registration - but a valid interceptor list. 111 // Use first interceptor everytimes. 112 // Note: it doesn't matter, which direction this helper implementation use to ask interceptor objects. 113 // Using of member m_aInterceptorList will starts at the beginning everytimes. 114 // It depends from the filling operation, in which direction it works realy! 115 if (!xInterceptor.is() && m_lInterceptionRegs.size()>0) 116 { 117 pIt = m_lInterceptionRegs.begin(); 118 xInterceptor = pIt->xInterceptor; 119 } 120 121 // c) No registered interceptor => use our direct slave. 122 // This helper exist by design and must be valid everytimes ... 123 // But to be more feature proof - we should check that .-) 124 if (!xInterceptor.is() && m_xSlave.is()) 125 xInterceptor = m_xSlave; 126 127 aReadLock.unlock(); 128 // } SAFE 129 130 css::uno::Reference< css::frame::XDispatch > xReturn; 131 if (xInterceptor.is()) 132 xReturn = xInterceptor->queryDispatch(aURL, sTargetFrameName, nSearchFlags); 133 return xReturn; 134 } 135 136 /*----------------------------------------------------------------------------- 137 31.03.2003 07:58 138 -----------------------------------------------------------------------------*/ 139 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL InterceptionHelper::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) 140 throw(css::uno::RuntimeException) 141 { 142 sal_Int32 c = lDescriptor.getLength(); 143 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatches (c); 144 css::uno::Reference< css::frame::XDispatch >* pDispatches = lDispatches.getArray(); 145 const css::frame::DispatchDescriptor* pDescriptor = lDescriptor.getConstArray(); 146 147 for (sal_Int32 i=0; i<c; ++i) 148 pDispatches[i] = queryDispatch(pDescriptor[i].FeatureURL, pDescriptor[i].FrameName, pDescriptor[i].SearchFlags); 149 150 return lDispatches; 151 } 152 153 /*----------------------------------------------------------------------------- 154 31.03.2003 10:20 155 -----------------------------------------------------------------------------*/ 156 void SAL_CALL InterceptionHelper::registerDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor) 157 throw(css::uno::RuntimeException) 158 { 159 // reject wrong calling of this interface method 160 css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); 161 if (!xInterceptor.is()) 162 throw css::uno::RuntimeException(DECLARE_ASCII("NULL references not allowed as in parameter"), xThis); 163 164 // Fill a new info structure for new interceptor. 165 // Save his reference and try to get an additional URL/pattern list from him. 166 // If no list exist register these interceptor for all dispatch events with "*"! 167 InterceptorInfo aInfo; 168 169 aInfo.xInterceptor = css::uno::Reference< css::frame::XDispatchProvider >(xInterceptor, css::uno::UNO_QUERY); 170 css::uno::Reference< css::frame::XInterceptorInfo > xInfo(xInterceptor, css::uno::UNO_QUERY); 171 if (xInfo.is()) 172 aInfo.lURLPattern = xInfo->getInterceptedURLs(); 173 else 174 { 175 aInfo.lURLPattern.realloc(1); 176 aInfo.lURLPattern[0] = ::rtl::OUString::createFromAscii("*"); 177 } 178 179 // SAFE { 180 WriteGuard aWriteLock(m_aLock); 181 182 // a) no interceptor at all - set this instance as master for given interceptor 183 // and set our slave as it's slave - and put this interceptor to the list. 184 // It's place there doesn matter. Because this list is currently empty. 185 if (m_lInterceptionRegs.empty()) 186 { 187 xInterceptor->setMasterDispatchProvider(xThis ); 188 xInterceptor->setSlaveDispatchProvider (m_xSlave); 189 m_lInterceptionRegs.push_back(aInfo); 190 } 191 192 // b) OK - there is at least one interceptor already registered. 193 // It's slave and it's master must be valid references ... 194 // because we created it. But we have to look for the static bool which 195 // regulate direction of using of interceptor objects! 196 197 // b1) If "m_bPreferrFirstInterceptor" is set to true, we have to 198 // insert it behind any other existing interceptor - means at the end of our list. 199 else if (m_bPreferrFirstInterceptor) 200 { 201 css::uno::Reference< css::frame::XDispatchProvider > xMasterD = m_lInterceptionRegs.rbegin()->xInterceptor; 202 css::uno::Reference< css::frame::XDispatchProviderInterceptor > xMasterI (xMasterD, css::uno::UNO_QUERY); 203 204 xInterceptor->setMasterDispatchProvider(xMasterD ); 205 xInterceptor->setSlaveDispatchProvider (m_xSlave ); 206 xMasterI->setSlaveDispatchProvider (aInfo.xInterceptor); 207 208 m_lInterceptionRegs.push_back(aInfo); 209 } 210 211 // b2) If "m_bPreferrFirstInterceptor" is set to false, we have to 212 // insert it before any other existing interceptor - means at the beginning of our list. 213 else 214 { 215 css::uno::Reference< css::frame::XDispatchProvider > xSlaveD = m_lInterceptionRegs.begin()->xInterceptor; 216 css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY); 217 218 xInterceptor->setMasterDispatchProvider(xThis ); 219 xInterceptor->setSlaveDispatchProvider (xSlaveD ); 220 xSlaveI->setMasterDispatchProvider (aInfo.xInterceptor); 221 222 m_lInterceptionRegs.push_front(aInfo); 223 } 224 225 css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); 226 227 aWriteLock.unlock(); 228 // } SAFE 229 230 // Don't forget to send a frame action event "context changed". 231 // Any cached dispatch objects must be validated now! 232 if (xOwner.is()) 233 xOwner->contextChanged(); 234 } 235 236 /*----------------------------------------------------------------------------- 237 31.03.2003 10:27 238 -----------------------------------------------------------------------------*/ 239 void SAL_CALL InterceptionHelper::releaseDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor) 240 throw(css::uno::RuntimeException) 241 { 242 // reject wrong calling of this interface method 243 css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); 244 if (!xInterceptor.is()) 245 throw css::uno::RuntimeException(DECLARE_ASCII("NULL references not allowed as in parameter"), xThis); 246 247 // SAFE { 248 WriteGuard aWriteLock(m_aLock); 249 250 // search this interceptor ... 251 // If it could be located inside cache - 252 // use it's slave/master relations to update the interception list; 253 // set empty references for it as new master and slave; 254 // and relase it from out cache. 255 InterceptorList::iterator pIt = m_lInterceptionRegs.findByReference(xInterceptor); 256 if (pIt != m_lInterceptionRegs.end()) 257 { 258 css::uno::Reference< css::frame::XDispatchProvider > xSlaveD (xInterceptor->getSlaveDispatchProvider() , css::uno::UNO_QUERY); 259 css::uno::Reference< css::frame::XDispatchProvider > xMasterD (xInterceptor->getMasterDispatchProvider(), css::uno::UNO_QUERY); 260 css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY); 261 css::uno::Reference< css::frame::XDispatchProviderInterceptor > xMasterI (xMasterD , css::uno::UNO_QUERY); 262 263 if (xMasterI.is()) 264 xMasterI->setSlaveDispatchProvider(xSlaveD); 265 266 if (xSlaveI.is()) 267 xSlaveI->setMasterDispatchProvider(xMasterD); 268 269 xInterceptor->setSlaveDispatchProvider (css::uno::Reference< css::frame::XDispatchProvider >()); 270 xInterceptor->setMasterDispatchProvider(css::uno::Reference< css::frame::XDispatchProvider >()); 271 272 m_lInterceptionRegs.erase(pIt); 273 } 274 275 css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); 276 277 aWriteLock.unlock(); 278 // } SAFE 279 280 // Don't forget to send a frame action event "context changed". 281 // Any cached dispatch objects must be validated now! 282 if (xOwner.is()) 283 xOwner->contextChanged(); 284 } 285 286 /*----------------------------------------------------------------------------- 287 31.03.2003 10:31 288 -----------------------------------------------------------------------------*/ 289 #define FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN 290 void SAL_CALL InterceptionHelper::disposing(const css::lang::EventObject& aEvent) 291 throw(css::uno::RuntimeException) 292 { 293 #ifdef FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN 294 // SAFE -> 295 ReadGuard aReadLock(m_aLock); 296 297 // check calli ... we accept such disposing call's only from our onwer frame. 298 css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); 299 if (aEvent.Source != xOwner) 300 return; 301 302 // Because every interceptor hold at least one reference to us ... and we destruct this list 303 // of interception objects ... we should hold ourself alive .-) 304 css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY_THROW); 305 306 // We need a full copy of all currently registered interceptor objects. 307 // Otherwhise we cant iterate over this vector without the risk, that our iterator will be invalid. 308 // Because this vetor will be influenced by every deregistered interceptor. 309 InterceptionHelper::InterceptorList aCopy = m_lInterceptionRegs; 310 311 aReadLock.unlock(); 312 // <- SAFE 313 314 InterceptionHelper::InterceptorList::iterator pIt; 315 for ( pIt = aCopy.begin(); 316 pIt != aCopy.end() ; 317 ++pIt ) 318 { 319 InterceptionHelper::InterceptorInfo& rInfo = *pIt; 320 if (rInfo.xInterceptor.is()) 321 { 322 css::uno::Reference< css::frame::XDispatchProviderInterceptor > xInterceptor(rInfo.xInterceptor, css::uno::UNO_QUERY_THROW); 323 releaseDispatchProviderInterceptor(xInterceptor); 324 rInfo.xInterceptor.clear(); 325 } 326 } 327 328 aCopy.clear(); 329 330 #if OSL_DEBUG_LEVEL > 0 331 // SAFE -> 332 aReadLock.lock(); 333 if (!m_lInterceptionRegs.empty() ) 334 OSL_ENSURE(sal_False, "There are some pending interceptor objects, which seams to be registered during (!) the destruction of a frame."); 335 aReadLock.unlock(); 336 // <- SAFE 337 #endif // ODL_DEBUG_LEVEL>0 338 339 #endif // FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN 340 } 341 342 } // namespace framework 343