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_dbaccess.hxx"
26 
27 #include "intercept.hxx"
28 #include "dbastrings.hrc"
29 
30 #include <com/sun/star/embed/EmbedStates.hpp>
31 #include <com/sun/star/document/XEventBroadcaster.hpp>
32 #include <com/sun/star/util/XModifiable.hpp>
33 #include <cppuhelper/weak.hxx>
34 
35 #include <comphelper/types.hxx>
36 #include <tools/debug.hxx>
37 #include <tools/diagnose_ex.h>
38 
39 
40 namespace dbaccess
41 {
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::util;
44 using namespace ::com::sun::star::ucb;
45 using namespace ::com::sun::star::beans;
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star::sdbc;
48 using namespace ::com::sun::star::frame;
49 using namespace ::com::sun::star::io;
50 using namespace ::com::sun::star::embed;
51 using namespace ::com::sun::star::container;
52 using namespace ::comphelper;
53 using namespace ::cppu;
54 
55 #define DISPATCH_SAVEAS		0
56 #define DISPATCH_SAVE		1
57 #define DISPATCH_CLOSEDOC	2
58 #define DISPATCH_CLOSEWIN	3
59 #define DISPATCH_CLOSEFRAME	4
60 #define DISPATCH_RELOAD		5
61 // the OSL_ENSURE in CTOR has to be changed too, when adding new defines
62 
dispose()63 void SAL_CALL OInterceptor::dispose()
64 	throw( RuntimeException )
65 {
66 	EventObject aEvt( *this );
67 
68     osl::MutexGuard aGuard(m_aMutex);
69 
70     if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
71 		m_pDisposeEventListeners->disposeAndClear( aEvt );
72 
73 	if ( m_pStatCL )
74 		m_pStatCL->disposeAndClear( aEvt );
75 
76 	m_xSlaveDispatchProvider.clear();
77 	m_xMasterDispatchProvider.clear();
78 
79     m_pContentHolder = NULL;
80 }
81 
82 
DBG_NAME(OInterceptor)83 DBG_NAME(OInterceptor)
84 
85 OInterceptor::OInterceptor( ODocumentDefinition* _pContentHolder,sal_Bool _bAllowEditDoc )
86     :m_pContentHolder( _pContentHolder )
87     ,m_aInterceptedURL(7)
88     ,m_pDisposeEventListeners(0)
89     ,m_pStatCL(0)
90     ,m_bAllowEditDoc(_bAllowEditDoc)
91 {
92     DBG_CTOR(OInterceptor,NULL);
93 
94 	OSL_ENSURE(DISPATCH_RELOAD < m_aInterceptedURL.getLength(),"Illegal size.");
95 
96 	m_aInterceptedURL[DISPATCH_SAVEAS]		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:SaveAs"));
97 	m_aInterceptedURL[DISPATCH_SAVE]		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:Save"));
98 	m_aInterceptedURL[DISPATCH_CLOSEDOC]	= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:CloseDoc"));
99 	m_aInterceptedURL[DISPATCH_CLOSEWIN]	= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:CloseWin"));
100 	m_aInterceptedURL[DISPATCH_CLOSEFRAME]	= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:CloseFrame"));
101 	m_aInterceptedURL[DISPATCH_RELOAD]		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:Reload"));
102 }
103 
104 
~OInterceptor()105 OInterceptor::~OInterceptor()
106 {
107 	if( m_pDisposeEventListeners )
108 		delete m_pDisposeEventListeners;
109 
110 	if(m_pStatCL)
111 		delete m_pStatCL;
112 
113     DBG_DTOR(OInterceptor,NULL);
114 }
115 
116 struct DispatchHelper
117 {
118     URL aURL;
119     Sequence<PropertyValue > aArguments;
120 };
121 
122 //XDispatch
dispatch(const URL & _URL,const Sequence<PropertyValue> & Arguments)123 void SAL_CALL OInterceptor::dispatch( const URL& _URL,const Sequence<PropertyValue >& Arguments ) throw (RuntimeException)
124 {
125     ::osl::MutexGuard aGuard( m_aMutex );
126 	if ( !m_pContentHolder )
127         return;
128 
129     if ( _URL.Complete == m_aInterceptedURL[ DISPATCH_SAVE ] )
130 	{
131 		m_pContentHolder->save( sal_False );
132         return;
133     }
134 
135 	if ( _URL.Complete == m_aInterceptedURL[ DISPATCH_RELOAD ] )
136 	{
137         ODocumentDefinition::fillReportData(
138             m_pContentHolder->getContext(),
139             m_pContentHolder->getComponent(),
140             m_pContentHolder->getConnection()
141         );
142         return;
143 	}
144 
145 	if( _URL.Complete == m_aInterceptedURL[ DISPATCH_SAVEAS ] )
146 	{
147         if ( m_pContentHolder->isNewReport() )
148         {
149             m_pContentHolder->saveAs();
150         }
151         else if ( m_xSlaveDispatchProvider.is() )
152         {
153 		    Sequence< PropertyValue > aNewArgs = Arguments;
154 		    sal_Int32 nInd = 0;
155 
156 		    while( nInd < aNewArgs.getLength() )
157 		    {
158 			    if ( aNewArgs[nInd].Name.equalsAscii( "SaveTo" ) )
159 			    {
160 				    aNewArgs[nInd].Value <<= sal_True;
161 				    break;
162 			    }
163 			    nInd++;
164 		    }
165 
166 		    if ( nInd == aNewArgs.getLength() )
167 		    {
168 			    aNewArgs.realloc( nInd + 1 );
169 			    aNewArgs[nInd].Name = ::rtl::OUString::createFromAscii( "SaveTo" );
170 			    aNewArgs[nInd].Value <<= sal_True;
171 		    }
172 
173 		    Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch(
174 			    _URL, ::rtl::OUString::createFromAscii( "_self" ), 0 );
175 		    if ( xDispatch.is() )
176 			    xDispatch->dispatch( _URL, aNewArgs );
177         }
178         return;
179 	}
180 
181 	if  (   _URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEDOC ]
182         ||  _URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEWIN ]
183         ||  _URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEFRAME ]
184         )
185     {
186         DispatchHelper* pHelper = new DispatchHelper;
187         pHelper->aArguments = Arguments;
188         pHelper->aURL = _URL;
189         Application::PostUserEvent( LINK( this, OInterceptor, OnDispatch ), reinterpret_cast< void* >( pHelper ) );
190         return;
191 	}
192 }
193 
IMPL_LINK(OInterceptor,OnDispatch,void *,_pDispatcher)194 IMPL_LINK( OInterceptor, OnDispatch, void*, _pDispatcher )
195 {
196     ::std::auto_ptr<DispatchHelper> pHelper( reinterpret_cast< DispatchHelper* >( _pDispatcher ) );
197 	try
198 	{
199         if ( m_pContentHolder && m_pContentHolder->prepareClose() && m_xSlaveDispatchProvider.is() )
200 		{
201 		    Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch(
202                 pHelper->aURL, ::rtl::OUString::createFromAscii( "_self" ), 0 );
203 		    if ( xDispatch.is() )
204             {
205                 Reference< ::com::sun::star::document::XEventBroadcaster> xEvtB(m_pContentHolder->getComponent(),UNO_QUERY);
206                 if ( xEvtB.is() )
207                     xEvtB->removeEventListener(this);
208 
209                 Reference< XInterface > xKeepContentHolderAlive( *m_pContentHolder );
210                 xDispatch->dispatch( pHelper->aURL,pHelper->aArguments);
211             }
212 		}
213     }
214 	catch ( const Exception& )
215 	{
216         DBG_UNHANDLED_EXCEPTION();
217 	}
218 
219 	return 0L;
220 }
221 
addStatusListener(const Reference<XStatusListener> & Control,const URL & _URL)222 void SAL_CALL OInterceptor::addStatusListener(
223 	const Reference<
224 	XStatusListener >& Control,
225 	const URL& _URL )
226 	throw (
227 		RuntimeException
228 	)
229 {
230 	if(!Control.is())
231 		return;
232 
233 	if ( m_pContentHolder && _URL.Complete == m_aInterceptedURL[DISPATCH_SAVEAS] )
234 	{   // SaveAs
235 
236         if ( !m_pContentHolder->isNewReport() )
237         {
238             FeatureStateEvent aStateEvent;
239 		    aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVEAS];
240 		    aStateEvent.FeatureDescriptor = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SaveCopyTo"));
241 		    aStateEvent.IsEnabled = sal_True;
242 		    aStateEvent.Requery = sal_False;
243 		    aStateEvent.State <<= (rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("($3)")));
244             Control->statusChanged(aStateEvent);
245         }
246 
247 		{
248 			osl::MutexGuard aGuard(m_aMutex);
249 			if(!m_pStatCL)
250 				m_pStatCL = new PropertyChangeListenerContainer(m_aMutex);
251 		}
252 
253 		m_pStatCL->addInterface(_URL.Complete,Control);
254 	}
255 	else if ( m_pContentHolder && _URL.Complete == m_aInterceptedURL[DISPATCH_SAVE] )
256 	{   // Save
257 		FeatureStateEvent aStateEvent;
258 		aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVE];
259 		aStateEvent.FeatureDescriptor = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Update"));
260 		aStateEvent.IsEnabled = m_pContentHolder != NULL && m_pContentHolder->isModified();
261 		aStateEvent.Requery = sal_False;
262 
263 		Control->statusChanged(aStateEvent);
264 		{
265 			osl::MutexGuard aGuard(m_aMutex);
266 			if(!m_pStatCL)
267 				m_pStatCL = new PropertyChangeListenerContainer(m_aMutex);
268 		}
269 
270 		m_pStatCL->addInterface(_URL.Complete,Control);
271 		Reference< ::com::sun::star::document::XEventBroadcaster> xEvtB(m_pContentHolder->getComponent(),UNO_QUERY);
272 		if ( xEvtB.is() )
273 			xEvtB->addEventListener(this);
274 	}
275 	else
276 	{
277 		sal_Int32 i = 2;
278 		if(_URL.Complete == m_aInterceptedURL[i] ||
279 			_URL.Complete == m_aInterceptedURL[++i] ||
280 			_URL.Complete == m_aInterceptedURL[++i] ||
281 			_URL.Complete == m_aInterceptedURL[i = DISPATCH_RELOAD] )
282 		{   // Close and return
283 			FeatureStateEvent aStateEvent;
284 			aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
285 			aStateEvent.FeatureDescriptor = rtl::OUString(
286 				RTL_CONSTASCII_USTRINGPARAM("Close and Return"));
287 			aStateEvent.IsEnabled = sal_True;
288 			aStateEvent.Requery = sal_False;
289 			Control->statusChanged(aStateEvent);
290 
291 
292 			{
293 				osl::MutexGuard aGuard(m_aMutex);
294 				if(!m_pStatCL)
295 					m_pStatCL = new PropertyChangeListenerContainer(m_aMutex);
296 			}
297 
298 			m_pStatCL->addInterface(_URL.Complete,Control);
299 			return;
300 		}
301 	}
302 }
303 
304 
removeStatusListener(const Reference<XStatusListener> & Control,const URL & _URL)305 void SAL_CALL OInterceptor::removeStatusListener(
306 	const Reference<
307 	XStatusListener >& Control,
308 	const URL& _URL )
309 	throw (
310 		RuntimeException
311 	)
312 {
313 	if(!(Control.is() && m_pStatCL))
314 		return;
315 	else
316 	{
317 		m_pStatCL->removeInterface(_URL.Complete,Control);
318 		return;
319 	}
320 }
321 
322 
323 //XInterceptorInfo
getInterceptedURLs()324 Sequence< ::rtl::OUString > SAL_CALL OInterceptor::getInterceptedURLs(  ) 	throw ( RuntimeException	)
325 {
326 	// now implemented as update
327 	return m_aInterceptedURL;
328 }
329 
330 
331 // XDispatchProvider
332 
queryDispatch(const URL & _URL,const::rtl::OUString & TargetFrameName,sal_Int32 SearchFlags)333 Reference< XDispatch > SAL_CALL OInterceptor::queryDispatch( const URL& _URL,const ::rtl::OUString& TargetFrameName,sal_Int32 SearchFlags )
334 	throw (RuntimeException)
335 {
336 	osl::MutexGuard aGuard(m_aMutex);
337 	const ::rtl::OUString* pIter = m_aInterceptedURL.getConstArray();
338 	const ::rtl::OUString* pEnd	  = pIter + m_aInterceptedURL.getLength();
339 	for(;pIter != pEnd;++pIter)
340 	{
341 		if ( _URL.Complete == *pIter )
342 			return (XDispatch*)this;
343 	}
344 
345 	if(m_xSlaveDispatchProvider.is())
346 		return m_xSlaveDispatchProvider->queryDispatch(_URL,TargetFrameName,SearchFlags);
347 	else
348 		return Reference<XDispatch>();
349 }
350 
queryDispatches(const Sequence<DispatchDescriptor> & Requests)351 Sequence< Reference< XDispatch > > SAL_CALL OInterceptor::queryDispatches( 	const Sequence<DispatchDescriptor >& Requests )	throw (		RuntimeException	)
352 {
353 	Sequence< Reference< XDispatch > > aRet;
354 	osl::MutexGuard aGuard(m_aMutex);
355 	if(m_xSlaveDispatchProvider.is())
356 		aRet = m_xSlaveDispatchProvider->queryDispatches(Requests);
357 	else
358 		aRet.realloc(Requests.getLength());
359 
360 	for(sal_Int32 i = 0; i < Requests.getLength(); ++i)
361 	{
362 		const ::rtl::OUString* pIter = m_aInterceptedURL.getConstArray();
363 		const ::rtl::OUString* pEnd	  = pIter + m_aInterceptedURL.getLength();
364 		for(;pIter != pEnd;++pIter)
365 		{
366 			if ( Requests[i].FeatureURL.Complete == *pIter )
367 			{
368 				aRet[i] = (XDispatch*) this;
369 				break;
370 			}
371 		}
372 	}
373 
374 	return aRet;
375 }
376 
377 
378 
379 //XDispatchProviderInterceptor
380 
getSlaveDispatchProvider()381 Reference< XDispatchProvider > SAL_CALL OInterceptor::getSlaveDispatchProvider(  ) 	throw ( RuntimeException 	)
382 {
383 	osl::MutexGuard aGuard(m_aMutex);
384 	return m_xSlaveDispatchProvider;
385 }
386 
387 void SAL_CALL
setSlaveDispatchProvider(const Reference<XDispatchProvider> & NewDispatchProvider)388 OInterceptor::setSlaveDispatchProvider(	const Reference< XDispatchProvider >& NewDispatchProvider )
389 	throw (		RuntimeException	)
390 {
391 	osl::MutexGuard aGuard(m_aMutex);
392 	m_xSlaveDispatchProvider = NewDispatchProvider;
393 }
394 
395 
getMasterDispatchProvider()396 Reference< XDispatchProvider > SAL_CALL OInterceptor::getMasterDispatchProvider(  )
397 	throw (
398 		RuntimeException
399 	)
400 {
401 	osl::MutexGuard aGuard(m_aMutex);
402 	return m_xMasterDispatchProvider;
403 }
404 
405 
setMasterDispatchProvider(const Reference<XDispatchProvider> & NewSupplier)406 void SAL_CALL OInterceptor::setMasterDispatchProvider(
407 	const Reference< XDispatchProvider >& NewSupplier )
408 	throw (
409 		RuntimeException
410 	)
411 {
412 	osl::MutexGuard aGuard(m_aMutex);
413 	m_xMasterDispatchProvider = NewSupplier;
414 }
415 // -----------------------------------------------------------------------------
notifyEvent(const::com::sun::star::document::EventObject & Event)416 void SAL_CALL OInterceptor::notifyEvent( const ::com::sun::star::document::EventObject& Event ) throw (::com::sun::star::uno::RuntimeException)
417 {
418 	osl::ResettableMutexGuard _rGuard(m_aMutex);
419 	if ( m_pStatCL &&	Event.EventName == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OnModifyChanged")) )
420 	{
421 		OInterfaceContainerHelper* pListener = m_pStatCL->getContainer(m_aInterceptedURL[DISPATCH_SAVE]);
422 		if ( pListener )
423 		{
424 			FeatureStateEvent aEvt;
425 			aEvt.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVE];
426 			aEvt.FeatureDescriptor = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Update"));
427 			Reference<XModifiable> xModel(Event.Source,UNO_QUERY);
428 			aEvt.IsEnabled = xModel.is() && xModel->isModified();
429 			aEvt.Requery = sal_False;
430 
431 			NOTIFY_LISTERNERS((*pListener),XStatusListener,statusChanged)
432 		}
433 	}
434 }
435 // -----------------------------------------------------------------------------
disposing(const::com::sun::star::lang::EventObject &)436 void SAL_CALL OInterceptor::disposing( const ::com::sun::star::lang::EventObject& /*Source*/ ) throw (::com::sun::star::uno::RuntimeException)
437 {
438 }
439 
440 //........................................................................
441 }	// namespace dbaccess
442 //........................................................................
443 
444