1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xcl97esc.cxx,v $
10 * $Revision: 1.26.128.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include <com/sun/star/awt/XControlModel.hpp>
35 #include <com/sun/star/embed/XClassifiedObject.hpp>
36 #include <com/sun/star/form/XFormsSupplier.hpp>
37 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
38 #include <com/sun/star/script/XEventAttacherManager.hpp>
40 #include <svx/svdpage.hxx>
41 #include <svx/outlobj.hxx>
42 #include <svx/svdotext.hxx>
43 #include <svx/svdobj.hxx>
44 #include <svx/svdoole2.hxx>
45 #include <svx/unoapi.hxx>
46 #include <svx/fmglob.hxx>
47 #include <svx/msocximex.hxx>
48 #include <vcl/outdev.hxx>
49 #include <unotools/tempfile.hxx>
50 #include <unotools/ucbstreamhelper.hxx>
51 #include <tools/debug.hxx>
52 #include <svx/sdasitm.hxx>
54 #include <sot/exchange.hxx>
55 #include "xeescher.hxx"
58 #include "document.hxx"
59 #include "drwlayer.hxx"
60 #include "xecontent.hxx"
61 #include <svx/flditem.hxx>
62 #include "userdat.hxx"
63 #include "xcl97rec.hxx"
64 #include "xehelper.hxx"
65 #include "xechart.hxx"
66 #include "xcl97esc.hxx"
68 using ::com::sun::star::uno::Reference
;
69 using ::com::sun::star::uno::Sequence
;
70 using ::com::sun::star::uno::Exception
;
71 using ::com::sun::star::uno::UNO_QUERY
;
72 using ::com::sun::star::uno::UNO_QUERY_THROW
;
73 using ::com::sun::star::container::XIndexAccess
;
74 using ::com::sun::star::embed::XClassifiedObject
;
75 using ::com::sun::star::drawing::XShape
;
76 using ::com::sun::star::awt::XControlModel
;
77 using ::com::sun::star::form::XFormsSupplier
;
78 using ::com::sun::star::script::ScriptEventDescriptor
;
79 using ::com::sun::star::script::XEventAttacherManager
;
81 // --- class XclEscherEx ---------------------------------------------
83 XclEscherEx::XclEscherEx( const XclExpRoot
& rRoot
, SvStream
& rStrm
, UINT32 nDrawings
)
85 EscherEx( rStrm
, nDrawings
),
91 pTheClientData( new XclEscherClientData
),
92 pAdditionalText( NULL
),
95 aOffsetMap
.Insert( (void*) 0, LIST_APPEND
); // start of stream
96 // Xcl forgets OLE objects completely if the Escher object is not EMF and
97 // the corresponding OLE application is opened and nothing is changed.
102 XclEscherEx::~XclEscherEx()
104 DBG_ASSERT( !aStack
.Count(), "~XclEscherEx: stack not empty" );
106 delete pTheClientData
;
116 SvStream
* XclEscherEx::QueryPicStream()
122 pPicTempFile
= new utl::TempFile
;
123 if ( pPicTempFile
->IsValid() )
124 pPicTempFile
->EnableKillingFile();
133 pPicStrm
= utl::UcbStreamHelper::CreateStream( pPicTempFile
->GetURL(), STREAM_STD_READWRITE
);
134 pPicStrm
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
141 void XclEscherEx::InsertAtCurrentPos( UINT32 nBytes
, BOOL bCont
)
143 ULONG nPos
= GetStreamPos();
144 ULONG nCnt
= aOffsetMap
.Count();
146 for ( j
=0, nOff
= (ULONG
) aOffsetMap
.First(); j
<nCnt
;
147 j
++, nOff
= (ULONG
) aOffsetMap
.Next() )
150 aOffsetMap
.Replace( (void*) (nOff
+ nBytes
) );
152 EscherEx::InsertAtCurrentPos( nBytes
, bCont
);
156 ULONG
XclEscherEx::AddCurrentOffsetToMap()
158 aOffsetMap
.Insert( (void*) GetStreamPos(), LIST_APPEND
);
159 return aOffsetMap
.Count() - 1;
163 void XclEscherEx::ReplaceCurrentOffsetInMap( ULONG nPos
)
165 aOffsetMap
.Replace( (void*) GetStreamPos(), nPos
);
168 sal_Bool
ImplXclEscherExIsFontwork( const SdrObject
* pObj
)
170 const rtl::OUString
sTextPath( RTL_CONSTASCII_USTRINGPARAM ( "TextPath" ) );
172 sal_Bool bIsFontwork
= sal_False
;
173 if ( pObj
->GetObjIdentifier() == OBJ_CUSTOMSHAPE
)
175 SdrCustomShapeGeometryItem
& rGeometryItem
= (SdrCustomShapeGeometryItem
&)
176 pObj
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
178 com::sun::star::uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( sTextPath
, sTextPath
);
180 *pAny
>>= bIsFontwork
;
185 EscherExHostAppData
* XclEscherEx::StartShape( const com::sun::star::uno::Reference
<
186 com::sun::star::drawing::XShape
>& rShape
)
188 if ( nAdditionalText
)
190 BOOL bInGroup
= ( pCurrXclObj
!= NULL
);
192 { // stacked recursive group object
193 if ( !pCurrAppData
->IsStackedGroup() )
194 { //! UpdateStopPos only once
195 pCurrAppData
->SetStackedGroup( TRUE
);
196 pCurrXclObj
->UpdateStopPos();
199 aStack
.Push( pCurrXclObj
);
200 aStack
.Push( pCurrAppData
);
201 pCurrAppData
= new XclEscherHostAppData
;
202 SdrObject
* pObj
= GetSdrObjectFromXShape( rShape
);
204 pCurrXclObj
= new XclObjAny( GetRoot() ); // just what is it?!?
208 sal_uInt16 nObjType
= pObj
->GetObjIdentifier();
210 if( nObjType
== OBJ_OLE2
)
212 //! not-const because GetObjRef may load the OLE object
213 Reference
< XClassifiedObject
> xObj( ((SdrOle2Obj
*)pObj
)->GetObjRef(), UNO_QUERY
);
216 SvGlobalName
aObjClsId( xObj
->getClassID() );
217 if ( SotExchange::IsChart( aObjClsId
) )
218 { // yes, it's a chart diagram
219 GetOldRoot().pObjRecs
->Add( new XclExpChartObj( GetRoot(), rShape
) );
220 pCurrXclObj
= NULL
; // no metafile or whatsoever
222 else // metafile and OLE object
223 pCurrXclObj
= new XclObjOle( GetRoot(), *pObj
);
225 else // just a metafile
226 pCurrXclObj
= new XclObjAny( GetRoot() );
228 else if( nObjType
== OBJ_UNO
)
230 pCurrXclObj
= CreateCtrlObj( rShape
);
232 pCurrXclObj
= new XclObjAny( GetRoot() ); // just a metafile
234 else if( !ScDrawLayer::IsNoteCaption( pObj
) )
236 // #107540# ignore permanent note shapes
237 // #i12190# do not ignore callouts (do not filter by object type ID)
238 pCurrXclObj
= ShapeInteractionHelper::CreateShapeObj( GetRoot(), rShape
);
239 ShapeInteractionHelper::PopulateShapeInteractionInfo( GetRoot(), rShape
, *pCurrAppData
);
244 if ( !GetOldRoot().pObjRecs
->Add( pCurrXclObj
) )
245 { // maximum count reached, object got deleted
250 pCurrAppData
->SetClientData( pTheClientData
);
251 if ( nAdditionalText
== 0 )
257 /* Create a dummy anchor carrying the flags. Real coordinates are
258 calculated later in WriteData(EscherEx&,const Rectangle&). */
259 XclExpDffAnchor
* pAnchor
= new XclExpDffAnchor( GetRoot() );
260 pAnchor
->SetFlags( *pObj
);
261 pCurrAppData
->SetClientAnchor( pAnchor
);
263 const SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, pObj
);
264 if ( pTextObj
&& !ImplXclEscherExIsFontwork( pTextObj
) && ( pObj
->GetObjIdentifier() != OBJ_CAPTION
) )
266 const OutlinerParaObject
* pParaObj
= pTextObj
->GetOutlinerParaObject();
268 pCurrAppData
->SetClientTextbox(
269 new XclEscherClientTextbox( GetRoot(), *pTextObj
, pCurrXclObj
) );
275 pCurrAppData
->SetClientAnchor( new XclExpDffAnchor( GetRoot() ) );
278 else if ( nAdditionalText
== 3 )
280 if ( pAdditionalText
)
282 pAdditionalText
->SetXclObj( pCurrXclObj
);
283 pCurrAppData
->SetClientTextbox( pAdditionalText
);
289 pCurrAppData
->SetDontWriteShape( TRUE
);
294 void XclEscherEx::EndShape( UINT16 nShapeType
, UINT32 nShapeID
)
296 // own escher data created? -> never delete such objects
297 bool bOwnEscher
= pCurrXclObj
&& pCurrXclObj
->IsOwnEscher();
299 // post process the current object - not for objects with own escher data
300 if( pCurrXclObj
&& !bOwnEscher
)
302 // escher data of last shape not written? -> delete it from object list
305 XclObj
* pLastObj
= static_cast< XclObj
* >( GetOldRoot().pObjRecs
->Last() );
306 DBG_ASSERT( pLastObj
== pCurrXclObj
, "XclEscherEx::EndShape - wrong object" );
307 if ( pLastObj
== pCurrXclObj
)
309 GetOldRoot().pObjRecs
->Remove();
310 DELETEZ( pCurrXclObj
);
317 if ( pCurrAppData
->IsStackedGroup() )
318 pCurrXclObj
->SetEscherShapeTypeGroup();
321 pCurrXclObj
->SetEscherShapeType( nShapeType
);
322 pCurrXclObj
->UpdateStopPos();
327 // get next object from stack
329 pCurrAppData
= static_cast< XclEscherHostAppData
* >( aStack
.Pop() );
330 pCurrXclObj
= static_cast< XclObj
* >( aStack
.Pop() );
331 if( nAdditionalText
== 3 )
336 EscherExHostAppData
* XclEscherEx::EnterAdditionalTextGroup()
339 pAdditionalText
= (XclEscherClientTextbox
*) pCurrAppData
->GetClientTextbox();
340 pCurrAppData
->SetClientTextbox( NULL
);
345 void XclEscherEx::DeleteCurrAppData()
349 delete pCurrAppData
->GetClientAnchor();
350 // delete pCurrAppData->GetClientData();
351 delete pCurrAppData
->GetClientTextbox();
352 delete pCurrAppData
->GetInteractionInfo();
358 void XclEscherEx::EndDocument()
365 XclExpOcxControlObj
* XclEscherEx::CreateCtrlObj( Reference
< XShape
> xShape
)
367 ::std::auto_ptr
< XclExpOcxControlObj
> xOcxCtrl
;
369 Reference
< XControlModel
> xCtrlModel
= XclControlHelper::GetControlModel( xShape
);
370 if( xCtrlModel
.is() )
373 if( !mxCtlsStrm
.Is() )
374 mxCtlsStrm
= OpenStream( EXC_STREAM_CTLS
);
375 if( mxCtlsStrm
.Is() )
378 sal_uInt32 nStrmStart
= static_cast< sal_uInt32
>( mxCtlsStrm
->Tell() );
380 // writes from xCtrlModel into mxCtlsStrm, raw class name returned in aClassName
381 if( SvxMSConvertOCXControls::WriteOCXExcelKludgeStream( mxCtlsStrm
, xCtrlModel
, xShape
->getSize(), aClassName
) )
383 sal_uInt32 nStrmSize
= static_cast< sal_uInt32
>( mxCtlsStrm
->Tell() - nStrmStart
);
384 // adjust the class name to "Forms.***.1"
385 aClassName
.InsertAscii( "Forms.", 0 ).AppendAscii( ".1" );
386 xOcxCtrl
.reset( new XclExpOcxControlObj( GetRoot(), xShape
, aClassName
, nStrmStart
, nStrmSize
) );
390 return xOcxCtrl
.release();
395 XclExpTbxControlObj
* XclEscherEx::CreateCtrlObj( Reference
< XShape
> xShape
)
397 ::std::auto_ptr
< XclExpTbxControlObj
> xTbxCtrl( new XclExpTbxControlObj( GetRoot(), xShape
) );
398 if( xTbxCtrl
->GetObjType() == EXC_OBJTYPE_UNKNOWN
)
403 // find attached macro
404 Reference
< XControlModel
> xCtrlModel
= XclControlHelper::GetControlModel( xShape
);
405 ConvertTbxMacro( *xTbxCtrl
, xCtrlModel
);
407 return xTbxCtrl
.release();
410 void XclEscherEx::ConvertTbxMacro( XclExpTbxControlObj
& rTbxCtrlObj
, Reference
< XControlModel
> xCtrlModel
)
412 SdrPage
* pSdrPage
= GetSdrPage( GetCurrScTab() );
413 if( xCtrlModel
.is() && GetDocShell() && pSdrPage
) try
415 Reference
< XFormsSupplier
> xFormsSupplier( pSdrPage
->getUnoPage(), UNO_QUERY_THROW
);
416 Reference
< XIndexAccess
> xFormsIA( xFormsSupplier
->getForms(), UNO_QUERY_THROW
);
418 // 1) try to find the index of the processed control in the form
420 Reference
< XIndexAccess
> xFormIA
; // needed in step 2) below
421 sal_Int32 nFoundIdx
= -1;
423 // search all existing forms in the draw page
424 for( sal_Int32 nFormIdx
= 0, nFormCount
= xFormsIA
->getCount();
425 (nFoundIdx
< 0) && (nFormIdx
< nFormCount
); ++nFormIdx
)
427 // get the XIndexAccess interface of the form with index nFormIdx
428 if( xFormIA
.set( xFormsIA
->getByIndex( nFormIdx
), UNO_QUERY
) )
430 // search all elements (controls) of the current form by index
431 for( sal_Int32 nCtrlIdx
= 0, nCtrlCount
= xFormIA
->getCount();
432 (nFoundIdx
< 0) && (nCtrlIdx
< nCtrlCount
); ++nCtrlIdx
)
434 // compare implementation pointers of the control models
435 Reference
< XControlModel
> xCurrModel( xFormIA
->getByIndex( nCtrlIdx
), UNO_QUERY
);
436 if( xCtrlModel
.get() == xCurrModel
.get() )
437 nFoundIdx
= nCtrlIdx
;
442 // 2) try to find an attached macro
444 if( xFormIA
.is() && (nFoundIdx
>= 0) )
446 Reference
< XEventAttacherManager
> xEventMgr( xFormIA
, UNO_QUERY_THROW
);
447 // loop over all events attached to the found control
448 const Sequence
< ScriptEventDescriptor
> aEventSeq( xEventMgr
->getScriptEvents( nFoundIdx
) );
450 for( sal_Int32 nEventIdx
= 0, nEventCount
= aEventSeq
.getLength();
451 !bFound
&& (nEventIdx
< nEventCount
); ++nEventIdx
)
453 // try to set the event data at the Excel control object, returns true on success
454 bFound
= rTbxCtrlObj
.SetMacroLink( aEventSeq
[ nEventIdx
] );
465 // --- class XclEscher -----------------------------------------------
467 XclEscher::XclEscher( const XclExpRoot
& rRoot
, UINT32 nDrawings
) :
470 pTempFile
= new utl::TempFile
;
471 pTempFile
->EnableKillingFile();
472 pStrm
= utl::UcbStreamHelper::CreateStream( pTempFile
->GetURL(), STREAM_STD_READWRITE
);
473 pStrm
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
474 pEx
= new XclEscherEx( rRoot
, *pStrm
, nDrawings
);
478 XclEscher::~XclEscher()
486 void XclEscher::AddSdrPage()
488 if( SdrPage
* pPage
= GetSdrPage( GetCurrScTab() ) )
489 pEx
->AddSdrPage( *pPage
);
490 // #106213# the first dummy object may still be open
491 DBG_ASSERT( pEx
->GetGroupLevel() <= 1, "XclEscher::AddSdrPage - still groups open?" );
492 while( pEx
->GetGroupLevel() )
497 // Escher client anchor =======================================================
499 XclExpDffAnchor::XclExpDffAnchor( const XclExpRoot
& rRoot
, sal_uInt16 nFlags
) :
501 maAnchor( rRoot
.GetCurrScTab() ),
506 XclExpDffAnchor::XclExpDffAnchor( const XclExpRoot
& rRoot
, const SdrObject
& rSdrObj
) :
508 maAnchor( rRoot
.GetCurrScTab() )
511 maAnchor
.SetRect( GetDoc(), rSdrObj
.GetCurrentBoundRect(), MAP_100TH_MM
);
514 void XclExpDffAnchor::SetFlags( const SdrObject
& rSdrObj
)
516 // Special case "page anchor" (X==0,Y==1) -> lock pos and size.
517 const Point
& rPos
= rSdrObj
.GetAnchorPos();
518 mnFlags
= ((rPos
.X() == 0) && (rPos
.Y() == 1)) ? EXC_ESC_ANCHOR_LOCKED
: 0;
521 void XclExpDffAnchor::WriteData( EscherEx
& rEx
, const Rectangle
& rRect
)
523 // the rectangle is already in twips
524 maAnchor
.SetRect( GetDoc(), rRect
, MAP_TWIP
);
529 void XclExpDffAnchor::WriteData( EscherEx
& rEx
) const
531 rEx
.AddAtom( 18, ESCHER_ClientAnchor
);
532 rEx
.GetStream() << mnFlags
<< maAnchor
;
536 // ----------------------------------------------------------------------------
538 XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot
& rRoot
, const Rectangle
& rRect
) :
539 XclExpDffAnchor( rRoot
, EXC_ESC_ANCHOR_SIZELOCKED
)
541 maAnchor
.SetRect( GetDoc(), rRect
, MAP_100TH_MM
);
545 // ----------------------------------------------------------------------------
547 XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot
& rRoot
, const ScAddress
& rScPos
) :
548 XclExpDffAnchor( rRoot
, EXC_ESC_ANCHOR_POSLOCKED
)
550 GetAddressConverter().ConvertAddress( maAnchor
.maFirst
, rScPos
, true );
551 maAnchor
.maLast
.mnCol
= maAnchor
.maFirst
.mnCol
+ 1;
552 maAnchor
.maLast
.mnRow
= maAnchor
.maFirst
.mnRow
+ 1;
553 maAnchor
.mnLX
= maAnchor
.mnTY
= maAnchor
.mnRX
= maAnchor
.mnBY
= 0;
557 // ============================================================================
559 // --- class XclEscherClientData -------------------------------------
561 void XclEscherClientData::WriteData( EscherEx
& rEx
) const
562 { // actual data is in the following OBJ record
563 rEx
.AddAtom( 0, ESCHER_ClientData
);
567 // --- class XclEscherClientTextbox -------------------------------------
569 XclEscherClientTextbox::XclEscherClientTextbox( const XclExpRoot
& rRoot
,
570 const SdrTextObj
& rObj
, XclObj
* pObj
)
579 void XclEscherClientTextbox::WriteData( EscherEx
& /*rEx*/ ) const
581 pXclObj
->SetText( GetRoot(), rTextObj
);
585 ShapeInteractionHelper::CreateShapeObj(const XclExpRoot
& rRoot
, const Reference
< XShape
>& xShape
)
587 return new XclExpShapeObj( rRoot
, xShape
);
591 ShapeInteractionHelper::PopulateShapeInteractionInfo(const XclExpRoot
& rRoot
, const Reference
< XShape
>& xShape
, EscherExHostAppData
& rHostAppData
)
595 SvMemoryStream
* pMemStrm
= NULL
;
596 rtl::OUString sHyperLink
;
597 rtl::OUString sMacro
;
598 if ( ScMacroInfo
* pInfo
= ScDrawLayer::GetMacroInfo( ::GetSdrObjectFromXShape( xShape
) ) )
600 sHyperLink
= pInfo
->GetHlink();
601 sMacro
= pInfo
->GetMacro();
603 if ( sHyperLink
.getLength() > 0 )
605 pMemStrm
= new SvMemoryStream();
606 XclExpStream
tmpStream( *pMemStrm
, rRoot
);
607 ScAddress dummyAddress
;
608 SvxURLField aUrlField
;
609 aUrlField
.SetURL( sHyperLink
);
610 XclExpHyperlink
hExpHlink( rRoot
, aUrlField
, dummyAddress
);
611 hExpHlink
.WriteEmbeddedData( tmpStream
);
613 if ( ( sHyperLink
.getLength() > 0 ) || ( sMacro
.getLength() > 0 ) )
614 rHostAppData
.SetInteractionInfo( new InteractionInfo( pMemStrm
, true ) );