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