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"
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
) :
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
),
103 pCurrAppData( NULL
),
104 pTheClientData( new XclEscherClientData
),
105 pAdditionalText( NULL
),
106 nAdditionalText( 0 ),
108 mbIsRootDff( pParent
== 0 )
110 InsertPersistOffset( mnNextKey
, 0 );
114 XclEscherEx::~XclEscherEx()
116 DBG_ASSERT( !aStack
.Count(), "~XclEscherEx: stack not empty" );
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. */
136 InsertPersistOffset( mnNextKey
, mpOutStrm
->Tell() );
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
);
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
;
195 EscherExHostAppData
* XclEscherEx::StartShape( const Reference
< XShape
>& rxShape
, const Rectangle
* pChildAnchor
)
197 if ( nAdditionalText
)
199 BOOL bInGroup
= ( pCurrXclObj
!= NULL
);
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
);
213 pCurrXclObj
= new XclObjAny( mrObjMgr
); // just what is it?!?
217 sal_uInt16 nObjType
= pObj
->GetObjIdentifier();
219 if( nObjType
== OBJ_OLE2
)
221 // no OLE objects in embedded drawings (chart shapes)
224 //! not-const because GetObjRef may load the OLE object
225 Reference
< XClassifiedObject
> xObj( ((SdrOle2Obj
*)pObj
)->GetObjRef(), UNO_QUERY
);
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
);
241 pCurrXclObj
= new XclObjAny( mrObjMgr
);
243 else if( nObjType
== OBJ_UNO
)
246 // no ActiveX controls in embedded drawings (chart shapes)
248 pCurrXclObj
= CreateCtrlObj( rxShape
, pChildAnchor
);
250 pCurrXclObj
= CreateCtrlObj( rxShape
, pChildAnchor
);
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
264 if ( !mrObjMgr
.AddObj( pCurrXclObj
) )
265 { // maximum count reached, object got deleted
270 pCurrAppData
->SetClientData( pTheClientData
);
271 if ( nAdditionalText
== 0 )
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();
289 pCurrAppData
->SetClientTextbox(
290 new XclEscherClientTextbox( GetRoot(), *pTextObj
, pCurrXclObj
) );
296 pCurrAppData
->SetClientAnchor( mrObjMgr
.CreateDffAnchor() );
299 else if ( nAdditionalText
== 3 )
301 if ( pAdditionalText
)
303 pAdditionalText
->SetXclObj( pCurrXclObj
);
304 pCurrAppData
->SetClientTextbox( pAdditionalText
);
310 pCurrAppData
->SetDontWriteShape( TRUE
);
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
326 XclObj
* pLastObj
= mrObjMgr
.RemoveLastObj();
327 DBG_ASSERT( pLastObj
== pCurrXclObj
, "XclEscherEx::EndShape - wrong object" );
335 if ( pCurrAppData
->IsStackedGroup() )
336 pCurrXclObj
->SetEscherShapeTypeGroup();
339 pCurrXclObj
->SetEscherShapeType( nShapeType
);
340 UpdateDffFragmentEnd();
345 // get next object from stack
347 pCurrAppData
= static_cast< XclEscherHostAppData
* >( aStack
.Pop() );
348 pCurrXclObj
= static_cast< XclObj
* >( aStack
.Pop() );
349 if( nAdditionalText
== 3 )
354 EscherExHostAppData
* XclEscherEx::EnterAdditionalTextGroup()
357 pAdditionalText
= (XclEscherClientTextbox
*) pCurrAppData
->GetClientTextbox();
358 pCurrAppData
->SetClientTextbox( NULL
);
363 void XclEscherEx::EndDocument()
366 Flush( static_cast< XclEscherExGlobal
& >( *mxGlobal
).GetPictureStream() );
368 // seek back DFF stream to prepare saving the MSODRAWING[GROUP] records
369 mpOutStrm
->Seek( 0 );
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() )
382 if( !mxCtlsStrm
.Is() )
383 mxCtlsStrm
= OpenStream( EXC_STREAM_CTLS
);
384 if( mxCtlsStrm
.Is() )
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();
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
)
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
) );
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
] );
474 void XclEscherEx::DeleteCurrAppData()
478 delete pCurrAppData
->GetClientAnchor();
479 // delete pCurrAppData->GetClientData();
480 delete pCurrAppData
->GetClientTextbox();
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
)
507 void XclEscherClientTextbox::WriteData( EscherEx
& /*rEx*/ ) const
509 pXclObj
->SetText( GetRoot(), rTextObj
);