summaryrefslogtreecommitdiff
path: root/sc/source/filter/xcl97/xcl97esc.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/xcl97/xcl97esc.cxx')
-rw-r--r--sc/source/filter/xcl97/xcl97esc.cxx512
1 files changed, 512 insertions, 0 deletions
diff --git a/sc/source/filter/xcl97/xcl97esc.cxx b/sc/source/filter/xcl97/xcl97esc.cxx
new file mode 100644
index 000000000000..a7c6dee67dc5
--- /dev/null
+++ b/sc/source/filter/xcl97/xcl97esc.cxx
@@ -0,0 +1,512 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/embed/XClassifiedObject.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+
+#include <svx/svdpage.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/fmglob.hxx>
+#include <filter/msfilter/msocximex.hxx>
+#include <vcl/outdev.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <tools/debug.hxx>
+#include <svx/sdasitm.hxx>
+
+#include <sot/exchange.hxx>
+#include "xeescher.hxx"
+
+#include "global.hxx"
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "xcl97rec.hxx"
+#include "xehelper.hxx"
+#include "xechart.hxx"
+#include "xcl97esc.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::embed::XClassifiedObject;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::awt::XControlModel;
+using ::com::sun::star::form::XFormsSupplier;
+using ::com::sun::star::script::ScriptEventDescriptor;
+using ::com::sun::star::script::XEventAttacherManager;
+
+// ============================================================================
+
+XclEscherExGlobal::XclEscherExGlobal( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+SvStream* XclEscherExGlobal::ImplQueryPictureStream()
+{
+ mxPicTempFile.reset( new ::utl::TempFile );
+ if( mxPicTempFile->IsValid() )
+ {
+ mxPicTempFile->EnableKillingFile();
+ mxPicStrm.reset( ::utl::UcbStreamHelper::CreateStream( mxPicTempFile->GetURL(), STREAM_STD_READWRITE ) );
+ mxPicStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+ }
+ return mxPicStrm.get();
+}
+
+// ============================================================================
+
+XclEscherEx::XclEscherEx( const XclExpRoot& rRoot, XclExpObjectManager& rObjMgr, SvStream& rStrm, const XclEscherEx* pParent ) :
+ EscherEx( pParent ? pParent->mxGlobal : EscherExGlobalRef( new XclEscherExGlobal( rRoot ) ), rStrm ),
+ XclExpRoot( rRoot ),
+ mrObjMgr( rObjMgr ),
+ pCurrXclObj( NULL ),
+ pCurrAppData( NULL ),
+ pTheClientData( new XclEscherClientData ),
+ pAdditionalText( NULL ),
+ nAdditionalText( 0 ),
+ mnNextKey( 0 ),
+ mbIsRootDff( pParent == 0 )
+{
+ InsertPersistOffset( mnNextKey, 0 );
+}
+
+
+XclEscherEx::~XclEscherEx()
+{
+ DBG_ASSERT( !aStack.Count(), "~XclEscherEx: stack not empty" );
+ DeleteCurrAppData();
+ delete pTheClientData;
+}
+
+
+sal_uInt32 XclEscherEx::InitNextDffFragment()
+{
+ /* Current value of mnNextKey will be used by caller to refer to the
+ starting point of the DFF fragment. The key exists already in the
+ PersistTable (has been inserted by c'tor of previous call of
+ InitNextDffFragment(), has been updated by UpdateDffFragmentEnd(). */
+ sal_uInt32 nPersistKey = mnNextKey;
+
+ /* Prepare the next key that is used by caller as end point of the DFF
+ fragment. Will be updated by caller when writing to the DFF stream,
+ using the UpdateDffFragmentEnd() function. This is needed to find DFF
+ data written by the SVX base class implementation without interaction,
+ e.g. the solver container that will be written after the last shape. */
+ ++mnNextKey;
+ InsertPersistOffset( mnNextKey, mpOutStrm->Tell() );
+
+ return nPersistKey;
+}
+
+void XclEscherEx::UpdateDffFragmentEnd()
+{
+ // update existing fragment key with new stream position
+ ReplacePersistOffset( mnNextKey, mpOutStrm->Tell() );
+}
+
+sal_uInt32 XclEscherEx::GetDffFragmentPos( sal_uInt32 nFragmentKey )
+{
+ /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
+ is non-const due to tools/List usage. */
+ return GetPersistOffset( nFragmentKey );
+}
+
+sal_uInt32 XclEscherEx::GetDffFragmentSize( sal_uInt32 nFragmentKey )
+{
+ /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
+ is non-const due to tools/List usage. */
+ return GetDffFragmentPos( nFragmentKey + 1 ) - GetDffFragmentPos( nFragmentKey );
+}
+
+bool XclEscherEx::HasPendingDffData()
+{
+ /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
+ is non-const due to tools/List usage. */
+ return GetDffFragmentPos( mnNextKey ) < GetStreamPos();
+}
+
+XclExpDffAnchorBase* XclEscherEx::CreateDffAnchor( const SdrObject& rSdrObj ) const
+{
+ // the object manager creates the correct anchor type according to context
+ XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
+ // pass the drawing object, that will calculate the anchor position
+ pAnchor->SetSdrObject( rSdrObj );
+ return pAnchor;
+}
+
+namespace {
+
+bool lcl_IsFontwork( const SdrObject* pObj )
+{
+ bool bIsFontwork = false;
+ if( pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE )
+ {
+ const OUString aTextPath = CREATE_OUSTRING( "TextPath" );
+ SdrCustomShapeGeometryItem& rGeometryItem = (SdrCustomShapeGeometryItem&)
+ pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ if( Any* pAny = rGeometryItem.GetPropertyValueByName( aTextPath, aTextPath ) )
+ *pAny >>= bIsFontwork;
+ }
+ return bIsFontwork;
+}
+
+} // namespace
+
+EscherExHostAppData* XclEscherEx::StartShape( const Reference< XShape >& rxShape, const Rectangle* pChildAnchor )
+{
+ if ( nAdditionalText )
+ nAdditionalText++;
+ BOOL bInGroup = ( pCurrXclObj != NULL );
+ if ( bInGroup )
+ { // stacked recursive group object
+ if ( !pCurrAppData->IsStackedGroup() )
+ { //! UpdateDffFragmentEnd only once
+ pCurrAppData->SetStackedGroup( TRUE );
+ UpdateDffFragmentEnd();
+ }
+ }
+ aStack.Push( pCurrXclObj );
+ aStack.Push( pCurrAppData );
+ pCurrAppData = new XclEscherHostAppData;
+ SdrObject* pObj = GetSdrObjectFromXShape( rxShape );
+ if ( !pObj )
+ pCurrXclObj = new XclObjAny( mrObjMgr ); // just what is it?!?
+ else
+ {
+ pCurrXclObj = NULL;
+ sal_uInt16 nObjType = pObj->GetObjIdentifier();
+
+ if( nObjType == OBJ_OLE2 )
+ {
+ // no OLE objects in embedded drawings (chart shapes)
+ if( mbIsRootDff )
+ {
+ //! not-const because GetObjRef may load the OLE object
+ Reference < XClassifiedObject > xObj( ((SdrOle2Obj*)pObj)->GetObjRef(), UNO_QUERY );
+ if ( xObj.is() )
+ {
+ SvGlobalName aObjClsId( xObj->getClassID() );
+ if ( SotExchange::IsChart( aObjClsId ) )
+ { // yes, it's a chart diagram
+ mrObjMgr.AddObj( new XclExpChartObj( mrObjMgr, rxShape, pChildAnchor ) );
+ pCurrXclObj = NULL; // no metafile or whatsoever
+ }
+ else // metafile and OLE object
+ pCurrXclObj = new XclObjOle( mrObjMgr, *pObj );
+ }
+ else // just a metafile
+ pCurrXclObj = new XclObjAny( mrObjMgr );
+ }
+ else
+ pCurrXclObj = new XclObjAny( mrObjMgr );
+ }
+ else if( nObjType == OBJ_UNO )
+ {
+#if EXC_EXP_OCX_CTRL
+ // no ActiveX controls in embedded drawings (chart shapes)
+ if( mbIsRootDff )
+ pCurrXclObj = CreateCtrlObj( rxShape, pChildAnchor );
+#else
+ pCurrXclObj = CreateCtrlObj( rxShape, pChildAnchor );
+#endif
+ if( !pCurrXclObj )
+ pCurrXclObj = new XclObjAny( mrObjMgr ); // just a metafile
+ }
+ else if( !ScDrawLayer::IsNoteCaption( pObj ) )
+ {
+ // #107540# ignore permanent note shapes
+ // #i12190# do not ignore callouts (do not filter by object type ID)
+ pCurrXclObj = new XclObjAny( mrObjMgr ); // just a metafile
+ }
+ }
+ if ( pCurrXclObj )
+ {
+ if ( !mrObjMgr.AddObj( pCurrXclObj ) )
+ { // maximum count reached, object got deleted
+ pCurrXclObj = NULL;
+ }
+ else
+ {
+ pCurrAppData->SetClientData( pTheClientData );
+ if ( nAdditionalText == 0 )
+ {
+ if ( pObj )
+ {
+ if ( !bInGroup )
+ {
+ /* Create a dummy anchor carrying the flags. Real
+ coordinates are calculated later in virtual call of
+ WriteData(EscherEx&,const Rectangle&). */
+ XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
+ pAnchor->SetFlags( *pObj );
+ pCurrAppData->SetClientAnchor( pAnchor );
+ }
+ const SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, pObj );
+ if( pTextObj && !lcl_IsFontwork( pTextObj ) && (pObj->GetObjIdentifier() != OBJ_CAPTION) )
+ {
+ const OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
+ if( pParaObj )
+ pCurrAppData->SetClientTextbox(
+ new XclEscherClientTextbox( GetRoot(), *pTextObj, pCurrXclObj ) );
+ }
+ }
+ else
+ {
+ if ( !bInGroup )
+ pCurrAppData->SetClientAnchor( mrObjMgr.CreateDffAnchor() );
+ }
+ }
+ else if ( nAdditionalText == 3 )
+ {
+ if ( pAdditionalText )
+ {
+ pAdditionalText->SetXclObj( pCurrXclObj );
+ pCurrAppData->SetClientTextbox( pAdditionalText );
+ }
+ }
+ }
+ }
+ if ( !pCurrXclObj )
+ pCurrAppData->SetDontWriteShape( TRUE );
+ return pCurrAppData;
+}
+
+
+void XclEscherEx::EndShape( UINT16 nShapeType, UINT32 nShapeID )
+{
+ // own escher data created? -> never delete such objects
+ bool bOwnEscher = pCurrXclObj && pCurrXclObj->IsOwnEscher();
+
+ // post process the current object - not for objects with own escher data
+ if( pCurrXclObj && !bOwnEscher )
+ {
+ // escher data of last shape not written? -> delete it from object list
+ if( nShapeID == 0 )
+ {
+ XclObj* pLastObj = mrObjMgr.RemoveLastObj();
+ DBG_ASSERT( pLastObj == pCurrXclObj, "XclEscherEx::EndShape - wrong object" );
+ DELETEZ( pLastObj );
+ pCurrXclObj = 0;
+ }
+
+ if( pCurrXclObj )
+ {
+ // set shape type
+ if ( pCurrAppData->IsStackedGroup() )
+ pCurrXclObj->SetEscherShapeTypeGroup();
+ else
+ {
+ pCurrXclObj->SetEscherShapeType( nShapeType );
+ UpdateDffFragmentEnd();
+ }
+ }
+ }
+
+ // get next object from stack
+ DeleteCurrAppData();
+ pCurrAppData = static_cast< XclEscherHostAppData* >( aStack.Pop() );
+ pCurrXclObj = static_cast< XclObj* >( aStack.Pop() );
+ if( nAdditionalText == 3 )
+ nAdditionalText = 0;
+}
+
+
+EscherExHostAppData* XclEscherEx::EnterAdditionalTextGroup()
+{
+ nAdditionalText = 1;
+ pAdditionalText = (XclEscherClientTextbox*) pCurrAppData->GetClientTextbox();
+ pCurrAppData->SetClientTextbox( NULL );
+ return pCurrAppData;
+}
+
+
+void XclEscherEx::EndDocument()
+{
+ if( mbIsRootDff )
+ Flush( static_cast< XclEscherExGlobal& >( *mxGlobal ).GetPictureStream() );
+
+ // seek back DFF stream to prepare saving the MSODRAWING[GROUP] records
+ mpOutStrm->Seek( 0 );
+}
+
+#if EXC_EXP_OCX_CTRL
+
+XclExpOcxControlObj* XclEscherEx::CreateCtrlObj( Reference< XShape > xShape, const Rectangle* pChildAnchor )
+{
+ ::std::auto_ptr< XclExpOcxControlObj > xOcxCtrl;
+
+ Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
+ if( xCtrlModel.is() )
+ {
+ // output stream
+ if( !mxCtlsStrm.Is() )
+ mxCtlsStrm = OpenStream( EXC_STREAM_CTLS );
+ if( mxCtlsStrm.Is() )
+ {
+ String aClassName;
+ sal_uInt32 nStrmStart = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() );
+
+ // writes from xCtrlModel into mxCtlsStrm, raw class name returned in aClassName
+ if( SvxMSConvertOCXControls::WriteOCXExcelKludgeStream( mxCtlsStrm, xCtrlModel, xShape->getSize(), aClassName ) )
+ {
+ sal_uInt32 nStrmSize = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() - nStrmStart );
+ // adjust the class name to "Forms.***.1"
+ aClassName.InsertAscii( "Forms.", 0 ).AppendAscii( ".1" );
+ xOcxCtrl.reset( new XclExpOcxControlObj( mrObjMgr, xShape, pChildAnchor, aClassName, nStrmStart, nStrmSize ) );
+ }
+ }
+ }
+ return xOcxCtrl.release();
+}
+
+#else
+
+XclExpTbxControlObj* XclEscherEx::CreateCtrlObj( Reference< XShape > xShape, const Rectangle* pChildAnchor )
+{
+ ::std::auto_ptr< XclExpTbxControlObj > xTbxCtrl( new XclExpTbxControlObj( mrObjMgr, xShape, pChildAnchor ) );
+ if( xTbxCtrl->GetObjType() == EXC_OBJTYPE_UNKNOWN )
+ xTbxCtrl.reset();
+
+ if( xTbxCtrl.get() )
+ {
+ // find attached macro
+ Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
+ ConvertTbxMacro( *xTbxCtrl, xCtrlModel );
+ }
+ return xTbxCtrl.release();
+}
+
+void XclEscherEx::ConvertTbxMacro( XclExpTbxControlObj& rTbxCtrlObj, Reference< XControlModel > xCtrlModel )
+{
+ SdrPage* pSdrPage = GetSdrPage( GetCurrScTab() );
+ if( xCtrlModel.is() && GetDocShell() && pSdrPage ) try
+ {
+ Reference< XFormsSupplier > xFormsSupplier( pSdrPage->getUnoPage(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xFormsIA( xFormsSupplier->getForms(), UNO_QUERY_THROW );
+
+ // 1) try to find the index of the processed control in the form
+
+ Reference< XIndexAccess > xFormIA; // needed in step 2) below
+ sal_Int32 nFoundIdx = -1;
+
+ // search all existing forms in the draw page
+ for( sal_Int32 nFormIdx = 0, nFormCount = xFormsIA->getCount();
+ (nFoundIdx < 0) && (nFormIdx < nFormCount); ++nFormIdx )
+ {
+ // get the XIndexAccess interface of the form with index nFormIdx
+ if( xFormIA.set( xFormsIA->getByIndex( nFormIdx ), UNO_QUERY ) )
+ {
+ // search all elements (controls) of the current form by index
+ for( sal_Int32 nCtrlIdx = 0, nCtrlCount = xFormIA->getCount();
+ (nFoundIdx < 0) && (nCtrlIdx < nCtrlCount); ++nCtrlIdx )
+ {
+ // compare implementation pointers of the control models
+ Reference< XControlModel > xCurrModel( xFormIA->getByIndex( nCtrlIdx ), UNO_QUERY );
+ if( xCtrlModel.get() == xCurrModel.get() )
+ nFoundIdx = nCtrlIdx;
+ }
+ }
+ }
+
+ // 2) try to find an attached macro
+
+ if( xFormIA.is() && (nFoundIdx >= 0) )
+ {
+ Reference< XEventAttacherManager > xEventMgr( xFormIA, UNO_QUERY_THROW );
+ // loop over all events attached to the found control
+ const Sequence< ScriptEventDescriptor > aEventSeq( xEventMgr->getScriptEvents( nFoundIdx ) );
+ bool bFound = false;
+ for( sal_Int32 nEventIdx = 0, nEventCount = aEventSeq.getLength();
+ !bFound && (nEventIdx < nEventCount); ++nEventIdx )
+ {
+ // try to set the event data at the Excel control object, returns true on success
+ bFound = rTbxCtrlObj.SetMacroLink( aEventSeq[ nEventIdx ] );
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+#endif
+
+void XclEscherEx::DeleteCurrAppData()
+{
+ if ( pCurrAppData )
+ {
+ delete pCurrAppData->GetClientAnchor();
+// delete pCurrAppData->GetClientData();
+ delete pCurrAppData->GetClientTextbox();
+ delete pCurrAppData;
+ }
+}
+
+// ============================================================================
+
+// --- class XclEscherClientData -------------------------------------
+
+void XclEscherClientData::WriteData( EscherEx& rEx ) const
+{ // actual data is in the following OBJ record
+ rEx.AddAtom( 0, ESCHER_ClientData );
+}
+
+
+// --- class XclEscherClientTextbox -------------------------------------
+
+XclEscherClientTextbox::XclEscherClientTextbox( const XclExpRoot& rRoot,
+ const SdrTextObj& rObj, XclObj* pObj )
+ :
+ XclExpRoot( rRoot ),
+ rTextObj( rObj ),
+ pXclObj( pObj )
+{
+}
+
+
+void XclEscherClientTextbox::WriteData( EscherEx& /*rEx*/ ) const
+{
+ pXclObj->SetText( GetRoot(), rTextObj );
+}
+
+