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