LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sc / source / filter / xcl97 / xcl97esc.cxx
blob7778944ccfd7a37fc4c8541e798a355203185863
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <com/sun/star/awt/XControlModel.hpp>
22 #include <com/sun/star/embed/XClassifiedObject.hpp>
23 #include <com/sun/star/embed/XEmbeddedObject.hpp>
24 #include <com/sun/star/form/XFormsSupplier.hpp>
25 #include <com/sun/star/script/XEventAttacherManager.hpp>
26 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <svx/svdpage.hxx>
29 #include <svx/svdotext.hxx>
30 #include <svx/svdobj.hxx>
31 #include <svx/svdoole2.hxx>
32 #include <svx/unoapi.hxx>
33 #include <unotools/tempfile.hxx>
34 #include <unotools/ucbstreamhelper.hxx>
35 #include <svx/sdasitm.hxx>
36 #include <sfx2/docfile.hxx>
37 #include <sal/log.hxx>
39 #include <sot/exchange.hxx>
40 #include <sot/storage.hxx>
41 #include <xeescher.hxx>
43 #include <drwlayer.hxx>
44 #include <xecontent.hxx>
45 #include <editeng/flditem.hxx>
46 #include <userdat.hxx>
47 #include <xcl97rec.hxx>
48 #include <xcl97esc.hxx>
49 #include <unotools/streamwrap.hxx>
50 #include <oox/ole/olehelper.hxx>
51 #include <sfx2/objsh.hxx>
53 using ::com::sun::star::uno::Any;
54 using ::com::sun::star::uno::Exception;
55 using ::com::sun::star::uno::Reference;
56 using ::com::sun::star::uno::Sequence;
57 using ::com::sun::star::uno::UNO_QUERY;
58 using ::com::sun::star::uno::UNO_QUERY_THROW;
59 using ::com::sun::star::container::XIndexAccess;
60 using ::com::sun::star::embed::XClassifiedObject;
61 using ::com::sun::star::drawing::XShape;
62 using ::com::sun::star::awt::XControlModel;
63 using ::com::sun::star::beans::XPropertySet;
64 using ::com::sun::star::uno::Any;
65 using ::com::sun::star::form::XFormsSupplier;
66 using ::com::sun::star::io::XOutputStream;
67 using ::com::sun::star::script::ScriptEventDescriptor;
68 using ::com::sun::star::script::XEventAttacherManager;
70 XclEscherExGlobal::XclEscherExGlobal( const XclExpRoot& rRoot ) :
71 XclExpRoot( rRoot )
73 SetBaseURI( GetMedium().GetBaseURL( true ) );
76 SvStream* XclEscherExGlobal::ImplQueryPictureStream()
78 mxPicTempFile.reset( new ::utl::TempFile );
79 if( mxPicTempFile->IsValid() )
81 mxPicTempFile->EnableKillingFile();
82 mxPicStrm = ::utl::UcbStreamHelper::CreateStream( mxPicTempFile->GetURL(), StreamMode::STD_READWRITE );
83 mxPicStrm->SetEndian( SvStreamEndian::LITTLE );
85 return mxPicStrm.get();
88 XclEscherEx::XclEscherEx( const XclExpRoot& rRoot, XclExpObjectManager& rObjMgr, SvStream& rStrm, const XclEscherEx* pParent ) :
89 EscherEx( pParent ? pParent->mxGlobal : std::make_shared<XclEscherExGlobal>( rRoot ), &rStrm ),
90 XclExpRoot( rRoot ),
91 mrObjMgr( rObjMgr ),
92 pCurrXclObj( nullptr ),
93 pTheClientData( new XclEscherClientData ),
94 pAdditionalText( nullptr ),
95 nAdditionalText( 0 ),
96 mnNextKey( 0 ),
97 mbIsRootDff( pParent == nullptr )
99 InsertPersistOffset( mnNextKey, 0 );
102 XclEscherEx::~XclEscherEx()
104 OSL_ENSURE( aStack.empty(), "~XclEscherEx: stack not empty" );
105 DeleteCurrAppData();
106 pTheClientData.reset();
109 sal_uInt32 XclEscherEx::InitNextDffFragment()
111 /* Current value of mnNextKey will be used by caller to refer to the
112 starting point of the DFF fragment. The key exists already in the
113 PersistTable (has been inserted by c'tor of previous call of
114 InitNextDffFragment(), has been updated by UpdateDffFragmentEnd(). */
115 sal_uInt32 nPersistKey = mnNextKey;
117 /* Prepare the next key that is used by caller as end point of the DFF
118 fragment. Will be updated by caller when writing to the DFF stream,
119 using the UpdateDffFragmentEnd() function. This is needed to find DFF
120 data written by the SVX base class implementation without interaction,
121 e.g. the solver container that will be written after the last shape. */
122 ++mnNextKey;
123 InsertPersistOffset( mnNextKey, mpOutStrm->Tell() );
125 return nPersistKey;
128 void XclEscherEx::UpdateDffFragmentEnd()
130 // update existing fragment key with new stream position
131 ReplacePersistOffset( mnNextKey, mpOutStrm->Tell() );
134 sal_uInt32 XclEscherEx::GetDffFragmentPos( sal_uInt32 nFragmentKey )
136 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
137 is non-const due to tools/List usage. */
138 return GetPersistOffset( nFragmentKey );
141 sal_uInt32 XclEscherEx::GetDffFragmentSize( sal_uInt32 nFragmentKey )
143 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
144 is non-const due to tools/List usage. */
145 return GetDffFragmentPos( nFragmentKey + 1 ) - GetDffFragmentPos( nFragmentKey );
148 bool XclEscherEx::HasPendingDffData()
150 /* TODO: this function is non-const because PersistTable::PtGetOffsetByID()
151 is non-const due to tools/List usage. */
152 return GetDffFragmentPos( mnNextKey ) < GetStreamPos();
155 XclExpDffAnchorBase* XclEscherEx::CreateDffAnchor( const SdrObject& rSdrObj ) const
157 // the object manager creates the correct anchor type according to context
158 XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
159 // pass the drawing object, that will calculate the anchor position
160 pAnchor->SetSdrObject( rSdrObj );
161 return pAnchor;
164 namespace {
166 bool lcl_IsFontwork( const SdrObject* pObj )
168 bool bIsFontwork = false;
169 if( pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE )
171 static const OUStringLiteral aTextPath = u"TextPath";
172 const SdrCustomShapeGeometryItem& rGeometryItem =
173 pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
174 if( const Any* pAny = rGeometryItem.GetPropertyValueByName( aTextPath, aTextPath ) )
175 *pAny >>= bIsFontwork;
177 return bIsFontwork;
180 } // namespace
182 EscherExHostAppData* XclEscherEx::StartShape( const Reference< XShape >& rxShape, const tools::Rectangle* pChildAnchor )
184 if ( nAdditionalText )
185 nAdditionalText++;
186 bool bInGroup = ( pCurrXclObj != nullptr );
187 if ( bInGroup )
188 { // stacked recursive group object
189 if ( !pCurrAppData->IsStackedGroup() )
190 { //! UpdateDffFragmentEnd only once
191 pCurrAppData->SetStackedGroup( true );
192 UpdateDffFragmentEnd();
195 aStack.push( std::make_pair( pCurrXclObj, std::move(pCurrAppData) ) );
196 pCurrAppData.reset( new XclEscherHostAppData );
197 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rxShape);
198 //added for exporting OCX control
199 sal_Int16 nMsCtlType = 0;
200 if ( !pObj )
201 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() ); // just what is it?!?
202 else
204 pCurrXclObj = nullptr;
205 sal_uInt16 nObjType = pObj->GetObjIdentifier();
207 if( nObjType == OBJ_OLE2 )
209 // no OLE objects in embedded drawings (chart shapes)
210 if( mbIsRootDff )
212 //! not-const because GetObjRef may load the OLE object
213 Reference < XClassifiedObject > xObj( static_cast<SdrOle2Obj*>(pObj)->GetObjRef() );
214 if ( xObj.is() )
216 SvGlobalName aObjClsId( xObj->getClassID() );
217 if ( SotExchange::IsChart( aObjClsId ) )
218 { // yes, it's a chart diagram
219 mrObjMgr.AddObj( std::make_unique<XclExpChartObj>( mrObjMgr, rxShape, pChildAnchor, &GetDoc() ) );
220 pCurrXclObj = nullptr; // no metafile or whatsoever
222 else // metafile and OLE object
223 pCurrXclObj = new XclObjOle( mrObjMgr, *pObj );
225 else // just a metafile
226 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() );
228 else
229 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() );
231 else if( nObjType == OBJ_UNO )
233 //added for exporting OCX control
234 Reference< XPropertySet > xPropSet( rxShape, UNO_QUERY );
235 Any aAny;
238 aAny = xPropSet->getPropertyValue("ControlTypeinMSO");
239 aAny >>= nMsCtlType;
241 catch(const Exception&)
243 SAL_WARN("sc", "XclEscherEx::StartShape, this control can't get the property ControlTypeinMSO!");
245 if( nMsCtlType == 2 ) //OCX Form Control
246 pCurrXclObj = CreateOCXCtrlObj( rxShape, pChildAnchor ).release();
247 else //TBX Form Control
248 pCurrXclObj = CreateTBXCtrlObj( rxShape, pChildAnchor ).release();
249 if( !pCurrXclObj )
250 pCurrXclObj = new XclObjAny( mrObjMgr, rxShape, &GetDoc() ); // just a metafile
252 else if( !ScDrawLayer::IsNoteCaption( pObj ) )
254 // ignore permanent note shapes
255 // #i12190# do not ignore callouts (do not filter by object type ID)
256 pCurrXclObj = ShapeInteractionHelper::CreateShapeObj( mrObjMgr, rxShape, &GetDoc() );
257 ShapeInteractionHelper::PopulateShapeInteractionInfo( mrObjMgr, rxShape, *pCurrAppData );
260 if ( pCurrXclObj )
262 if ( !mrObjMgr.AddObj( std::unique_ptr<XclObj>(pCurrXclObj) ) )
263 { // maximum count reached, object got deleted
264 pCurrXclObj = nullptr;
266 else
268 pCurrAppData->SetClientData( pTheClientData.get() );
269 if ( nAdditionalText == 0 )
271 if ( pObj )
273 if ( !bInGroup )
275 /* Create a dummy anchor carrying the flags. Real
276 coordinates are calculated later in virtual call of
277 WriteData(EscherEx&,const Rectangle&). */
278 XclExpDffAnchorBase* pAnchor = mrObjMgr.CreateDffAnchor();
279 pAnchor->SetFlags( *pObj );
280 pCurrAppData->SetClientAnchor( pAnchor );
282 const SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( pObj );
283 if( pTextObj && !lcl_IsFontwork( pTextObj ) && (pObj->GetObjIdentifier() != OBJ_CAPTION) )
285 const OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
286 if( pParaObj )
287 pCurrAppData->SetClientTextbox(
288 new XclEscherClientTextbox( GetRoot(), *pTextObj, pCurrXclObj ) );
291 else
293 if ( !bInGroup )
294 pCurrAppData->SetClientAnchor( mrObjMgr.CreateDffAnchor() );
297 else if ( nAdditionalText == 3 )
299 if ( pAdditionalText )
301 pAdditionalText->SetXclObj( pCurrXclObj );
302 pCurrAppData->SetClientTextbox( pAdditionalText );
307 if(pObj)
309 //add for exporting OCX control
310 //for OCX control import from MS office file,we need keep the id value as MS office file.
311 //GetOldRoot().pObjRecs->Add( pCurrXclObj ) statement has generated the id value as obj id rule;
312 //but we trick it here.
313 sal_uInt16 nObjType = pObj->GetObjIdentifier();
314 if( nObjType == OBJ_UNO && pCurrXclObj )
316 Reference< XPropertySet > xPropSet( rxShape, UNO_QUERY );
317 Any aAny;
320 aAny = xPropSet->getPropertyValue("ObjIDinMSO");
322 catch(const Exception&)
324 SAL_WARN("sc", "XclEscherEx::StartShape, this control can't get the property ObjIDinMSO!");
326 sal_uInt16 nObjIDinMSO = 0xFFFF;
327 aAny >>= nObjIDinMSO;
328 if( nObjIDinMSO != 0xFFFF && nMsCtlType == 2) //OCX
330 pCurrXclObj->SetId(nObjIDinMSO);
334 if ( !pCurrXclObj )
335 pCurrAppData->SetDontWriteShape( true );
336 return pCurrAppData.get();
339 void XclEscherEx::EndShape( sal_uInt16 nShapeType, sal_uInt32 nShapeID )
341 // own escher data created? -> never delete such objects
342 bool bOwnEscher = pCurrXclObj && pCurrXclObj->IsOwnEscher();
344 // post process the current object - not for objects with own escher data
345 if( pCurrXclObj && !bOwnEscher )
347 // escher data of last shape not written? -> delete it from object list
348 if( nShapeID == 0 )
350 std::unique_ptr<XclObj> pLastObj = mrObjMgr.RemoveLastObj();
351 OSL_ENSURE( pLastObj.get() == pCurrXclObj, "XclEscherEx::EndShape - wrong object" );
352 pCurrXclObj = nullptr;
355 if( pCurrXclObj )
357 // set shape type
358 if ( pCurrAppData->IsStackedGroup() )
359 pCurrXclObj->SetEscherShapeTypeGroup();
360 else
362 pCurrXclObj->SetEscherShapeType( nShapeType );
363 UpdateDffFragmentEnd();
368 // get next object from stack
369 DeleteCurrAppData();
370 if (aStack.empty())
372 pCurrXclObj = nullptr;
373 pCurrAppData = nullptr;
375 else
377 pCurrXclObj = aStack.top().first;
378 pCurrAppData = std::move(aStack.top().second);
379 aStack.pop();
381 if( nAdditionalText == 3 )
382 nAdditionalText = 0;
385 EscherExHostAppData* XclEscherEx::EnterAdditionalTextGroup()
387 nAdditionalText = 1;
388 pAdditionalText = static_cast<XclEscherClientTextbox*>( pCurrAppData->GetClientTextbox() );
389 pCurrAppData->SetClientTextbox( nullptr );
390 return pCurrAppData.get();
393 void XclEscherEx::EndDocument()
395 if( mbIsRootDff )
396 Flush( static_cast< XclEscherExGlobal& >( *mxGlobal ).GetPictureStream() );
398 // seek back DFF stream to prepare saving the MSODRAWING[GROUP] records
399 mpOutStrm->Seek( 0 );
402 std::unique_ptr<XclExpOcxControlObj> XclEscherEx::CreateOCXCtrlObj( Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor )
404 ::std::unique_ptr< XclExpOcxControlObj > xOcxCtrl;
406 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
407 if( xCtrlModel.is() )
409 // output stream
410 if( !mxCtlsStrm.is() )
411 mxCtlsStrm = OpenStream( EXC_STREAM_CTLS );
412 if( mxCtlsStrm.is() )
414 OUString aClassName;
415 sal_uInt32 nStrmStart = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() );
417 // writes from xCtrlModel into mxCtlsStrm, raw class name returned in aClassName
418 Reference< XOutputStream > xOut( new utl::OSeekableOutputStreamWrapper( *mxCtlsStrm ) );
419 Reference< css::frame::XModel > xModel( GetDocShell() ? GetDocShell()->GetModel() : nullptr );
420 if( xModel.is() && xOut.is() && oox::ole::MSConvertOCXControls::WriteOCXExcelKludgeStream( xModel, xOut, xCtrlModel, xShape->getSize(), aClassName ) )
422 sal_uInt32 nStrmSize = static_cast< sal_uInt32 >( mxCtlsStrm->Tell() - nStrmStart );
423 // adjust the class name to "Forms.***.1"
424 aClassName = "Forms." + aClassName + ".1";
425 xOcxCtrl.reset( new XclExpOcxControlObj( mrObjMgr, xShape, pChildAnchor, aClassName, nStrmStart, nStrmSize ) );
429 return xOcxCtrl;
432 std::unique_ptr<XclExpTbxControlObj> XclEscherEx::CreateTBXCtrlObj( Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor )
434 ::std::unique_ptr< XclExpTbxControlObj > xTbxCtrl( new XclExpTbxControlObj( mrObjMgr, xShape, pChildAnchor ) );
435 if( xTbxCtrl->GetObjType() == EXC_OBJTYPE_UNKNOWN )
436 xTbxCtrl.reset();
438 if (xTbxCtrl)
440 // find attached macro
441 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
442 ConvertTbxMacro( *xTbxCtrl, xCtrlModel );
444 return xTbxCtrl;
447 void XclEscherEx::ConvertTbxMacro( XclExpTbxControlObj& rTbxCtrlObj, Reference< XControlModel > const & xCtrlModel )
449 SdrPage* pSdrPage = GetSdrPage( GetCurrScTab() );
450 if( !(xCtrlModel.is() && GetDocShell() && pSdrPage) )
451 return;
455 Reference< XFormsSupplier > xFormsSupplier( pSdrPage->getUnoPage(), UNO_QUERY_THROW );
456 Reference< XIndexAccess > xFormsIA( xFormsSupplier->getForms(), UNO_QUERY_THROW );
458 // 1) try to find the index of the processed control in the form
460 Reference< XIndexAccess > xFormIA; // needed in step 2) below
461 sal_Int32 nFoundIdx = -1;
463 // search all existing forms in the draw page
464 for( sal_Int32 nFormIdx = 0, nFormCount = xFormsIA->getCount();
465 (nFoundIdx < 0) && (nFormIdx < nFormCount); ++nFormIdx )
467 // get the XIndexAccess interface of the form with index nFormIdx
468 if( xFormIA.set( xFormsIA->getByIndex( nFormIdx ), UNO_QUERY ) )
470 // search all elements (controls) of the current form by index
471 for( sal_Int32 nCtrlIdx = 0, nCtrlCount = xFormIA->getCount();
472 (nFoundIdx < 0) && (nCtrlIdx < nCtrlCount); ++nCtrlIdx )
474 // compare implementation pointers of the control models
475 Reference< XControlModel > xCurrModel( xFormIA->getByIndex( nCtrlIdx ), UNO_QUERY );
476 if( xCtrlModel.get() == xCurrModel.get() )
477 nFoundIdx = nCtrlIdx;
482 // 2) try to find an attached macro
484 if( xFormIA.is() && (nFoundIdx >= 0) )
486 Reference< XEventAttacherManager > xEventMgr( xFormIA, UNO_QUERY_THROW );
487 // loop over all events attached to the found control
488 const Sequence< ScriptEventDescriptor > aEventSeq( xEventMgr->getScriptEvents( nFoundIdx ) );
489 for( const auto& rEvent : aEventSeq )
491 // try to set the event data at the Excel control object, returns true on success
492 if (rTbxCtrlObj.SetMacroLink( rEvent ))
493 break;
497 catch( Exception& )
502 void XclEscherEx::DeleteCurrAppData()
504 if ( pCurrAppData )
506 delete pCurrAppData->GetClientAnchor();
507 delete pCurrAppData->GetClientTextbox();
508 delete pCurrAppData->GetInteractionInfo();
509 pCurrAppData.reset();
513 // --- class XclEscherClientData -------------------------------------
515 void XclEscherClientData::WriteData( EscherEx& rEx ) const
516 { // actual data is in the following OBJ record
517 rEx.AddAtom( 0, ESCHER_ClientData );
520 // --- class XclEscherClientTextbox -------------------------------------
522 XclEscherClientTextbox::XclEscherClientTextbox( const XclExpRoot& rRoot,
523 const SdrTextObj& rObj, XclObj* pObj )
525 XclExpRoot( rRoot ),
526 rTextObj( rObj ),
527 pXclObj( pObj )
531 void XclEscherClientTextbox::WriteData( EscherEx& /*rEx*/ ) const
533 pXclObj->SetText( GetRoot(), rTextObj );
536 XclExpShapeObj*
537 ShapeInteractionHelper::CreateShapeObj( XclExpObjectManager& rObjMgr, const Reference< XShape >& xShape, ScDocument* pDoc )
539 return new XclExpShapeObj( rObjMgr, xShape, pDoc );
542 void ShapeInteractionHelper::PopulateShapeInteractionInfo(const XclExpObjectManager& rObjMgr,
543 const Reference<XShape>& xShape,
544 EscherExHostAppData& rHostAppData)
548 SvMemoryStream* pMemStrm = nullptr;
549 OUString sHyperLink;
550 OUString sMacro;
551 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
552 if (pObj)
553 sHyperLink = pObj->getHyperlink();
554 if (ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo(pObj))
556 sMacro = pInfo->GetMacro();
558 if (!sHyperLink.isEmpty())
560 pMemStrm = new SvMemoryStream();
561 XclExpStream tmpStream(*pMemStrm, rObjMgr.GetRoot());
562 ScAddress dummyAddress;
563 SvxURLField aUrlField;
564 aUrlField.SetURL(sHyperLink);
565 XclExpHyperlink hExpHlink(rObjMgr.GetRoot(), aUrlField, dummyAddress);
566 hExpHlink.WriteEmbeddedData(tmpStream);
568 if (!sHyperLink.isEmpty() || !sMacro.isEmpty())
569 rHostAppData.SetInteractionInfo(new InteractionInfo(pMemStrm));
571 catch (Exception&)
576 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */