1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <memory>
21 #include <com/sun/star/awt/XControlModel.hpp>
22 #include <com/sun/star/embed/XClassifiedObject.hpp>
23 #include <com/sun/star/form/XFormsSupplier.hpp>
24 #include <com/sun/star/script/XEventAttacherManager.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26
27 #include <svx/svdpage.hxx>
28 #include <svx/svdotext.hxx>
29 #include <svx/svdobj.hxx>
30 #include <svx/svdoole2.hxx>
31 #include <svx/unoapi.hxx>
32 #include <unotools/tempfile.hxx>
33 #include <unotools/ucbstreamhelper.hxx>
34 #include <svx/sdasitm.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <sal/log.hxx>
37
38 #include <sot/exchange.hxx>
39 #include <sot/storage.hxx>
40 #include <xeescher.hxx>
41
42 #include <drwlayer.hxx>
43 #include <xecontent.hxx>
44 #include <editeng/flditem.hxx>
45 #include <userdat.hxx>
46 #include <xcl97rec.hxx>
47 #include <xcl97esc.hxx>
48 #include <unotools/streamwrap.hxx>
49 #include <oox/ole/olehelper.hxx>
50 #include <sfx2/objsh.hxx>
51
52 using ::com::sun::star::uno::Any;
53 using ::com::sun::star::uno::Exception;
54 using ::com::sun::star::uno::Reference;
55 using ::com::sun::star::uno::Sequence;
56 using ::com::sun::star::uno::UNO_QUERY;
57 using ::com::sun::star::uno::UNO_QUERY_THROW;
58 using ::com::sun::star::container::XIndexAccess;
59 using ::com::sun::star::embed::XClassifiedObject;
60 using ::com::sun::star::drawing::XShape;
61 using ::com::sun::star::awt::XControlModel;
62 using ::com::sun::star::beans::XPropertySet;
63 using ::com::sun::star::uno::Any;
64 using ::com::sun::star::form::XFormsSupplier;
65 using ::com::sun::star::io::XOutputStream;
66 using ::com::sun::star::script::ScriptEventDescriptor;
67 using ::com::sun::star::script::XEventAttacherManager;
68
XclEscherExGlobal(const XclExpRoot & rRoot)69 XclEscherExGlobal::XclEscherExGlobal( const XclExpRoot& rRoot ) :
70 XclExpRoot( rRoot )
71 {
72 SetBaseURI( GetMedium().GetBaseURL( true ) );
73 }
74
ImplQueryPictureStream()75 SvStream* XclEscherExGlobal::ImplQueryPictureStream()
76 {
77 mxPicTempFile.reset( new ::utl::TempFile );
78 if( mxPicTempFile->IsValid() )
79 {
80 mxPicTempFile->EnableKillingFile();
81 mxPicStrm = ::utl::UcbStreamHelper::CreateStream( mxPicTempFile->GetURL(), StreamMode::STD_READWRITE );
82 mxPicStrm->SetEndian( SvStreamEndian::LITTLE );
83 }
84 return mxPicStrm.get();
85 }
86
XclEscherEx(const XclExpRoot & rRoot,XclExpObjectManager & rObjMgr,SvStream & rStrm,const XclEscherEx * pParent)87 XclEscherEx::XclEscherEx( const XclExpRoot& rRoot, XclExpObjectManager& rObjMgr, SvStream& rStrm, const XclEscherEx* pParent ) :
88 EscherEx( pParent ? pParent->mxGlobal : std::shared_ptr<EscherExGlobal>( new XclEscherExGlobal( rRoot ) ), &rStrm ),
89 XclExpRoot( rRoot ),
90 mrObjMgr( rObjMgr ),
91 pCurrXclObj( nullptr ),
92 pTheClientData( new XclEscherClientData ),
93 pAdditionalText( nullptr ),
94 nAdditionalText( 0 ),
95 mnNextKey( 0 ),
96 mbIsRootDff( pParent == nullptr )
97 {
98 InsertPersistOffset( mnNextKey, 0 );
99 }
100
~XclEscherEx()101 XclEscherEx::~XclEscherEx()
102 {
103 OSL_ENSURE( aStack.empty(), "~XclEscherEx: stack not empty" );
104 DeleteCurrAppData();
105 pTheClientData.reset();
106 }
107
InitNextDffFragment()108 sal_uInt32 XclEscherEx::InitNextDffFragment()
109 {
110 /* Current value of mnNextKey will be used by caller to refer to the
111 starting point of the DFF fragment. The key exists already in the
112 PersistTable (has been inserted by c'tor of previous call of
113 InitNextDffFragment(), has been updated by UpdateDffFragmentEnd(). */
114 sal_uInt32 nPersistKey = mnNextKey;
115
116 /* Prepare the next key that is used by caller as end point of the DFF
117 fragment. Will be updated by caller when writing to the DFF stream,
118 using the UpdateDffFragmentEnd() function. This is needed to find DFF
119 data written by the SVX base class implementation without interaction,
120 e.g. the solver container that will be written after the last shape. */
121 ++mnNextKey;
122 InsertPersistOffset( mnNextKey, mpOutStrm->Tell() );
123
124 return nPersistKey;
125 }
126
UpdateDffFragmentEnd()127 void XclEscherEx::UpdateDffFragmentEnd()
128 {
129 // update existing fragment key with new stream position
130 ReplacePersistOffset( mnNextKey, mpOutStrm->Tell() );
131 }
132
GetDffFragmentPos(sal_uInt32 nFragmentKey)133 sal_uInt32 XclEscherEx::GetDffFragmentPos( sal_uInt32 nFragmentKey )
134 {
135 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
136 is non-const due to tools/List usage. */
137 return GetPersistOffset( nFragmentKey );
138 }
139
GetDffFragmentSize(sal_uInt32 nFragmentKey)140 sal_uInt32 XclEscherEx::GetDffFragmentSize( sal_uInt32 nFragmentKey )
141 {
142 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
143 is non-const due to tools/List usage. */
144 return GetDffFragmentPos( nFragmentKey + 1 ) - GetDffFragmentPos( nFragmentKey );
145 }
146
HasPendingDffData()147 bool XclEscherEx::HasPendingDffData()
148 {
149 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
150 is non-const due to tools/List usage. */
151 return GetDffFragmentPos( mnNextKey ) < GetStreamPos();
152 }
153
CreateDffAnchor(const SdrObject & rSdrObj) const154 XclExpDffAnchorBase* XclEscherEx::CreateDffAnchor( const SdrObject& rSdrObj ) const
155 {
156 // the object manager creates the correct anchor type according to context
157 XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
158 // pass the drawing object, that will calculate the anchor position
159 pAnchor->SetSdrObject( rSdrObj );
160 return pAnchor;
161 }
162
163 namespace {
164
lcl_IsFontwork(const SdrObject * pObj)165 bool lcl_IsFontwork( const SdrObject* pObj )
166 {
167 bool bIsFontwork = false;
168 if( pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE )
169 {
170 const OUString aTextPath = "TextPath";
171 const SdrCustomShapeGeometryItem& rGeometryItem =
172 pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
173 if( const Any* pAny = rGeometryItem.GetPropertyValueByName( aTextPath, aTextPath ) )
174 *pAny >>= bIsFontwork;
175 }
176 return bIsFontwork;
177 }
178
179 } // namespace
180
StartShape(const Reference<XShape> & rxShape,const tools::Rectangle * pChildAnchor)181 EscherExHostAppData* XclEscherEx::StartShape( const Reference< XShape >& rxShape, const tools::Rectangle* pChildAnchor )
182 {
183 if ( nAdditionalText )
184 nAdditionalText++;
185 bool bInGroup = ( pCurrXclObj != nullptr );
186 if ( bInGroup )
187 { // stacked recursive group object
188 if ( !pCurrAppData->IsStackedGroup() )
189 { //! UpdateDffFragmentEnd only once
190 pCurrAppData->SetStackedGroup( true );
191 UpdateDffFragmentEnd();
192 }
193 }
194 aStack.push( std::make_pair( pCurrXclObj, std::move(pCurrAppData) ) );
195 pCurrAppData.reset( new XclEscherHostAppData );
196 SdrObject* pObj = GetSdrObjectFromXShape( rxShape );
197 //added for exporting OCX control
198 sal_Int16 nMsCtlType = 0;
199 if ( !pObj )
200 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() ); // just what is it?!?
201 else
202 {
203 pCurrXclObj = nullptr;
204 sal_uInt16 nObjType = pObj->GetObjIdentifier();
205
206 if( nObjType == OBJ_OLE2 )
207 {
208 // no OLE objects in embedded drawings (chart shapes)
209 if( mbIsRootDff )
210 {
211 //! not-const because GetObjRef may load the OLE object
212 Reference < XClassifiedObject > xObj( static_cast<SdrOle2Obj*>(pObj)->GetObjRef(), UNO_QUERY );
213 if ( xObj.is() )
214 {
215 SvGlobalName aObjClsId( xObj->getClassID() );
216 if ( SotExchange::IsChart( aObjClsId ) )
217 { // yes, it's a chart diagram
218 mrObjMgr.AddObj( std::make_unique<XclExpChartObj>( mrObjMgr, rxShape, pChildAnchor, &GetDoc() ) );
219 pCurrXclObj = nullptr; // no metafile or whatsoever
220 }
221 else // metafile and OLE object
222 pCurrXclObj = new XclObjOle( mrObjMgr, *pObj );
223 }
224 else // just a metafile
225 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() );
226 }
227 else
228 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() );
229 }
230 else if( nObjType == OBJ_UNO )
231 {
232 //added for exporting OCX control
233 Reference< XPropertySet > xPropSet( rxShape, UNO_QUERY );
234 Any aAny;
235 try
236 {
237 aAny = xPropSet->getPropertyValue("ControlTypeinMSO");
238 aAny >>= nMsCtlType;
239 }
240 catch(const Exception&)
241 {
242 SAL_WARN("sc", "XclEscherEx::StartShape, this control can't get the property ControlTypeinMSO!");
243 }
244 if( nMsCtlType == 2 ) //OCX Form Control
245 pCurrXclObj = CreateOCXCtrlObj( rxShape, pChildAnchor ).release();
246 else //TBX Form Control
247 pCurrXclObj = CreateTBXCtrlObj( rxShape, pChildAnchor ).release();
248 if( !pCurrXclObj )
249 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() ); // just a metafile
250 }
251 else if( !ScDrawLayer::IsNoteCaption( pObj ) )
252 {
253 // ignore permanent note shapes
254 // #i12190# do not ignore callouts (do not filter by object type ID)
255 pCurrXclObj = ShapeInteractionHelper::CreateShapeObj( mrObjMgr, rxShape, &GetDoc() );
256 ShapeInteractionHelper::PopulateShapeInteractionInfo( mrObjMgr, rxShape, *pCurrAppData );
257 }
258 }
259 if ( pCurrXclObj )
260 {
261 if ( !mrObjMgr.AddObj( std::unique_ptr<XclObj>(pCurrXclObj) ) )
262 { // maximum count reached, object got deleted
263 pCurrXclObj = nullptr;
264 }
265 else
266 {
267 pCurrAppData->SetClientData( pTheClientData.get() );
268 if ( nAdditionalText == 0 )
269 {
270 if ( pObj )
271 {
272 if ( !bInGroup )
273 {
274 /* Create a dummy anchor carrying the flags. Real
275 coordinates are calculated later in virtual call of
276 WriteData(EscherEx&,const Rectangle&). */
277 XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
278 pAnchor->SetFlags( *pObj );
279 pCurrAppData->SetClientAnchor( pAnchor );
280 }
281 const SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( pObj );
282 if( pTextObj && !lcl_IsFontwork( pTextObj ) && (pObj->GetObjIdentifier() != OBJ_CAPTION) )
283 {
284 const OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
285 if( pParaObj )
286 pCurrAppData->SetClientTextbox(
287 new XclEscherClientTextbox( GetRoot(), *pTextObj, pCurrXclObj ) );
288 }
289 }
290 else
291 {
292 if ( !bInGroup )
293 pCurrAppData->SetClientAnchor( mrObjMgr.CreateDffAnchor() );
294 }
295 }
296 else if ( nAdditionalText == 3 )
297 {
298 if ( pAdditionalText )
299 {
300 pAdditionalText->SetXclObj( pCurrXclObj );
301 pCurrAppData->SetClientTextbox( pAdditionalText );
302 }
303 }
304 }
305 }
306 if(pObj)
307 {
308 //add for exporting OCX control
309 //for OCX control import from MS office file,we need keep the id value as MS office file.
310 //GetOldRoot().pObjRecs->Add( pCurrXclObj ) statement has generated the id value as obj id rule;
311 //but we trick it here.
312 sal_uInt16 nObjType = pObj->GetObjIdentifier();
313 if( nObjType == OBJ_UNO && pCurrXclObj )
314 {
315 Reference< XPropertySet > xPropSet( rxShape, UNO_QUERY );
316 Any aAny;
317 try
318 {
319 aAny = xPropSet->getPropertyValue("ObjIDinMSO");
320 }
321 catch(const Exception&)
322 {
323 SAL_WARN("sc", "XclEscherEx::StartShape, this control can't get the property ObjIDinMSO!");
324 }
325 sal_uInt16 nObjIDinMSO = 0xFFFF;
326 aAny >>= nObjIDinMSO;
327 if( nObjIDinMSO != 0xFFFF && nMsCtlType == 2) //OCX
328 {
329 pCurrXclObj->SetId(nObjIDinMSO);
330 }
331 }
332 }
333 if ( !pCurrXclObj )
334 pCurrAppData->SetDontWriteShape( true );
335 return pCurrAppData.get();
336 }
337
EndShape(sal_uInt16 nShapeType,sal_uInt32 nShapeID)338 void XclEscherEx::EndShape( sal_uInt16 nShapeType, sal_uInt32 nShapeID )
339 {
340 // own escher data created? -> never delete such objects
341 bool bOwnEscher = pCurrXclObj && pCurrXclObj->IsOwnEscher();
342
343 // post process the current object - not for objects with own escher data
344 if( pCurrXclObj && !bOwnEscher )
345 {
346 // escher data of last shape not written? -> delete it from object list
347 if( nShapeID == 0 )
348 {
349 std::unique_ptr<XclObj> pLastObj = mrObjMgr.RemoveLastObj();
350 OSL_ENSURE( pLastObj.get() == pCurrXclObj, "XclEscherEx::EndShape - wrong object" );
351 pCurrXclObj = nullptr;
352 }
353
354 if( pCurrXclObj )
355 {
356 // set shape type
357 if ( pCurrAppData->IsStackedGroup() )
358 pCurrXclObj->SetEscherShapeTypeGroup();
359 else
360 {
361 pCurrXclObj->SetEscherShapeType( nShapeType );
362 UpdateDffFragmentEnd();
363 }
364 }
365 }
366
367 // get next object from stack
368 DeleteCurrAppData();
369 if (aStack.empty())
370 {
371 pCurrXclObj = nullptr;
372 pCurrAppData = nullptr;
373 }
374 else
375 {
376 pCurrXclObj = aStack.top().first;
377 pCurrAppData = std::move(aStack.top().second);
378 aStack.pop();
379 }
380 if( nAdditionalText == 3 )
381 nAdditionalText = 0;
382 }
383
EnterAdditionalTextGroup()384 EscherExHostAppData* XclEscherEx::EnterAdditionalTextGroup()
385 {
386 nAdditionalText = 1;
387 pAdditionalText = static_cast<XclEscherClientTextbox*>( pCurrAppData->GetClientTextbox() );
388 pCurrAppData->SetClientTextbox( nullptr );
389 return pCurrAppData.get();
390 }
391
EndDocument()392 void XclEscherEx::EndDocument()
393 {
394 if( mbIsRootDff )
395 Flush( static_cast< XclEscherExGlobal& >( *mxGlobal ).GetPictureStream() );
396
397 // seek back DFF stream to prepare saving the MSODRAWING[GROUP] records
398 mpOutStrm->Seek( 0 );
399 }
400
CreateOCXCtrlObj(Reference<XShape> const & xShape,const tools::Rectangle * pChildAnchor)401 std::unique_ptr<XclExpOcxControlObj> XclEscherEx::CreateOCXCtrlObj( Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor )
402 {
403 ::std::unique_ptr< XclExpOcxControlObj > xOcxCtrl;
404
405 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
406 if( xCtrlModel.is() )
407 {
408 // output stream
409 if( !mxCtlsStrm.is() )
410 mxCtlsStrm = OpenStream( EXC_STREAM_CTLS );
411 if( mxCtlsStrm.is() )
412 {
413 OUString aClassName;
414 sal_uInt32 nStrmStart = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() );
415
416 // writes from xCtrlModel into mxCtlsStrm, raw class name returned in aClassName
417 Reference< XOutputStream > xOut( new utl::OSeekableOutputStreamWrapper( *mxCtlsStrm ) );
418 Reference< css::frame::XModel > xModel( GetDocShell() ? GetDocShell()->GetModel() : nullptr );
419 if( xModel.is() && xOut.is() && oox::ole::MSConvertOCXControls::WriteOCXExcelKludgeStream( xModel, xOut, xCtrlModel, xShape->getSize(), aClassName ) )
420 {
421 sal_uInt32 nStrmSize = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() - nStrmStart );
422 // adjust the class name to "Forms.***.1"
423 aClassName = "Forms." + aClassName + ".1";
424 xOcxCtrl.reset( new XclExpOcxControlObj( mrObjMgr, xShape, pChildAnchor, aClassName, nStrmStart, nStrmSize ) );
425 }
426 }
427 }
428 return xOcxCtrl;
429 }
430
CreateTBXCtrlObj(Reference<XShape> const & xShape,const tools::Rectangle * pChildAnchor)431 std::unique_ptr<XclExpTbxControlObj> XclEscherEx::CreateTBXCtrlObj( Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor )
432 {
433 ::std::unique_ptr< XclExpTbxControlObj > xTbxCtrl( new XclExpTbxControlObj( mrObjMgr, xShape, pChildAnchor ) );
434 if( xTbxCtrl->GetObjType() == EXC_OBJTYPE_UNKNOWN )
435 xTbxCtrl.reset();
436
437 if (xTbxCtrl)
438 {
439 // find attached macro
440 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
441 ConvertTbxMacro( *xTbxCtrl, xCtrlModel );
442 }
443 return xTbxCtrl;
444 }
445
ConvertTbxMacro(XclExpTbxControlObj & rTbxCtrlObj,Reference<XControlModel> const & xCtrlModel)446 void XclEscherEx::ConvertTbxMacro( XclExpTbxControlObj& rTbxCtrlObj, Reference< XControlModel > const & xCtrlModel )
447 {
448 SdrPage* pSdrPage = GetSdrPage( GetCurrScTab() );
449 if( xCtrlModel.is() && GetDocShell() && pSdrPage ) try
450 {
451 Reference< XFormsSupplier > xFormsSupplier( pSdrPage->getUnoPage(), UNO_QUERY_THROW );
452 Reference< XIndexAccess > xFormsIA( xFormsSupplier->getForms(), UNO_QUERY_THROW );
453
454 // 1) try to find the index of the processed control in the form
455
456 Reference< XIndexAccess > xFormIA; // needed in step 2) below
457 sal_Int32 nFoundIdx = -1;
458
459 // search all existing forms in the draw page
460 for( sal_Int32 nFormIdx = 0, nFormCount = xFormsIA->getCount();
461 (nFoundIdx < 0) && (nFormIdx < nFormCount); ++nFormIdx )
462 {
463 // get the XIndexAccess interface of the form with index nFormIdx
464 if( xFormIA.set( xFormsIA->getByIndex( nFormIdx ), UNO_QUERY ) )
465 {
466 // search all elements (controls) of the current form by index
467 for( sal_Int32 nCtrlIdx = 0, nCtrlCount = xFormIA->getCount();
468 (nFoundIdx < 0) && (nCtrlIdx < nCtrlCount); ++nCtrlIdx )
469 {
470 // compare implementation pointers of the control models
471 Reference< XControlModel > xCurrModel( xFormIA->getByIndex( nCtrlIdx ), UNO_QUERY );
472 if( xCtrlModel.get() == xCurrModel.get() )
473 nFoundIdx = nCtrlIdx;
474 }
475 }
476 }
477
478 // 2) try to find an attached macro
479
480 if( xFormIA.is() && (nFoundIdx >= 0) )
481 {
482 Reference< XEventAttacherManager > xEventMgr( xFormIA, UNO_QUERY_THROW );
483 // loop over all events attached to the found control
484 const Sequence< ScriptEventDescriptor > aEventSeq( xEventMgr->getScriptEvents( nFoundIdx ) );
485 for( const auto& rEvent : aEventSeq )
486 {
487 // try to set the event data at the Excel control object, returns true on success
488 if (rTbxCtrlObj.SetMacroLink( rEvent ))
489 break;
490 }
491 }
492 }
493 catch( Exception& )
494 {
495 }
496 }
497
DeleteCurrAppData()498 void XclEscherEx::DeleteCurrAppData()
499 {
500 if ( pCurrAppData )
501 {
502 delete pCurrAppData->GetClientAnchor();
503 // delete pCurrAppData->GetClientData();
504 delete pCurrAppData->GetClientTextbox();
505 delete pCurrAppData->GetInteractionInfo();
506 pCurrAppData.reset();
507 }
508 }
509
510 // --- class XclEscherClientData -------------------------------------
511
WriteData(EscherEx & rEx) const512 void XclEscherClientData::WriteData( EscherEx& rEx ) const
513 { // actual data is in the following OBJ record
514 rEx.AddAtom( 0, ESCHER_ClientData );
515 }
516
517 // --- class XclEscherClientTextbox -------------------------------------
518
XclEscherClientTextbox(const XclExpRoot & rRoot,const SdrTextObj & rObj,XclObj * pObj)519 XclEscherClientTextbox::XclEscherClientTextbox( const XclExpRoot& rRoot,
520 const SdrTextObj& rObj, XclObj* pObj )
521 :
522 XclExpRoot( rRoot ),
523 rTextObj( rObj ),
524 pXclObj( pObj )
525 {
526 }
527
WriteData(EscherEx &) const528 void XclEscherClientTextbox::WriteData( EscherEx& /*rEx*/ ) const
529 {
530 pXclObj->SetText( GetRoot(), rTextObj );
531 }
532
533 XclExpShapeObj*
CreateShapeObj(XclExpObjectManager & rObjMgr,const Reference<XShape> & xShape,ScDocument * pDoc)534 ShapeInteractionHelper::CreateShapeObj( XclExpObjectManager& rObjMgr, const Reference< XShape >& xShape, ScDocument* pDoc )
535 {
536 return new XclExpShapeObj( rObjMgr, xShape, pDoc );
537 }
538
539 void
PopulateShapeInteractionInfo(const XclExpObjectManager & rObjMgr,const Reference<XShape> & xShape,EscherExHostAppData & rHostAppData)540 ShapeInteractionHelper::PopulateShapeInteractionInfo( const XclExpObjectManager& rObjMgr, const Reference< XShape >& xShape, EscherExHostAppData& rHostAppData )
541 {
542 try
543 {
544 SvMemoryStream* pMemStrm = nullptr;
545 OUString sHyperLink;
546 OUString sMacro;
547 if ( ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( ::GetSdrObjectFromXShape( xShape ) ) )
548 {
549 sHyperLink = pInfo->GetHlink();
550 sMacro = pInfo->GetMacro();
551 }
552 if ( !sHyperLink.isEmpty() )
553 {
554 pMemStrm = new SvMemoryStream();
555 XclExpStream tmpStream( *pMemStrm, rObjMgr.GetRoot() );
556 ScAddress dummyAddress;
557 SvxURLField aUrlField;
558 aUrlField.SetURL( sHyperLink );
559 XclExpHyperlink hExpHlink( rObjMgr.GetRoot(), aUrlField, dummyAddress );
560 hExpHlink.WriteEmbeddedData( tmpStream );
561 }
562 if ( !sHyperLink.isEmpty() || !sMacro.isEmpty() )
563 rHostAppData.SetInteractionInfo( new InteractionInfo( pMemStrm ) );
564 }
565 catch( Exception& )
566 {
567 }
568 }
569
570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
571