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 #include "embeddoc.hxx"
29 #include <osl/diagnose.h>
30 #include <com/sun/star/frame/XController.hpp>
31 #include <com/sun/star/beans/PropertyValue.hpp>
32 
33 
34 using namespace ::com::sun::star;
35 
36 
37 extern ::rtl::OUString	getFilterNameFromGUID_Impl( GUID* );
38 
39 //-------------------------------------------------------------------------------
40 // IOleObject
41 
42 
43 STDMETHODIMP EmbedDocument_Impl::SetClientSite( IOleClientSite* pSite )
44 {
45 	m_pClientSite = pSite;
46 	return S_OK;
47 }
48 
49 STDMETHODIMP EmbedDocument_Impl::GetClientSite( IOleClientSite** pSite )
50 {
51 	*pSite = m_pClientSite;
52 	return S_OK;
53 }
54 
55 STDMETHODIMP EmbedDocument_Impl::SetHostNames( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj )
56 {
57 	// the code should be ignored for links
58 	if ( !m_aFileName.getLength() )
59 	{
60 		m_pDocHolder->setTitle(
61 			rtl::OUString(
62 				(sal_Unicode*)szContainerObj));
63 		m_pDocHolder->setContainerName(
64 			rtl::OUString(
65 				(sal_Unicode*)szContainerApp));
66 	}
67 
68 	return S_OK;
69 }
70 
71 STDMETHODIMP EmbedDocument_Impl::Close( DWORD dwSaveOption )
72 {
73     HRESULT hr = S_OK;
74 
75     if ( m_pDocHolder->HasFrame() )
76     {
77         if ( dwSaveOption == 2 && m_aFileName.getLength() )
78         {
79             // ask the user about saving
80             if ( m_pDocHolder->ExecuteSuspendCloseFrame() )
81             {
82                 m_pDocHolder->CloseDocument();
83                 return S_OK;
84             }
85             else
86                 return OLE_E_PROMPTSAVECANCELLED;
87         }
88 
89         if ( dwSaveOption != 1 )
90             hr = SaveObject(); // ADVF_DATAONSTOP);
91 
92 	    m_pDocHolder->CloseFrame();
93         OLENotifyDeactivation();
94     }
95 
96 	m_pDocHolder->FreeOffice();
97 	m_pDocHolder->CloseDocument();
98 
99 	OLENotifyClosing();
100 
101 	return hr;
102 }
103 
104 
105 HRESULT EmbedDocument_Impl::OLENotifyClosing()
106 {
107 	HRESULT hr = S_OK;
108 
109 	AdviseSinkHashMap aAHM(m_aAdviseHashMap);
110 
111 	for ( AdviseSinkHashMapIterator iAdvise = aAHM.begin();
112 		  iAdvise != aAHM.end(); iAdvise++ )
113 	{
114 		if ( iAdvise->second )
115 			iAdvise->second->OnClose();
116 	}
117 
118 	return hr;
119 
120 }
121 
122 STDMETHODIMP EmbedDocument_Impl::SetMoniker( DWORD /*dwWhichMoniker*/, IMoniker * /*pmk*/ )
123 {
124     return E_NOTIMPL;
125 }
126 
127 STDMETHODIMP EmbedDocument_Impl::GetMoniker( DWORD /*dwAssign*/, DWORD /*dwWhichMoniker*/, IMoniker ** /*ppmk*/ )
128 {
129     return E_NOTIMPL;
130 }
131 
132 STDMETHODIMP EmbedDocument_Impl::InitFromData( IDataObject * /*pDataObject*/, BOOL /*fCreation*/, DWORD /*dwReserved*/ )
133 {
134     return E_NOTIMPL;
135 }
136 
137 STDMETHODIMP EmbedDocument_Impl::GetClipboardData( DWORD /*dwReserved*/, IDataObject ** /*ppDataObject*/ )
138 {
139     return E_NOTIMPL;
140 }
141 
142 /**
143  *  Well, this is a not so very inefficient way to deliver
144  *
145  */
146 
147 STDMETHODIMP EmbedDocument_Impl::DoVerb(
148 	LONG iVerb,
149 	LPMSG,
150 	IOleClientSite *pActiveSite,
151 	LONG,
152 	HWND,
153 	LPCRECT )
154 {
155 	// no locking is used since the OLE must use the same thread always
156 	if ( m_bIsInVerbHandling )
157         return OLEOBJ_S_CANNOT_DOVERB_NOW;
158 
159     // an object can not handle any Verbs in Hands off mode
160     if ( m_pMasterStorage == NULL || m_pOwnStream == NULL )
161         return OLE_E_CANT_BINDTOSOURCE;
162 
163 
164 	BooleanGuard_Impl aGuard( m_bIsInVerbHandling );
165 
166 	if ( iVerb == OLEIVERB_PRIMARY )
167 	{
168 		if ( m_aFileName.getLength() )
169 		{
170 			// that should be a link
171 			iVerb = OLEIVERB_OPEN;
172 		}
173 		else
174 			iVerb = OLEIVERB_SHOW;
175 	}
176 
177 	try
178 	{
179 		switch(iVerb) {
180 			case OLEIVERB_DISCARDUNDOSTATE:
181 				// free any undostate?
182 				break;
183 			case OLEIVERB_INPLACEACTIVATE:
184 				OSL_ENSURE(m_pDocHolder,"no document for inplace activation");
185 
186 				return m_pDocHolder->InPlaceActivate(pActiveSite,FALSE);
187 				break;
188 			case OLEIVERB_UIACTIVATE:
189 				OSL_ENSURE(m_pDocHolder,"no document for	 inplace activation");
190 
191 				return m_pDocHolder->InPlaceActivate(pActiveSite,TRUE);
192 				break;
193 			case OLEIVERB_PRIMARY:
194 			case OLEIVERB_SHOW:
195 				OSL_ENSURE(m_pDocHolder,"no document for inplace activation");
196 
197 				if(m_pDocHolder->isActive())
198 					return NOERROR; //Already active
199 
200 				if(SUCCEEDED(
201 					m_pDocHolder->InPlaceActivate(
202 						pActiveSite,TRUE)))
203 					return NOERROR;
204 
205 				// intended fall trough
206 			case OLEIVERB_OPEN:
207 				OSL_ENSURE(m_pDocHolder,"no document to open");
208 
209 				// the commented code could be usefull in case
210 				// outer window would be resized depending from inner one
211 				// RECTL aEmbArea;
212 				// m_pDocHolder->GetVisArea( &aEmbArea );
213 				// m_pDocHolder->show();
214 				// m_pDocHolder->SetVisArea( &aEmbArea );
215 
216 				if(m_pDocHolder->isActive())
217 				{
218 					m_pDocHolder->InPlaceDeactivate();
219 					m_pDocHolder->DisableInplaceActivation(true);
220 				}
221 
222 				SIZEL aEmbSize;
223 				m_pDocHolder->GetExtent( &aEmbSize );
224 				m_pDocHolder->show();
225 				m_pDocHolder->resizeWin( aEmbSize );
226 
227 				if ( m_pClientSite )
228 					m_pClientSite->OnShowWindow( TRUE );
229 
230 				notify();
231 				break;
232 			case OLEIVERB_HIDE:
233 				OSL_ENSURE(m_pDocHolder,"no document to hide");
234 
235 				if(m_pDocHolder->isActive())
236 					m_pDocHolder->InPlaceDeactivate();
237 				else {
238 					m_pDocHolder->hide();
239 
240 					if( m_pClientSite )
241 						m_pClientSite->OnShowWindow(FALSE);
242 				}
243 				break;
244 			default:
245 				break;
246 		}
247 	}
248 	catch( uno::Exception& )
249 	{
250 		return OLEOBJ_S_CANNOT_DOVERB_NOW;
251 	}
252 
253 	return NOERROR;
254 }
255 
256 
257 
258 STDMETHODIMP EmbedDocument_Impl::EnumVerbs( IEnumOLEVERB ** /*ppEnumOleVerb*/ )
259 {
260     return OLE_S_USEREG;
261 }
262 
263 STDMETHODIMP EmbedDocument_Impl::Update()
264 {
265     return S_OK;
266 //    HRESULT hr = CACHE_E_NOCACHE_UPDATED;
267 //    return hr;
268 }
269 
270 STDMETHODIMP EmbedDocument_Impl::IsUpToDate()
271 {
272     return S_OK;
273 }
274 
275 STDMETHODIMP EmbedDocument_Impl::GetUserClassID( CLSID *pClsid )
276 {
277     return GetClassID( pClsid );
278 }
279 
280 STDMETHODIMP EmbedDocument_Impl::GetUserType( DWORD /*dwFormOfTypeUe*/, LPOLESTR * /*pszUserType*/ )
281 {
282     return OLE_S_USEREG;
283 }
284 
285 STDMETHODIMP EmbedDocument_Impl::SetExtent( DWORD /*dwDrawAspect*/, SIZEL *psizel )
286 {
287     if ( !psizel )
288         return E_FAIL;
289 
290     m_pDocHolder->SetExtent( psizel );
291 
292     return S_OK;
293 }
294 
295 STDMETHODIMP EmbedDocument_Impl::GetExtent( DWORD /*dwDrawAspect*/, SIZEL * psizel )
296 {
297     if ( !psizel )
298         return E_INVALIDARG;
299 
300     if ( FAILED( m_pDocHolder->GetExtent( psizel ) ) )
301     {
302         // return default values
303         psizel->cx = 500;
304         psizel->cy = 500;
305     }
306 
307     return S_OK;
308 }
309 
310 STDMETHODIMP EmbedDocument_Impl::Advise( IAdviseSink *pAdvSink, DWORD *pdwConnection )
311 {
312     if ( m_nAdviseNum == 0xFFFFFFFF )
313         return E_OUTOFMEMORY;
314 
315     pAdvSink->AddRef();
316     m_aAdviseHashMap.insert( ::std::pair< DWORD, IAdviseSink* >( m_nAdviseNum, pAdvSink ) );
317     *pdwConnection = m_nAdviseNum++;
318 
319     return S_OK;
320 }
321 
322 STDMETHODIMP EmbedDocument_Impl::Unadvise( DWORD dwConnection )
323 {
324 	AdviseSinkHashMapIterator iAdvise = m_aAdviseHashMap.find( dwConnection );
325 	if ( iAdvise != m_aAdviseHashMap.end() )
326 	{
327 		iAdvise->second->Release();
328 		m_aAdviseHashMap.erase( iAdvise );
329 	}
330 	else
331 		return OLE_E_NOCONNECTION;
332 
333 	return S_OK;
334 }
335 
336 STDMETHODIMP EmbedDocument_Impl::EnumAdvise( IEnumSTATDATA ** /*ppenumAdvise*/ )
337 {
338 	return E_NOTIMPL;
339 }
340 
341 STDMETHODIMP EmbedDocument_Impl::GetMiscStatus( DWORD /*dwAspect*/, DWORD * /*pdwStatus*/ )
342 {
343 	return OLE_S_USEREG;
344 }
345 
346 STDMETHODIMP EmbedDocument_Impl::SetColorScheme( LOGPALETTE * /*pLogpal*/ )
347 {
348 	return E_NOTIMPL;
349 }
350 
351 //-------------------------------------------------------------------------------
352 // IDispatch
353 
354 STDMETHODIMP EmbedDocument_Impl::GetTypeInfoCount( unsigned int FAR*  pctinfo )
355 {
356 	if ( m_pDocHolder->GetIDispatch() )
357 		return m_pDocHolder->GetIDispatch()->GetTypeInfoCount( pctinfo );
358 
359 	return E_NOTIMPL;
360 }
361 
362 STDMETHODIMP EmbedDocument_Impl::GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo )
363 {
364 	if ( m_pDocHolder->GetIDispatch() )
365 		return m_pDocHolder->GetIDispatch()->GetTypeInfo( iTInfo, lcid, ppTInfo );
366 
367 	return DISP_E_BADINDEX; // the only error that can be returned
368 }
369 
370 STDMETHODIMP EmbedDocument_Impl::GetIDsOfNames( REFIID riid,
371 												OLECHAR FAR* FAR* rgszNames,
372 												unsigned int cNames,
373 												LCID lcid,
374 												DISPID FAR* rgDispId )
375 {
376 	if ( m_pDocHolder->GetIDispatch() )
377 		return m_pDocHolder->GetIDispatch()->GetIDsOfNames( riid, rgszNames, cNames, lcid, rgDispId );
378 
379 	for ( unsigned int ind = 0; ind < cNames; ind++ )
380 		rgDispId[ind] = DISPID_UNKNOWN;
381 
382 	return DISP_E_UNKNOWNNAME;
383 }
384 
385 STDMETHODIMP EmbedDocument_Impl::Invoke( DISPID dispIdMember,
386 										 REFIID riid,
387 										 LCID lcid,
388 										 WORD wFlags,
389 										 DISPPARAMS FAR* pDispParams,
390 										 VARIANT FAR* pVarResult,
391 										 EXCEPINFO FAR* pExcepInfo,
392 										 unsigned int FAR* puArgErr )
393 {
394 	if ( m_pDocHolder->GetIDispatch() )
395 		return m_pDocHolder->GetIDispatch()->Invoke( dispIdMember,
396 													 riid,
397 													 lcid,
398 													 wFlags,
399 													 pDispParams,
400 													 pVarResult,
401 													 pExcepInfo,
402 													 puArgErr );
403 
404 	return DISP_E_MEMBERNOTFOUND;
405 }
406 
407 //-------------------------------------------------------------------------------
408 // IExternalConnection
409 
410 DWORD STDMETHODCALLTYPE EmbedDocument_Impl::AddConnection( DWORD , DWORD )
411 {
412     return AddRef();
413 }
414 
415 DWORD STDMETHODCALLTYPE EmbedDocument_Impl::ReleaseConnection( DWORD , DWORD , BOOL )
416 {
417     return Release();
418 }
419 
420 // C++ - methods
421 
422 HRESULT EmbedDocument_Impl::SaveObject()
423 {
424 	HRESULT hr = S_OK;
425 
426 	if(m_pClientSite) {
427 		hr = m_pClientSite->SaveObject();
428 
429 		for ( AdviseSinkHashMapIterator iAdvise =
430 				  m_aAdviseHashMap.begin();
431 			  iAdvise != m_aAdviseHashMap.end();
432 			  iAdvise++ )
433 			if ( iAdvise->second )
434 				iAdvise->second->OnSave( );
435 	}
436 	else if ( m_aFileName.getLength() && IsDirty() == S_OK )
437 	{
438 		::rtl::OUString aPreservFileName = m_aFileName;
439 
440 		// in case of links the containers does not provide client site sometimes
441 		hr = Save( (LPCOLESTR)NULL, FALSE ); // triggers saving to the link location
442 		SaveCompleted( (LPCOLESTR)aPreservFileName.getStr() );
443 	}
444 
445     notify( false );
446 
447 	return hr;
448 }
449 
450 
451 HRESULT EmbedDocument_Impl::ShowObject()
452 {
453 	HRESULT hr = S_OK;
454 
455 	if(m_pClientSite)
456 		hr = m_pClientSite->ShowObject();
457 
458 	return hr;
459 }
460 
461 
462 void EmbedDocument_Impl::notify( bool bDataChanged )
463 {
464 	for ( AdviseSinkHashMapIterator iAdvise =
465 			  m_aAdviseHashMap.begin();
466 		  iAdvise != m_aAdviseHashMap.end();
467 		  iAdvise++ )
468 		if ( iAdvise->second )
469 			iAdvise->second->OnViewChange( DVASPECT_CONTENT, -1 );
470 
471     if ( m_pDAdviseHolder && bDataChanged )
472 		m_pDAdviseHolder->SendOnDataChange( (IDataObject*)this, 0, 0 );
473 }
474 
475 void EmbedDocument_Impl::Deactivate()
476 {
477     HRESULT hr = S_OK;
478 
479     if ( m_pDocHolder->HasFrame() )
480     {
481 	    hr = SaveObject();
482 	    m_pDocHolder->CloseFrame();
483 	    OLENotifyDeactivation();
484     }
485 }
486 
487 HRESULT EmbedDocument_Impl::OLENotifyDeactivation()
488 {
489 	HRESULT hr = S_OK;
490 
491 	if ( m_pClientSite )
492 		hr = m_pClientSite->OnShowWindow( FALSE );
493 
494 	return hr;
495 
496 }
497 
498 // Fix strange warnings about some
499 // ATL::CAxHostWindow::QueryInterface|AddRef|Releae functions.
500 // warning C4505: 'xxx' : unreferenced local function has been removed
501 #if defined(_MSC_VER)
502 #pragma warning(disable: 4505)
503 #endif
504 
505