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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svtools.hxx"
30 #include <com/sun/star/embed/XComponentSupplier.hpp>
31 #include <com/sun/star/embed/EmbedStates.hpp>
32 #include <com/sun/star/embed/XVisualObject.hpp>
33 #include <com/sun/star/embed/XEmbedPersist.hpp>
34 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
35 #include <com/sun/star/datatransfer/XTransferable.hpp>
36 #include <com/sun/star/embed/Aspects.hpp>
37 
38 #include <svtools/embedtransfer.hxx>
39 #include <tools/mapunit.hxx>
40 #include <vcl/outdev.hxx>
41 #include <comphelper/storagehelper.hxx>
42 #include <unotools/ucbstreamhelper.hxx>
43 #include <unotools/streamwrap.hxx>
44 #include <unotools/tempfile.hxx>
45 #include <toolkit/helper/vclunohelper.hxx>
46 
47 #include <svtools/embedhlp.hxx>
48 
49 using namespace ::com::sun::star;
50 
51 SvEmbedTransferHelper::SvEmbedTransferHelper( const uno::Reference< embed::XEmbeddedObject >& xObj,
52 												Graphic* pGraphic,
53 												sal_Int64 nAspect )
54 : m_xObj( xObj )
55 , m_pGraphic( pGraphic ? new Graphic( *pGraphic ) : NULL )
56 , m_nAspect( nAspect )
57 {
58     if( xObj.is() )
59     {
60         TransferableObjectDescriptor aObjDesc;
61 
62         FillTransferableObjectDescriptor( aObjDesc, m_xObj, NULL, m_nAspect );
63         PrepareOLE( aObjDesc );
64     }
65 }
66 
67 // -----------------------------------------------------------------------------
68 
69 SvEmbedTransferHelper::~SvEmbedTransferHelper()
70 {
71 	if ( m_pGraphic )
72 	{
73 		delete m_pGraphic;
74 		m_pGraphic = NULL;
75 	}
76 }
77 
78 // -----------------------------------------------------------------------------
79 
80 void SvEmbedTransferHelper::AddSupportedFormats()
81 {
82 	AddFormat( SOT_FORMATSTR_ID_EMBED_SOURCE );
83 	AddFormat( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR );
84 	AddFormat( FORMAT_GDIMETAFILE );
85 }
86 
87 // -----------------------------------------------------------------------------
88 
89 sal_Bool SvEmbedTransferHelper::GetData( const ::com::sun::star::datatransfer::DataFlavor& rFlavor )
90 {
91 	sal_Bool bRet = sal_False;
92 
93 	if( m_xObj.is() )
94 	{
95         try
96         {
97             sal_uInt32 nFormat = SotExchange::GetFormat( rFlavor );
98             if( HasFormat( nFormat ) )
99             {
100                 if( nFormat == SOT_FORMATSTR_ID_OBJECTDESCRIPTOR )
101                 {
102                     TransferableObjectDescriptor aDesc;
103                     FillTransferableObjectDescriptor( aDesc, m_xObj, m_pGraphic, m_nAspect );
104                     bRet = SetTransferableObjectDescriptor( aDesc, rFlavor );
105                 }
106                 else if( nFormat == SOT_FORMATSTR_ID_EMBED_SOURCE )
107                 {
108                     try
109                     {
110 						// TODO/LATER: Propbably the graphic should be copied here as well
111 						// currently it is handled by the applications
112                         utl::TempFile aTmp;
113                         aTmp.EnableKillingFile( sal_True );
114                         uno::Reference < embed::XEmbedPersist > xPers( m_xObj, uno::UNO_QUERY );
115                         if ( xPers.is() )
116                         {
117                             uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetTemporaryStorage();
118                             ::rtl::OUString aName = ::rtl::OUString::createFromAscii("Dummy");
119                             SvStream* pStream = NULL;
120                             sal_Bool bDeleteStream = sal_False;
121                             uno::Sequence < beans::PropertyValue > aEmpty;
122                             xPers->storeToEntry( xStg, aName, aEmpty, aEmpty );
123                             if ( xStg->isStreamElement( aName ) )
124                             {
125                                 uno::Reference < io::XStream > xStm = xStg->cloneStreamElement( aName );
126                                 pStream = utl::UcbStreamHelper::CreateStream( xStm );
127                                 bDeleteStream = sal_True;
128                             }
129                             else
130                             {
131                                 pStream = aTmp.GetStream( STREAM_STD_READWRITE );
132                                 uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper( *pStream ) );
133                                 xStg->openStorageElement( aName, embed::ElementModes::READ )->copyToStorage( xStor );
134                             }
135 
136                             ::com::sun::star::uno::Any                  aAny;
137                             const sal_uInt32                            nLen = pStream->Seek( STREAM_SEEK_TO_END );
138                             ::com::sun::star::uno::Sequence< sal_Int8 > aSeq( nLen );
139 
140                             pStream->Seek( STREAM_SEEK_TO_BEGIN );
141                             pStream->Read( aSeq.getArray(),  nLen );
142                             if ( bDeleteStream )
143                                 delete pStream;
144 
145                             if( ( bRet = ( aSeq.getLength() > 0 ) ) == sal_True )
146                             {
147                                 aAny <<= aSeq;
148                                 SetAny( aAny, rFlavor );
149                             }
150                         }
151                         else
152                         {
153                             //TODO/LATER: how to handle objects without persistance?!
154                         }
155                     }
156                     catch ( uno::Exception& )
157                     {
158                     }
159                 }
160                 else if ( nFormat == FORMAT_GDIMETAFILE && m_pGraphic )
161 				{
162 					SvMemoryStream aMemStm( 65535, 65535 );
163                     aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
164 
165 					const GDIMetaFile& aMetaFile = m_pGraphic->GetGDIMetaFile();
166 					((GDIMetaFile*)(&aMetaFile))->Write( aMemStm );
167 					uno::Any aAny;
168 					aAny <<= uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aMemStm.GetData() ),
169 													aMemStm.Seek( STREAM_SEEK_TO_END ) );
170 					SetAny( aAny, rFlavor );
171 					bRet = sal_True;
172 				}
173 				else if ( m_xObj.is() && :: svt::EmbeddedObjectRef::TryRunningState( m_xObj ) )
174                 {
175                     uno::Reference< datatransfer::XTransferable > xTransferable( m_xObj->getComponent(), uno::UNO_QUERY );
176                     if ( xTransferable.is() )
177                     {
178                         uno::Any aAny = xTransferable->getTransferData( rFlavor );
179                         SetAny( aAny, rFlavor );
180                         bRet = sal_True;
181                     }
182                 }
183             }
184 		}
185 		catch( uno::Exception& )
186 		{
187 			// Error handling?
188 		}
189 	}
190 
191 	return bRet;
192 }
193 
194 // -----------------------------------------------------------------------------
195 
196 void SvEmbedTransferHelper::ObjectReleased()
197 {
198 	m_xObj = uno::Reference< embed::XEmbeddedObject >();
199 }
200 
201 void SvEmbedTransferHelper::FillTransferableObjectDescriptor( TransferableObjectDescriptor& rDesc,
202     const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XEmbeddedObject >& xObj,
203 	Graphic* pGraphic,
204 	sal_Int64 nAspect )
205 {
206     //TODO/LATER: need TypeName to fill it into the Descriptor (will be shown in listbox)
207     ::com::sun::star::datatransfer::DataFlavor aFlavor;
208     SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR, aFlavor );
209 
210     rDesc.maClassName = SvGlobalName( xObj->getClassID() );
211     rDesc.maTypeName = aFlavor.HumanPresentableName;
212 
213     //TODO/LATER: the aspect size in the descriptor is wrong, unfortunately the stream
214 	// representation of the descriptor allows only 4 bytes for the aspect
215 	// so for internal transport something different should be found
216     rDesc.mnViewAspect = sal::static_int_cast<sal_uInt16>( nAspect );
217 
218     //TODO/LATER: status needs to become sal_Int64
219     rDesc.mnOle2Misc = sal::static_int_cast<sal_Int32>(xObj->getStatus( rDesc.mnViewAspect ));
220 
221 	Size aSize;
222 	MapMode aMapMode( MAP_100TH_MM );
223 	if ( nAspect == embed::Aspects::MSOLE_ICON )
224 	{
225 		if ( pGraphic )
226 		{
227 			aMapMode = pGraphic->GetPrefMapMode();
228 			aSize = pGraphic->GetPrefSize();
229 		}
230 		else
231 			aSize = Size( 2500, 2500 );
232 	}
233 	else
234 	{
235 		try
236 		{
237     		awt::Size aSz;
238 			aSz = xObj->getVisualAreaSize( rDesc.mnViewAspect );
239 			aSize = Size( aSz.Width, aSz.Height );
240 		}
241 		catch( embed::NoVisualAreaSizeException& )
242 		{
243 			OSL_ENSURE( sal_False, "Can not get visual area size!\n" );
244 			aSize = Size( 5000, 5000 );
245 		}
246 
247     	// TODO/LEAN: getMapUnit can switch object to running state
248     	aMapMode = MapMode( VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( rDesc.mnViewAspect ) ) );
249 	}
250 
251     rDesc.maSize = OutputDevice::LogicToLogic( aSize, aMapMode, MapMode( MAP_100TH_MM ) );
252 	rDesc.maDragStartPos = Point();
253 	rDesc.maDisplayName = String();
254 	rDesc.mbCanLink = sal_False;
255 }
256 
257