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 #include <cppuhelper/weak.hxx>
28 
29 #include <embeddoc.hxx>
30 #include <docholder.hxx>
31 #include <intercept.hxx>
32 
33 using namespace ::com::sun::star;
34 
35 
36 
37 #define IUL 6
38 
39 
40 
41 uno::Sequence< ::rtl::OUString > Interceptor::m_aInterceptedURL(IUL);
42 
43 
44 
45 
46 struct equalOUString
47 {
48 	bool operator()(
49 		const rtl::OUString& rKey1,
50 		const rtl::OUString& rKey2 ) const
51 	{
52 		return !!( rKey1 == rKey2 );
53 	}
54 };
55 
56 
57 struct hashOUString
58 {
59 	size_t operator()( const rtl::OUString& rName ) const
60 	{
61 		return rName.hashCode();
62 	}
63 };
64 
65 
66 
67 class StatusChangeListenerContainer
68 	: public ::cppu::OMultiTypeInterfaceContainerHelperVar<
69 rtl::OUString,hashOUString,equalOUString>
70 {
71 public:
72 	StatusChangeListenerContainer( ::osl::Mutex& aMutex )
73 		:  cppu::OMultiTypeInterfaceContainerHelperVar<
74 	rtl::OUString,hashOUString,equalOUString>(aMutex)
75 	{
76 	}
77 };
78 
79 
80 void SAL_CALL
81 Interceptor::addEventListener(
82 	const uno::Reference<lang::XEventListener >& Listener )
83 	throw( uno::RuntimeException )
84 {
85 	osl::MutexGuard aGuard( m_aMutex );
86 
87 	if ( ! m_pDisposeEventListeners )
88 		m_pDisposeEventListeners =
89 			new cppu::OInterfaceContainerHelper( m_aMutex );
90 
91 	m_pDisposeEventListeners->addInterface( Listener );
92 }
93 
94 
95 void SAL_CALL
96 Interceptor::removeEventListener(
97 	const uno::Reference< lang::XEventListener >& Listener )
98 	throw( uno::RuntimeException )
99 {
100 	osl::MutexGuard aGuard( m_aMutex );
101 
102 	if ( m_pDisposeEventListeners )
103 		m_pDisposeEventListeners->removeInterface( Listener );
104 }
105 
106 
107 void SAL_CALL Interceptor::dispose()
108 	throw(::com::sun::star::uno::RuntimeException)
109 {
110 	lang::EventObject aEvt;
111 	aEvt.Source = static_cast< frame::XDispatch* >( this );
112 
113 	osl::MutexGuard aGuard(m_aMutex);
114 
115 	if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
116 		m_pDisposeEventListeners->disposeAndClear( aEvt );
117 
118 	if(m_pStatCL)
119 		m_pStatCL->disposeAndClear( aEvt );
120 
121 	m_xSlaveDispatchProvider = 0;
122 	m_xMasterDispatchProvider = 0;
123 }
124 
125 
126 
127 Interceptor::Interceptor(
128 	const ::rtl::Reference< EmbeddedDocumentInstanceAccess_Impl >& xOleAccess,
129 	DocumentHolder* pDocH,
130 	sal_Bool bLink )
131 	: m_xOleAccess( xOleAccess ),
132 	  m_xDocHLocker( static_cast< ::cppu::OWeakObject* >( pDocH ) ),
133 	  m_pDocH(pDocH),
134 	  m_pStatCL(0),
135 	  m_pDisposeEventListeners(0),
136 	  m_bLink( bLink )
137 {
138 	m_aInterceptedURL[0] = rtl::OUString(
139 		RTL_CONSTASCII_USTRINGPARAM(".uno:Save"));
140 	m_aInterceptedURL[1] = rtl::OUString(
141 		RTL_CONSTASCII_USTRINGPARAM(".uno:SaveAll"));
142 	m_aInterceptedURL[2] = rtl::OUString(
143 		RTL_CONSTASCII_USTRINGPARAM(".uno:CloseDoc"));
144 	m_aInterceptedURL[3] = rtl::OUString(
145 		RTL_CONSTASCII_USTRINGPARAM(".uno:CloseWin"));
146 	m_aInterceptedURL[4] = rtl::OUString(
147 		RTL_CONSTASCII_USTRINGPARAM(".uno:CloseFrame"));
148 	m_aInterceptedURL[5] = rtl::OUString(
149 		RTL_CONSTASCII_USTRINGPARAM(".uno:SaveAs"));
150 }
151 
152 
153 Interceptor::~Interceptor()
154 {
155 	if( m_pDisposeEventListeners )
156 		delete m_pDisposeEventListeners;
157 
158 	if(m_pStatCL)
159 		delete m_pStatCL;
160 
161 	DocumentHolder* pTmpDocH = NULL;
162 	uno::Reference< uno::XInterface > xLock;
163 	{
164 		osl::MutexGuard aGuard(m_aMutex);
165 		xLock = m_xDocHLocker.get();
166 		if ( xLock.is() )
167 			pTmpDocH = m_pDocH;
168 	}
169 
170 	if ( pTmpDocH )
171 		pTmpDocH->ClearInterceptor();
172 }
173 
174 void Interceptor::DisconnectDocHolder()
175 {
176 	osl::MutexGuard aGuard(m_aMutex);
177 	m_xDocHLocker.clear();
178 	m_pDocH = NULL;
179 	m_xOleAccess = NULL;
180 }
181 
182 //XDispatch
183 void SAL_CALL
184 Interceptor::dispatch(
185 	const util::URL& URL,
186 	const uno::Sequence<
187 	beans::PropertyValue >& Arguments )
188 	throw (uno::RuntimeException)
189 {
190 	::rtl::Reference< EmbeddedDocumentInstanceAccess_Impl > xOleAccess;
191 	{
192 		osl::MutexGuard aGuard(m_aMutex);
193 		xOleAccess = m_xOleAccess;
194 	}
195 
196 	if ( xOleAccess.is() )
197 	{
198 		LockedEmbedDocument_Impl aDocLock = xOleAccess->GetEmbedDocument();
199 		if ( aDocLock.GetEmbedDocument() )
200 		{
201             if( !m_bLink && URL.Complete == m_aInterceptedURL[0])
202                 aDocLock.GetEmbedDocument()->SaveObject();
203             else if(!m_bLink
204                  && ( URL.Complete == m_aInterceptedURL[2] ||
205                       URL.Complete == m_aInterceptedURL[3] ||
206                       URL.Complete == m_aInterceptedURL[4] ) )
207                 aDocLock.GetEmbedDocument()->Close( 0 );
208 			else if ( URL.Complete == m_aInterceptedURL[5] )
209 			{
210 				uno::Sequence< beans::PropertyValue > aNewArgs = Arguments;
211 				sal_Int32 nInd = 0;
212 
213 				while( nInd < aNewArgs.getLength() )
214 				{
215 					if ( aNewArgs[nInd].Name.equalsAscii( "SaveTo" ) )
216 					{
217 						aNewArgs[nInd].Value <<= sal_True;
218 						break;
219 					}
220 					nInd++;
221 				}
222 
223 				if ( nInd == aNewArgs.getLength() )
224 				{
225 					aNewArgs.realloc( nInd + 1 );
226 					aNewArgs[nInd].Name = ::rtl::OUString::createFromAscii( "SaveTo" );
227 					aNewArgs[nInd].Value <<= sal_True;
228 				}
229 
230 				uno::Reference< frame::XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch(
231 					URL, ::rtl::OUString::createFromAscii( "_self" ), 0 );
232 				if ( xDispatch.is() )
233 					xDispatch->dispatch( URL, aNewArgs );
234 			}
235 		}
236 	}
237 }
238 
239 
240 void Interceptor::generateFeatureStateEvent()
241 {
242 	if( m_pStatCL )
243 	{
244 		DocumentHolder* pTmpDocH = NULL;
245 		uno::Reference< uno::XInterface > xLock;
246 		{
247 			osl::MutexGuard aGuard(m_aMutex);
248 			xLock = m_xDocHLocker.get();
249 			if ( xLock.is() )
250 				pTmpDocH = m_pDocH;
251 		}
252 
253 		::rtl::OUString aTitle;
254 		if ( pTmpDocH )
255 			aTitle = pTmpDocH->getTitle();
256 
257 		for(int i = 0; i < IUL; ++i)
258 		{
259 			if( i == 1 || m_bLink && i != 5 )
260 				continue;
261 
262 			cppu::OInterfaceContainerHelper* pICH =
263 				m_pStatCL->getContainer(m_aInterceptedURL[i]);
264 			uno::Sequence<uno::Reference<uno::XInterface> > aSeq;
265 			if(pICH)
266 				aSeq = pICH->getElements();
267 			if(!aSeq.getLength())
268 				continue;
269 
270 			frame::FeatureStateEvent aStateEvent;
271 			aStateEvent.IsEnabled = sal_True;
272 			aStateEvent.Requery = sal_False;
273 			if(i == 0)
274 			{
275 
276 				aStateEvent.FeatureURL.Complete = m_aInterceptedURL[0];
277 				aStateEvent.FeatureDescriptor = rtl::OUString(
278 					RTL_CONSTASCII_USTRINGPARAM("Update"));
279 				aStateEvent.State <<= (rtl::OUString(
280 					RTL_CONSTASCII_USTRINGPARAM("($1) ")) +
281 									   aTitle);
282 
283 			}
284 			else if ( i == 5 )
285 			{
286 				aStateEvent.FeatureURL.Complete = m_aInterceptedURL[5];
287 				aStateEvent.FeatureDescriptor = rtl::OUString(
288 					RTL_CONSTASCII_USTRINGPARAM("SaveCopyTo"));
289 				aStateEvent.State <<= (rtl::OUString(
290 					RTL_CONSTASCII_USTRINGPARAM("($3)")));
291 			}
292 			else
293 			{
294 				aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
295 				aStateEvent.FeatureDescriptor = rtl::OUString(
296 					RTL_CONSTASCII_USTRINGPARAM("Close and Return"));
297 				aStateEvent.State <<= (rtl::OUString(
298 					RTL_CONSTASCII_USTRINGPARAM("($2) ")) +
299 									   aTitle);
300 
301 			}
302 
303 			for(sal_Int32 k = 0; k < aSeq.getLength(); ++k)
304 			{
305 				uno::Reference<frame::XStatusListener>
306 					Control(aSeq[k],uno::UNO_QUERY);
307 				if(Control.is())
308 					Control->statusChanged(aStateEvent);
309 
310 			}
311 		}
312 	}
313 }
314 
315 
316 void SAL_CALL
317 Interceptor::addStatusListener(
318 	const uno::Reference<
319 	frame::XStatusListener >& Control,
320 	const util::URL& URL )
321 	throw (
322 		uno::RuntimeException
323 	)
324 {
325 	if(!Control.is())
326 		return;
327 
328 	if( !m_bLink && URL.Complete == m_aInterceptedURL[0] )
329 	{   // Save
330 		DocumentHolder* pTmpDocH = NULL;
331 		uno::Reference< uno::XInterface > xLock;
332 		{
333 			osl::MutexGuard aGuard(m_aMutex);
334 			xLock = m_xDocHLocker.get();
335 			if ( xLock.is() )
336 				pTmpDocH = m_pDocH;
337 		}
338 
339 		::rtl::OUString aTitle;
340 		if ( pTmpDocH )
341 			aTitle = pTmpDocH->getTitle();
342 
343 		frame::FeatureStateEvent aStateEvent;
344 		aStateEvent.FeatureURL.Complete = m_aInterceptedURL[0];
345 		aStateEvent.FeatureDescriptor = rtl::OUString(
346 			RTL_CONSTASCII_USTRINGPARAM("Update"));
347 		aStateEvent.IsEnabled = sal_True;
348 		aStateEvent.Requery = sal_False;
349 		aStateEvent.State <<= (rtl::OUString(
350 			RTL_CONSTASCII_USTRINGPARAM("($1) ")) +
351 							   aTitle );
352 		Control->statusChanged(aStateEvent);
353 
354 		{
355 			osl::MutexGuard aGuard(m_aMutex);
356 			if(!m_pStatCL)
357 				m_pStatCL =
358 					new StatusChangeListenerContainer(m_aMutex);
359 		}
360 
361 		m_pStatCL->addInterface(URL.Complete,Control);
362 		return;
363 	}
364 
365 	sal_Int32 i = 2;
366 	if ( !m_bLink
367 	  && ( URL.Complete == m_aInterceptedURL[i] ||
368 	       URL.Complete == m_aInterceptedURL[++i] ||
369 	       URL.Complete == m_aInterceptedURL[++i] ) )
370 	{   // Close and return
371 		DocumentHolder* pTmpDocH = NULL;
372 		uno::Reference< uno::XInterface > xLock;
373 		{
374 			osl::MutexGuard aGuard(m_aMutex);
375 			xLock = m_xDocHLocker.get();
376 			if ( xLock.is() )
377 				pTmpDocH = m_pDocH;
378 		}
379 
380 		::rtl::OUString aTitle;
381 		if ( pTmpDocH )
382 			aTitle = pTmpDocH->getTitle();
383 
384 		frame::FeatureStateEvent aStateEvent;
385 		aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
386 		aStateEvent.FeatureDescriptor = rtl::OUString(
387 			RTL_CONSTASCII_USTRINGPARAM("Close and Return"));
388 		aStateEvent.IsEnabled = sal_True;
389 		aStateEvent.Requery = sal_False;
390 		aStateEvent.State <<= (rtl::OUString(
391 			RTL_CONSTASCII_USTRINGPARAM("($2) ")) +
392 							   aTitle );
393 		Control->statusChanged(aStateEvent);
394 
395 
396 		{
397 			osl::MutexGuard aGuard(m_aMutex);
398 			if(!m_pStatCL)
399 				m_pStatCL =
400 					new StatusChangeListenerContainer(m_aMutex);
401 		}
402 
403 		m_pStatCL->addInterface(URL.Complete,Control);
404 		return;
405 	}
406 
407 	if(URL.Complete == m_aInterceptedURL[5])
408 	{   // SaveAs
409 		frame::FeatureStateEvent aStateEvent;
410 		aStateEvent.FeatureURL.Complete = m_aInterceptedURL[5];
411 		aStateEvent.FeatureDescriptor = rtl::OUString(
412 			RTL_CONSTASCII_USTRINGPARAM("SaveCopyTo"));
413 		aStateEvent.IsEnabled = sal_True;
414 		aStateEvent.Requery = sal_False;
415 		aStateEvent.State <<= (rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("($3)")));
416 		Control->statusChanged(aStateEvent);
417 
418 		{
419 			osl::MutexGuard aGuard(m_aMutex);
420 			if(!m_pStatCL)
421 				m_pStatCL =
422 					new StatusChangeListenerContainer(m_aMutex);
423 		}
424 
425 		m_pStatCL->addInterface(URL.Complete,Control);
426 		return;
427 	}
428 
429 }
430 
431 
432 void SAL_CALL
433 Interceptor::removeStatusListener(
434 	const uno::Reference<
435 	frame::XStatusListener >& Control,
436 	const util::URL& URL )
437 	throw (
438 		uno::RuntimeException
439 	)
440 {
441 	if(!(Control.is() && m_pStatCL))
442 		return;
443 	else {
444 		m_pStatCL->removeInterface(URL.Complete,Control);
445 		return;
446 	}
447 }
448 
449 
450 //XInterceptorInfo
451 uno::Sequence< ::rtl::OUString >
452 SAL_CALL
453 Interceptor::getInterceptedURLs(  )
454 	throw (
455 		uno::RuntimeException
456 	)
457 {
458 	// now implemented as update
459 	if ( m_bLink )
460 	{
461 		uno::Sequence< ::rtl::OUString > aResult( 2 );
462 		aResult[0] = m_aInterceptedURL[1];
463 		aResult[1] = m_aInterceptedURL[5];
464 
465 		return aResult;
466 	}
467 
468 	return m_aInterceptedURL;
469 }
470 
471 
472 // XDispatchProvider
473 
474 uno::Reference< frame::XDispatch > SAL_CALL
475 Interceptor::queryDispatch(
476 	const util::URL& URL,
477 	const ::rtl::OUString& TargetFrameName,
478 	sal_Int32 SearchFlags )
479 	throw (
480 		uno::RuntimeException
481 	)
482 {
483 	osl::MutexGuard aGuard(m_aMutex);
484 	if( !m_bLink && URL.Complete == m_aInterceptedURL[0] )
485 		return (frame::XDispatch*)this;
486 	else if(URL.Complete == m_aInterceptedURL[1])
487 		return (frame::XDispatch*)0   ;
488 	else if( !m_bLink && URL.Complete == m_aInterceptedURL[2] )
489 		return (frame::XDispatch*)this;
490 	else if( !m_bLink && URL.Complete == m_aInterceptedURL[3] )
491 		return (frame::XDispatch*)this;
492 	else if( !m_bLink && URL.Complete == m_aInterceptedURL[4] )
493 		return (frame::XDispatch*)this;
494 	else if(URL.Complete == m_aInterceptedURL[5])
495 		return (frame::XDispatch*)this;
496 	else {
497 		if(m_xSlaveDispatchProvider.is())
498 			return m_xSlaveDispatchProvider->queryDispatch(
499 				URL,TargetFrameName,SearchFlags);
500 		else
501 			return uno::Reference<frame::XDispatch>(0);
502 	}
503 }
504 
505 uno::Sequence< uno::Reference< frame::XDispatch > > SAL_CALL
506 Interceptor::queryDispatches(
507 	const uno::Sequence<frame::DispatchDescriptor >& Requests )
508 	throw (
509 		uno::RuntimeException
510 	)
511 {
512 	uno::Sequence< uno::Reference< frame::XDispatch > > aRet;
513 	osl::MutexGuard aGuard(m_aMutex);
514 	if(m_xSlaveDispatchProvider.is())
515 		aRet = m_xSlaveDispatchProvider->queryDispatches(Requests);
516 	else
517 		aRet.realloc(Requests.getLength());
518 
519 	for(sal_Int32 i = 0; i < Requests.getLength(); ++i)
520 		if ( !m_bLink && m_aInterceptedURL[0] == Requests[i].FeatureURL.Complete )
521 			aRet[i] = (frame::XDispatch*) this;
522 		else if(m_aInterceptedURL[1] == Requests[i].FeatureURL.Complete)
523 			aRet[i] = (frame::XDispatch*) 0;
524 		else if( !m_bLink && m_aInterceptedURL[2] == Requests[i].FeatureURL.Complete )
525 			aRet[i] = (frame::XDispatch*) this;
526 		else if( !m_bLink && m_aInterceptedURL[3] == Requests[i].FeatureURL.Complete )
527 			aRet[i] = (frame::XDispatch*) this;
528 		else if( !m_bLink && m_aInterceptedURL[4] == Requests[i].FeatureURL.Complete )
529 			aRet[i] = (frame::XDispatch*) this;
530 		else if(m_aInterceptedURL[5] == Requests[i].FeatureURL.Complete)
531 			aRet[i] = (frame::XDispatch*) this;
532 
533 	return aRet;
534 }
535 
536 
537 
538 //XDispatchProviderInterceptor
539 
540 uno::Reference< frame::XDispatchProvider > SAL_CALL
541 Interceptor::getSlaveDispatchProvider(  )
542 	throw (
543 		uno::RuntimeException
544 	)
545 {
546 	osl::MutexGuard aGuard(m_aMutex);
547 	return m_xSlaveDispatchProvider;
548 }
549 
550 void SAL_CALL
551 Interceptor::setSlaveDispatchProvider(
552 	const uno::Reference< frame::XDispatchProvider >& NewDispatchProvider )
553 	throw (
554 		uno::RuntimeException
555 	)
556 {
557 	osl::MutexGuard aGuard(m_aMutex);
558 	m_xSlaveDispatchProvider = NewDispatchProvider;
559 }
560 
561 
562 uno::Reference< frame::XDispatchProvider > SAL_CALL
563 Interceptor::getMasterDispatchProvider(  )
564 	throw (
565 		uno::RuntimeException
566 	)
567 {
568 	osl::MutexGuard aGuard(m_aMutex);
569 	return m_xMasterDispatchProvider;
570 }
571 
572 
573 void SAL_CALL
574 Interceptor::setMasterDispatchProvider(
575 	const uno::Reference< frame::XDispatchProvider >& NewSupplier )
576 	throw (
577 		uno::RuntimeException
578 	)
579 {
580 	osl::MutexGuard aGuard(m_aMutex);
581 	m_xMasterDispatchProvider = NewSupplier;
582 }
583 
584 // Fix strange warnings about some
585 // ATL::CAxHostWindow::QueryInterface|AddRef|Releae functions.
586 // warning C4505: 'xxx' : unreferenced local function has been removed
587 #if defined(_MSC_VER)
588 #pragma warning(disable: 4505)
589 #endif
590