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