merged tag ooo/OOO330_m14
[LibreOffice.git] / sc / source / filter / xcl97 / xcl97esc.cxx
bloba7c6dee67dc514e281e798fdf1578fdd43dc20b5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
31 #include <com/sun/star/awt/XControlModel.hpp>
32 #include <com/sun/star/embed/XClassifiedObject.hpp>
33 #include <com/sun/star/form/XFormsSupplier.hpp>
34 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
35 #include <com/sun/star/script/XEventAttacherManager.hpp>
37 #include <svx/svdpage.hxx>
38 #include <editeng/outlobj.hxx>
39 #include <svx/svdotext.hxx>
40 #include <svx/svdobj.hxx>
41 #include <svx/svdoole2.hxx>
42 #include <svx/unoapi.hxx>
43 #include <svx/fmglob.hxx>
44 #include <filter/msfilter/msocximex.hxx>
45 #include <vcl/outdev.hxx>
46 #include <unotools/tempfile.hxx>
47 #include <unotools/ucbstreamhelper.hxx>
48 #include <tools/debug.hxx>
49 #include <svx/sdasitm.hxx>
51 #include <sot/exchange.hxx>
52 #include "xeescher.hxx"
54 #include "global.hxx"
55 #include "document.hxx"
56 #include "drwlayer.hxx"
57 #include "xcl97rec.hxx"
58 #include "xehelper.hxx"
59 #include "xechart.hxx"
60 #include "xcl97esc.hxx"
62 using ::rtl::OUString;
63 using ::com::sun::star::uno::Any;
64 using ::com::sun::star::uno::Exception;
65 using ::com::sun::star::uno::Reference;
66 using ::com::sun::star::uno::Sequence;
67 using ::com::sun::star::uno::UNO_QUERY;
68 using ::com::sun::star::uno::UNO_QUERY_THROW;
69 using ::com::sun::star::container::XIndexAccess;
70 using ::com::sun::star::embed::XClassifiedObject;
71 using ::com::sun::star::drawing::XShape;
72 using ::com::sun::star::awt::XControlModel;
73 using ::com::sun::star::form::XFormsSupplier;
74 using ::com::sun::star::script::ScriptEventDescriptor;
75 using ::com::sun::star::script::XEventAttacherManager;
77 // ============================================================================
79 XclEscherExGlobal::XclEscherExGlobal( const XclExpRoot& rRoot ) :
80 XclExpRoot( rRoot )
84 SvStream* XclEscherExGlobal::ImplQueryPictureStream()
86 mxPicTempFile.reset( new ::utl::TempFile );
87 if( mxPicTempFile->IsValid() )
89 mxPicTempFile->EnableKillingFile();
90 mxPicStrm.reset( ::utl::UcbStreamHelper::CreateStream( mxPicTempFile->GetURL(), STREAM_STD_READWRITE ) );
91 mxPicStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
93 return mxPicStrm.get();
96 // ============================================================================
98 XclEscherEx::XclEscherEx( const XclExpRoot& rRoot, XclExpObjectManager& rObjMgr, SvStream& rStrm, const XclEscherEx* pParent ) :
99 EscherEx( pParent ? pParent->mxGlobal : EscherExGlobalRef( new XclEscherExGlobal( rRoot ) ), rStrm ),
100 XclExpRoot( rRoot ),
101 mrObjMgr( rObjMgr ),
102 pCurrXclObj( NULL ),
103 pCurrAppData( NULL ),
104 pTheClientData( new XclEscherClientData ),
105 pAdditionalText( NULL ),
106 nAdditionalText( 0 ),
107 mnNextKey( 0 ),
108 mbIsRootDff( pParent == 0 )
110 InsertPersistOffset( mnNextKey, 0 );
114 XclEscherEx::~XclEscherEx()
116 DBG_ASSERT( !aStack.Count(), "~XclEscherEx: stack not empty" );
117 DeleteCurrAppData();
118 delete pTheClientData;
122 sal_uInt32 XclEscherEx::InitNextDffFragment()
124 /* Current value of mnNextKey will be used by caller to refer to the
125 starting point of the DFF fragment. The key exists already in the
126 PersistTable (has been inserted by c'tor of previous call of
127 InitNextDffFragment(), has been updated by UpdateDffFragmentEnd(). */
128 sal_uInt32 nPersistKey = mnNextKey;
130 /* Prepare the next key that is used by caller as end point of the DFF
131 fragment. Will be updated by caller when writing to the DFF stream,
132 using the UpdateDffFragmentEnd() function. This is needed to find DFF
133 data written by the SVX base class implementation without interaction,
134 e.g. the solver container that will be written after the last shape. */
135 ++mnNextKey;
136 InsertPersistOffset( mnNextKey, mpOutStrm->Tell() );
138 return nPersistKey;
141 void XclEscherEx::UpdateDffFragmentEnd()
143 // update existing fragment key with new stream position
144 ReplacePersistOffset( mnNextKey, mpOutStrm->Tell() );
147 sal_uInt32 XclEscherEx::GetDffFragmentPos( sal_uInt32 nFragmentKey )
149 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
150 is non-const due to tools/List usage. */
151 return GetPersistOffset( nFragmentKey );
154 sal_uInt32 XclEscherEx::GetDffFragmentSize( sal_uInt32 nFragmentKey )
156 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
157 is non-const due to tools/List usage. */
158 return GetDffFragmentPos( nFragmentKey + 1 ) - GetDffFragmentPos( nFragmentKey );
161 bool XclEscherEx::HasPendingDffData()
163 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
164 is non-const due to tools/List usage. */
165 return GetDffFragmentPos( mnNextKey ) < GetStreamPos();
168 XclExpDffAnchorBase* XclEscherEx::CreateDffAnchor( const SdrObject& rSdrObj ) const
170 // the object manager creates the correct anchor type according to context
171 XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
172 // pass the drawing object, that will calculate the anchor position
173 pAnchor->SetSdrObject( rSdrObj );
174 return pAnchor;
177 namespace {
179 bool lcl_IsFontwork( const SdrObject* pObj )
181 bool bIsFontwork = false;
182 if( pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE )
184 const OUString aTextPath = CREATE_OUSTRING( "TextPath" );
185 SdrCustomShapeGeometryItem& rGeometryItem = (SdrCustomShapeGeometryItem&)
186 pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
187 if( Any* pAny = rGeometryItem.GetPropertyValueByName( aTextPath, aTextPath ) )
188 *pAny >>= bIsFontwork;
190 return bIsFontwork;
193 } // namespace
195 EscherExHostAppData* XclEscherEx::StartShape( const Reference< XShape >& rxShape, const Rectangle* pChildAnchor )
197 if ( nAdditionalText )
198 nAdditionalText++;
199 BOOL bInGroup = ( pCurrXclObj != NULL );
200 if ( bInGroup )
201 { // stacked recursive group object
202 if ( !pCurrAppData->IsStackedGroup() )
203 { //! UpdateDffFragmentEnd only once
204 pCurrAppData->SetStackedGroup( TRUE );
205 UpdateDffFragmentEnd();
208 aStack.Push( pCurrXclObj );
209 aStack.Push( pCurrAppData );
210 pCurrAppData = new XclEscherHostAppData;
211 SdrObject* pObj = GetSdrObjectFromXShape( rxShape );
212 if ( !pObj )
213 pCurrXclObj = new XclObjAny( mrObjMgr ); // just what is it?!?
214 else
216 pCurrXclObj = NULL;
217 sal_uInt16 nObjType = pObj->GetObjIdentifier();
219 if( nObjType == OBJ_OLE2 )
221 // no OLE objects in embedded drawings (chart shapes)
222 if( mbIsRootDff )
224 //! not-const because GetObjRef may load the OLE object
225 Reference < XClassifiedObject > xObj( ((SdrOle2Obj*)pObj)->GetObjRef(), UNO_QUERY );
226 if ( xObj.is() )
228 SvGlobalName aObjClsId( xObj->getClassID() );
229 if ( SotExchange::IsChart( aObjClsId ) )
230 { // yes, it's a chart diagram
231 mrObjMgr.AddObj( new XclExpChartObj( mrObjMgr, rxShape, pChildAnchor ) );
232 pCurrXclObj = NULL; // no metafile or whatsoever
234 else // metafile and OLE object
235 pCurrXclObj = new XclObjOle( mrObjMgr, *pObj );
237 else // just a metafile
238 pCurrXclObj = new XclObjAny( mrObjMgr );
240 else
241 pCurrXclObj = new XclObjAny( mrObjMgr );
243 else if( nObjType == OBJ_UNO )
245 #if EXC_EXP_OCX_CTRL
246 // no ActiveX controls in embedded drawings (chart shapes)
247 if( mbIsRootDff )
248 pCurrXclObj = CreateCtrlObj( rxShape, pChildAnchor );
249 #else
250 pCurrXclObj = CreateCtrlObj( rxShape, pChildAnchor );
251 #endif
252 if( !pCurrXclObj )
253 pCurrXclObj = new XclObjAny( mrObjMgr ); // just a metafile
255 else if( !ScDrawLayer::IsNoteCaption( pObj ) )
257 // #107540# ignore permanent note shapes
258 // #i12190# do not ignore callouts (do not filter by object type ID)
259 pCurrXclObj = new XclObjAny( mrObjMgr ); // just a metafile
262 if ( pCurrXclObj )
264 if ( !mrObjMgr.AddObj( pCurrXclObj ) )
265 { // maximum count reached, object got deleted
266 pCurrXclObj = NULL;
268 else
270 pCurrAppData->SetClientData( pTheClientData );
271 if ( nAdditionalText == 0 )
273 if ( pObj )
275 if ( !bInGroup )
277 /* Create a dummy anchor carrying the flags. Real
278 coordinates are calculated later in virtual call of
279 WriteData(EscherEx&,const Rectangle&). */
280 XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
281 pAnchor->SetFlags( *pObj );
282 pCurrAppData->SetClientAnchor( pAnchor );
284 const SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, pObj );
285 if( pTextObj && !lcl_IsFontwork( pTextObj ) && (pObj->GetObjIdentifier() != OBJ_CAPTION) )
287 const OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
288 if( pParaObj )
289 pCurrAppData->SetClientTextbox(
290 new XclEscherClientTextbox( GetRoot(), *pTextObj, pCurrXclObj ) );
293 else
295 if ( !bInGroup )
296 pCurrAppData->SetClientAnchor( mrObjMgr.CreateDffAnchor() );
299 else if ( nAdditionalText == 3 )
301 if ( pAdditionalText )
303 pAdditionalText->SetXclObj( pCurrXclObj );
304 pCurrAppData->SetClientTextbox( pAdditionalText );
309 if ( !pCurrXclObj )
310 pCurrAppData->SetDontWriteShape( TRUE );
311 return pCurrAppData;
315 void XclEscherEx::EndShape( UINT16 nShapeType, UINT32 nShapeID )
317 // own escher data created? -> never delete such objects
318 bool bOwnEscher = pCurrXclObj && pCurrXclObj->IsOwnEscher();
320 // post process the current object - not for objects with own escher data
321 if( pCurrXclObj && !bOwnEscher )
323 // escher data of last shape not written? -> delete it from object list
324 if( nShapeID == 0 )
326 XclObj* pLastObj = mrObjMgr.RemoveLastObj();
327 DBG_ASSERT( pLastObj == pCurrXclObj, "XclEscherEx::EndShape - wrong object" );
328 DELETEZ( pLastObj );
329 pCurrXclObj = 0;
332 if( pCurrXclObj )
334 // set shape type
335 if ( pCurrAppData->IsStackedGroup() )
336 pCurrXclObj->SetEscherShapeTypeGroup();
337 else
339 pCurrXclObj->SetEscherShapeType( nShapeType );
340 UpdateDffFragmentEnd();
345 // get next object from stack
346 DeleteCurrAppData();
347 pCurrAppData = static_cast< XclEscherHostAppData* >( aStack.Pop() );
348 pCurrXclObj = static_cast< XclObj* >( aStack.Pop() );
349 if( nAdditionalText == 3 )
350 nAdditionalText = 0;
354 EscherExHostAppData* XclEscherEx::EnterAdditionalTextGroup()
356 nAdditionalText = 1;
357 pAdditionalText = (XclEscherClientTextbox*) pCurrAppData->GetClientTextbox();
358 pCurrAppData->SetClientTextbox( NULL );
359 return pCurrAppData;
363 void XclEscherEx::EndDocument()
365 if( mbIsRootDff )
366 Flush( static_cast< XclEscherExGlobal& >( *mxGlobal ).GetPictureStream() );
368 // seek back DFF stream to prepare saving the MSODRAWING[GROUP] records
369 mpOutStrm->Seek( 0 );
372 #if EXC_EXP_OCX_CTRL
374 XclExpOcxControlObj* XclEscherEx::CreateCtrlObj( Reference< XShape > xShape, const Rectangle* pChildAnchor )
376 ::std::auto_ptr< XclExpOcxControlObj > xOcxCtrl;
378 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
379 if( xCtrlModel.is() )
381 // output stream
382 if( !mxCtlsStrm.Is() )
383 mxCtlsStrm = OpenStream( EXC_STREAM_CTLS );
384 if( mxCtlsStrm.Is() )
386 String aClassName;
387 sal_uInt32 nStrmStart = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() );
389 // writes from xCtrlModel into mxCtlsStrm, raw class name returned in aClassName
390 if( SvxMSConvertOCXControls::WriteOCXExcelKludgeStream( mxCtlsStrm, xCtrlModel, xShape->getSize(), aClassName ) )
392 sal_uInt32 nStrmSize = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() - nStrmStart );
393 // adjust the class name to "Forms.***.1"
394 aClassName.InsertAscii( "Forms.", 0 ).AppendAscii( ".1" );
395 xOcxCtrl.reset( new XclExpOcxControlObj( mrObjMgr, xShape, pChildAnchor, aClassName, nStrmStart, nStrmSize ) );
399 return xOcxCtrl.release();
402 #else
404 XclExpTbxControlObj* XclEscherEx::CreateCtrlObj( Reference< XShape > xShape, const Rectangle* pChildAnchor )
406 ::std::auto_ptr< XclExpTbxControlObj > xTbxCtrl( new XclExpTbxControlObj( mrObjMgr, xShape, pChildAnchor ) );
407 if( xTbxCtrl->GetObjType() == EXC_OBJTYPE_UNKNOWN )
408 xTbxCtrl.reset();
410 if( xTbxCtrl.get() )
412 // find attached macro
413 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
414 ConvertTbxMacro( *xTbxCtrl, xCtrlModel );
416 return xTbxCtrl.release();
419 void XclEscherEx::ConvertTbxMacro( XclExpTbxControlObj& rTbxCtrlObj, Reference< XControlModel > xCtrlModel )
421 SdrPage* pSdrPage = GetSdrPage( GetCurrScTab() );
422 if( xCtrlModel.is() && GetDocShell() && pSdrPage ) try
424 Reference< XFormsSupplier > xFormsSupplier( pSdrPage->getUnoPage(), UNO_QUERY_THROW );
425 Reference< XIndexAccess > xFormsIA( xFormsSupplier->getForms(), UNO_QUERY_THROW );
427 // 1) try to find the index of the processed control in the form
429 Reference< XIndexAccess > xFormIA; // needed in step 2) below
430 sal_Int32 nFoundIdx = -1;
432 // search all existing forms in the draw page
433 for( sal_Int32 nFormIdx = 0, nFormCount = xFormsIA->getCount();
434 (nFoundIdx < 0) && (nFormIdx < nFormCount); ++nFormIdx )
436 // get the XIndexAccess interface of the form with index nFormIdx
437 if( xFormIA.set( xFormsIA->getByIndex( nFormIdx ), UNO_QUERY ) )
439 // search all elements (controls) of the current form by index
440 for( sal_Int32 nCtrlIdx = 0, nCtrlCount = xFormIA->getCount();
441 (nFoundIdx < 0) && (nCtrlIdx < nCtrlCount); ++nCtrlIdx )
443 // compare implementation pointers of the control models
444 Reference< XControlModel > xCurrModel( xFormIA->getByIndex( nCtrlIdx ), UNO_QUERY );
445 if( xCtrlModel.get() == xCurrModel.get() )
446 nFoundIdx = nCtrlIdx;
451 // 2) try to find an attached macro
453 if( xFormIA.is() && (nFoundIdx >= 0) )
455 Reference< XEventAttacherManager > xEventMgr( xFormIA, UNO_QUERY_THROW );
456 // loop over all events attached to the found control
457 const Sequence< ScriptEventDescriptor > aEventSeq( xEventMgr->getScriptEvents( nFoundIdx ) );
458 bool bFound = false;
459 for( sal_Int32 nEventIdx = 0, nEventCount = aEventSeq.getLength();
460 !bFound && (nEventIdx < nEventCount); ++nEventIdx )
462 // try to set the event data at the Excel control object, returns true on success
463 bFound = rTbxCtrlObj.SetMacroLink( aEventSeq[ nEventIdx ] );
467 catch( Exception& )
472 #endif
474 void XclEscherEx::DeleteCurrAppData()
476 if ( pCurrAppData )
478 delete pCurrAppData->GetClientAnchor();
479 // delete pCurrAppData->GetClientData();
480 delete pCurrAppData->GetClientTextbox();
481 delete pCurrAppData;
485 // ============================================================================
487 // --- class XclEscherClientData -------------------------------------
489 void XclEscherClientData::WriteData( EscherEx& rEx ) const
490 { // actual data is in the following OBJ record
491 rEx.AddAtom( 0, ESCHER_ClientData );
495 // --- class XclEscherClientTextbox -------------------------------------
497 XclEscherClientTextbox::XclEscherClientTextbox( const XclExpRoot& rRoot,
498 const SdrTextObj& rObj, XclObj* pObj )
500 XclExpRoot( rRoot ),
501 rTextObj( rObj ),
502 pXclObj( pObj )
507 void XclEscherClientTextbox::WriteData( EscherEx& /*rEx*/ ) const
509 pXclObj->SetText( GetRoot(), rTextObj );