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_sc.hxx" 30 31 32 33 #include <sfx2/viewfrm.hxx> 34 #include <comphelper/uno3.hxx> 35 #include <svx/dataaccessdescriptor.hxx> 36 #include <svl/smplhint.hxx> 37 38 #include <com/sun/star/frame/XDispatchProviderInterception.hpp> 39 #include <com/sun/star/view/XSelectionSupplier.hpp> 40 #include <com/sun/star/sdb/CommandType.hpp> 41 42 #include "dispuno.hxx" 43 #include "unoguard.hxx" 44 #include "tabvwsh.hxx" 45 #include "dbdocfun.hxx" 46 #include "dbcolect.hxx" 47 48 using namespace com::sun::star; 49 50 //------------------------------------------------------------------------ 51 52 const char* cURLInsertColumns = ".uno:DataSourceBrowser/InsertColumns"; //data into text 53 const char* cURLDocDataSource = ".uno:DataSourceBrowser/DocumentDataSource"; 54 55 //------------------------------------------------------------------------ 56 57 SV_IMPL_PTRARR( XStatusListenerArr_Impl, XStatusListenerPtr ); 58 59 //------------------------------------------------------------------------ 60 61 uno::Reference<view::XSelectionSupplier> lcl_GetSelectionSupplier( SfxViewShell* pViewShell ) 62 { 63 if ( pViewShell ) 64 { 65 SfxViewFrame* pViewFrame = pViewShell->GetViewFrame(); 66 if (pViewFrame) 67 { 68 return uno::Reference<view::XSelectionSupplier>( pViewFrame->GetFrame().GetController(), uno::UNO_QUERY ); 69 } 70 } 71 return uno::Reference<view::XSelectionSupplier>(); 72 } 73 74 //------------------------------------------------------------------------ 75 76 77 ScDispatchProviderInterceptor::ScDispatchProviderInterceptor(ScTabViewShell* pViewSh) : 78 pViewShell( pViewSh ) 79 { 80 if ( pViewShell ) 81 { 82 m_xIntercepted.set(uno::Reference<frame::XDispatchProviderInterception>(pViewShell->GetViewFrame()->GetFrame().GetFrameInterface(), uno::UNO_QUERY)); 83 if (m_xIntercepted.is()) 84 { 85 comphelper::increment( m_refCount ); 86 87 m_xIntercepted->registerDispatchProviderInterceptor( 88 static_cast<frame::XDispatchProviderInterceptor*>(this)); 89 // this should make us the top-level dispatch-provider for the component, via a call to our 90 // setDispatchProvider we should have got an fallback for requests we (i.e. our master) cannot fullfill 91 uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY); 92 if (xInterceptedComponent.is()) 93 xInterceptedComponent->addEventListener(static_cast<lang::XEventListener*>(this)); 94 95 comphelper::decrement( m_refCount ); 96 } 97 98 StartListening(*pViewShell); 99 } 100 } 101 102 ScDispatchProviderInterceptor::~ScDispatchProviderInterceptor() 103 { 104 if (pViewShell) 105 EndListening(*pViewShell); 106 } 107 108 void ScDispatchProviderInterceptor::Notify( SfxBroadcaster&, const SfxHint& rHint ) 109 { 110 if ( rHint.ISA( SfxSimpleHint ) && 111 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) 112 pViewShell = NULL; 113 } 114 115 // XDispatchProvider 116 117 uno::Reference<frame::XDispatch> SAL_CALL ScDispatchProviderInterceptor::queryDispatch( 118 const util::URL& aURL, const rtl::OUString& aTargetFrameName, 119 sal_Int32 nSearchFlags ) 120 throw(uno::RuntimeException) 121 { 122 ScUnoGuard aGuard; 123 124 uno::Reference<frame::XDispatch> xResult; 125 // create some dispatch ... 126 if ( pViewShell && ( 127 !aURL.Complete.compareToAscii(cURLInsertColumns) || 128 !aURL.Complete.compareToAscii(cURLDocDataSource) ) ) 129 { 130 if (!m_xMyDispatch.is()) 131 m_xMyDispatch = new ScDispatch( pViewShell ); 132 xResult = m_xMyDispatch; 133 } 134 135 // ask our slave provider 136 if (!xResult.is() && m_xSlaveDispatcher.is()) 137 xResult = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags); 138 139 return xResult; 140 } 141 142 uno::Sequence< uno::Reference<frame::XDispatch> > SAL_CALL 143 ScDispatchProviderInterceptor::queryDispatches( 144 const uno::Sequence<frame::DispatchDescriptor>& aDescripts ) 145 throw(uno::RuntimeException) 146 { 147 ScUnoGuard aGuard; 148 149 uno::Sequence< uno::Reference< frame::XDispatch> > aReturn(aDescripts.getLength()); 150 uno::Reference< frame::XDispatch>* pReturn = aReturn.getArray(); 151 const frame::DispatchDescriptor* pDescripts = aDescripts.getConstArray(); 152 for (sal_Int16 i=0; i<aDescripts.getLength(); ++i, ++pReturn, ++pDescripts) 153 { 154 *pReturn = queryDispatch(pDescripts->FeatureURL, 155 pDescripts->FrameName, pDescripts->SearchFlags); 156 } 157 return aReturn; 158 } 159 160 // XDispatchProviderInterceptor 161 162 uno::Reference<frame::XDispatchProvider> SAL_CALL 163 ScDispatchProviderInterceptor::getSlaveDispatchProvider() 164 throw(uno::RuntimeException) 165 { 166 ScUnoGuard aGuard; 167 return m_xSlaveDispatcher; 168 } 169 170 void SAL_CALL ScDispatchProviderInterceptor::setSlaveDispatchProvider( 171 const uno::Reference<frame::XDispatchProvider>& xNewDispatchProvider ) 172 throw(uno::RuntimeException) 173 { 174 ScUnoGuard aGuard; 175 m_xSlaveDispatcher.set(xNewDispatchProvider); 176 } 177 178 uno::Reference<frame::XDispatchProvider> SAL_CALL 179 ScDispatchProviderInterceptor::getMasterDispatchProvider() 180 throw(uno::RuntimeException) 181 { 182 ScUnoGuard aGuard; 183 return m_xMasterDispatcher; 184 } 185 186 void SAL_CALL ScDispatchProviderInterceptor::setMasterDispatchProvider( 187 const uno::Reference<frame::XDispatchProvider>& xNewSupplier ) 188 throw(uno::RuntimeException) 189 { 190 ScUnoGuard aGuard; 191 m_xMasterDispatcher.set(xNewSupplier); 192 } 193 194 // XEventListener 195 196 void SAL_CALL ScDispatchProviderInterceptor::disposing( const lang::EventObject& /* Source */ ) 197 throw(::com::sun::star::uno::RuntimeException) 198 { 199 ScUnoGuard aGuard; 200 201 if (m_xIntercepted.is()) 202 { 203 m_xIntercepted->releaseDispatchProviderInterceptor( 204 static_cast<frame::XDispatchProviderInterceptor*>(this)); 205 uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY); 206 if (xInterceptedComponent.is()) 207 xInterceptedComponent->removeEventListener(static_cast<lang::XEventListener*>(this)); 208 209 m_xMyDispatch = NULL; 210 } 211 m_xIntercepted = NULL; 212 } 213 214 //------------------------------------------------------------------------ 215 216 ScDispatch::ScDispatch(ScTabViewShell* pViewSh) : 217 pViewShell( pViewSh ), 218 bListeningToView( sal_False ) 219 { 220 if (pViewShell) 221 StartListening(*pViewShell); 222 } 223 224 ScDispatch::~ScDispatch() 225 { 226 if (pViewShell) 227 EndListening(*pViewShell); 228 229 if (bListeningToView && pViewShell) 230 { 231 uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell )); 232 if ( xSupplier.is() ) 233 xSupplier->removeSelectionChangeListener(this); 234 } 235 } 236 237 void ScDispatch::Notify( SfxBroadcaster&, const SfxHint& rHint ) 238 { 239 if ( rHint.ISA( SfxSimpleHint ) && 240 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) 241 pViewShell = NULL; 242 } 243 244 // XDispatch 245 246 void SAL_CALL ScDispatch::dispatch( const util::URL& aURL, 247 const uno::Sequence<beans::PropertyValue>& aArgs ) 248 throw(uno::RuntimeException) 249 { 250 ScUnoGuard aGuard; 251 252 sal_Bool bDone = sal_False; 253 if ( pViewShell && !aURL.Complete.compareToAscii(cURLInsertColumns) ) 254 { 255 ScViewData* pViewData = pViewShell->GetViewData(); 256 ScAddress aPos( pViewData->GetCurX(), pViewData->GetCurY(), pViewData->GetTabNo() ); 257 258 ScDBDocFunc aFunc( *pViewData->GetDocShell() ); 259 bDone = aFunc.DoImportUno( aPos, aArgs ); 260 } 261 // cURLDocDataSource is never dispatched 262 263 if (!bDone) 264 throw uno::RuntimeException(); 265 } 266 267 void lcl_FillDataSource( frame::FeatureStateEvent& rEvent, const ScImportParam& rParam ) 268 { 269 rEvent.IsEnabled = rParam.bImport; 270 271 ::svx::ODataAccessDescriptor aDescriptor; 272 if ( rParam.bImport ) 273 { 274 sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND : 275 ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY : 276 sdb::CommandType::TABLE ); 277 278 aDescriptor.setDataSource(rtl::OUString( rParam.aDBName )); 279 aDescriptor[svx::daCommand] <<= rtl::OUString( rParam.aStatement ); 280 aDescriptor[svx::daCommandType] <<= nType; 281 } 282 else 283 { 284 // descriptor has to be complete anyway 285 286 rtl::OUString aEmpty; 287 aDescriptor[svx::daDataSource] <<= aEmpty; 288 aDescriptor[svx::daCommand] <<= aEmpty; 289 aDescriptor[svx::daCommandType] <<= (sal_Int32)sdb::CommandType::TABLE; 290 } 291 rEvent.State <<= aDescriptor.createPropertyValueSequence(); 292 } 293 294 void SAL_CALL ScDispatch::addStatusListener( 295 const uno::Reference<frame::XStatusListener>& xListener, 296 const util::URL& aURL ) 297 throw(uno::RuntimeException) 298 { 299 ScUnoGuard aGuard; 300 301 if (!pViewShell) 302 throw uno::RuntimeException(); 303 304 // initial state 305 frame::FeatureStateEvent aEvent; 306 aEvent.IsEnabled = sal_True; 307 aEvent.Source.set(static_cast<cppu::OWeakObject*>(this)); 308 aEvent.FeatureURL = aURL; 309 310 if ( !aURL.Complete.compareToAscii(cURLDocDataSource) ) 311 { 312 uno::Reference<frame::XStatusListener>* pObj = 313 new uno::Reference<frame::XStatusListener>( xListener ); 314 aDataSourceListeners.Insert( pObj, aDataSourceListeners.Count() ); 315 316 if (!bListeningToView) 317 { 318 uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell )); 319 if ( xSupplier.is() ) 320 xSupplier->addSelectionChangeListener(this); 321 bListeningToView = sal_True; 322 } 323 324 ScDBData* pDBData = pViewShell->GetDBData(sal_False,SC_DB_OLD); 325 if ( pDBData ) 326 pDBData->GetImportParam( aLastImport ); 327 lcl_FillDataSource( aEvent, aLastImport ); // modifies State, IsEnabled 328 } 329 //! else add to listener for "enabled" changes? 330 331 xListener->statusChanged( aEvent ); 332 } 333 334 void SAL_CALL ScDispatch::removeStatusListener( 335 const uno::Reference<frame::XStatusListener>& xListener, 336 const util::URL& aURL ) 337 throw(uno::RuntimeException) 338 { 339 ScUnoGuard aGuard; 340 341 if ( !aURL.Complete.compareToAscii(cURLDocDataSource) ) 342 { 343 sal_uInt16 nCount = aDataSourceListeners.Count(); 344 for ( sal_uInt16 n=nCount; n--; ) 345 { 346 uno::Reference<frame::XStatusListener> *pObj = aDataSourceListeners[n]; 347 if ( *pObj == xListener ) 348 { 349 aDataSourceListeners.DeleteAndDestroy( n ); 350 break; 351 } 352 } 353 354 if ( aDataSourceListeners.Count() == 0 && pViewShell ) 355 { 356 uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell )); 357 if ( xSupplier.is() ) 358 xSupplier->removeSelectionChangeListener(this); 359 bListeningToView = sal_False; 360 } 361 } 362 } 363 364 // XSelectionChangeListener 365 366 void SAL_CALL ScDispatch::selectionChanged( const ::com::sun::star::lang::EventObject& /* aEvent */ ) 367 throw (::com::sun::star::uno::RuntimeException) 368 { 369 // currently only called for URL cURLDocDataSource 370 371 if ( pViewShell ) 372 { 373 ScImportParam aNewImport; 374 ScDBData* pDBData = pViewShell->GetDBData(sal_False,SC_DB_OLD); 375 if ( pDBData ) 376 pDBData->GetImportParam( aNewImport ); 377 378 // notify listeners only if data source has changed 379 if ( aNewImport.bImport != aLastImport.bImport || 380 aNewImport.aDBName != aLastImport.aDBName || 381 aNewImport.aStatement != aLastImport.aStatement || 382 aNewImport.bSql != aLastImport.bSql || 383 aNewImport.nType != aLastImport.nType ) 384 { 385 frame::FeatureStateEvent aEvent; 386 aEvent.Source.set(static_cast<cppu::OWeakObject*>(this)); 387 aEvent.FeatureURL.Complete = rtl::OUString::createFromAscii( cURLDocDataSource ); 388 389 lcl_FillDataSource( aEvent, aNewImport ); // modifies State, IsEnabled 390 391 for ( sal_uInt16 n=0; n<aDataSourceListeners.Count(); n++ ) 392 (*aDataSourceListeners[n])->statusChanged( aEvent ); 393 394 aLastImport = aNewImport; 395 } 396 } 397 } 398 399 // XEventListener 400 401 void SAL_CALL ScDispatch::disposing( const ::com::sun::star::lang::EventObject& rSource ) 402 throw (::com::sun::star::uno::RuntimeException) 403 { 404 uno::Reference<view::XSelectionSupplier> xSupplier(rSource.Source, uno::UNO_QUERY); 405 xSupplier->removeSelectionChangeListener(this); 406 bListeningToView = sal_False; 407 408 lang::EventObject aEvent; 409 aEvent.Source.set(static_cast<cppu::OWeakObject*>(this)); 410 for ( sal_uInt16 n=0; n<aDataSourceListeners.Count(); n++ ) 411 (*aDataSourceListeners[n])->disposing( aEvent ); 412 413 pViewShell = NULL; 414 } 415 416