LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sc / source / filter / excel / xeescher.cxx
blob3d3d23520e9412d9ea16b13c0dbb9ec477ec91c5
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 <xeescher.hxx>
22 #include <com/sun/star/lang/XServiceInfo.hpp>
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/form/FormComponentType.hpp>
25 #include <com/sun/star/awt/VisualEffect.hpp>
26 #include <com/sun/star/awt/ScrollBarOrientation.hpp>
27 #include <com/sun/star/awt/XControlModel.hpp>
28 #include <com/sun/star/drawing/XShape.hpp>
29 #include <com/sun/star/form/binding/XBindableValue.hpp>
30 #include <com/sun/star/form/binding/XListEntrySink.hpp>
31 #include <com/sun/star/awt/Size.hpp>
32 #include <com/sun/star/chart/XChartDocument.hpp>
34 #include <set>
35 #include <vcl/BitmapReadAccess.hxx>
36 #include <svx/svdoole2.hxx>
37 #include <svx/svdocapt.hxx>
38 #include <editeng/outlobj.hxx>
39 #include <unotools/tempfile.hxx>
40 #include <unotools/ucbstreamhelper.hxx>
41 #include <svtools/embedhlp.hxx>
43 #include <unonames.hxx>
44 #include <convuno.hxx>
45 #include <postit.hxx>
47 #include <fapihelper.hxx>
48 #include <xcl97esc.hxx>
49 #include <xechart.hxx>
50 #include <xeformula.hxx>
51 #include <xehelper.hxx>
52 #include <xelink.hxx>
53 #include <xename.hxx>
54 #include <xestyle.hxx>
55 #include <xllink.hxx>
56 #include <xltools.hxx>
57 #include <userdat.hxx>
58 #include <drwlayer.hxx>
59 #include <svl/itemset.hxx>
60 #include <svx/unoapi.hxx>
61 #include <svx/sdtaitm.hxx>
62 #include <document.hxx>
63 #include <svx/xfillit0.hxx>
64 #include <svx/xflclit.hxx>
66 #include <comphelper/sequence.hxx>
67 #include <oox/token/tokens.hxx>
68 #include <oox/token/relationship.hxx>
69 #include <oox/export/drawingml.hxx>
70 #include <oox/export/chartexport.hxx>
71 #include <oox/export/utils.hxx>
72 #include <oox/token/namespaces.hxx>
73 #include <oox/export/vmlexport.hxx>
74 #include <memory>
76 using namespace com::sun::star;
77 using ::com::sun::star::uno::UNO_QUERY;
78 using ::com::sun::star::uno::Reference;
79 using ::com::sun::star::uno::Sequence;
80 using ::com::sun::star::lang::XServiceInfo;
81 using ::com::sun::star::beans::XPropertySet;
82 using ::com::sun::star::drawing::XShape;
83 using ::com::sun::star::drawing::XShapes;
84 using ::com::sun::star::frame::XModel;
85 using ::com::sun::star::awt::XControlModel;
86 using ::com::sun::star::form::binding::XBindableValue;
87 using ::com::sun::star::form::binding::XListEntrySink;
88 using ::com::sun::star::script::ScriptEventDescriptor;
89 using ::com::sun::star::table::CellAddress;
90 using ::com::sun::star::table::CellRangeAddress;
91 using ::oox::drawingml::DrawingML;
92 using ::oox::drawingml::ChartExport;
93 using namespace oox;
95 namespace
98 const char *ToHorizAlign( SdrTextHorzAdjust eAdjust )
100 switch( eAdjust )
102 case SDRTEXTHORZADJUST_CENTER:
103 return "center";
104 case SDRTEXTHORZADJUST_RIGHT:
105 return "right";
106 case SDRTEXTHORZADJUST_BLOCK:
107 return "justify";
108 case SDRTEXTHORZADJUST_LEFT:
109 default:
110 return "left";
114 const char *ToVertAlign( SdrTextVertAdjust eAdjust )
116 switch( eAdjust )
118 case SDRTEXTVERTADJUST_CENTER:
119 return "center";
120 case SDRTEXTVERTADJUST_BOTTOM:
121 return "bottom";
122 case SDRTEXTVERTADJUST_BLOCK:
123 return "justify";
124 case SDRTEXTVERTADJUST_TOP:
125 default:
126 return "top";
130 void lcl_WriteAnchorVertex( sax_fastparser::FSHelperPtr const & rComments, const tools::Rectangle &aRect )
132 rComments->startElement(FSNS(XML_xdr, XML_col));
133 rComments->writeEscaped( OUString::number( aRect.Left() ) );
134 rComments->endElement( FSNS( XML_xdr, XML_col ) );
135 rComments->startElement(FSNS(XML_xdr, XML_colOff));
136 rComments->writeEscaped( OUString::number( aRect.Top() ) );
137 rComments->endElement( FSNS( XML_xdr, XML_colOff ) );
138 rComments->startElement(FSNS(XML_xdr, XML_row));
139 rComments->writeEscaped( OUString::number( aRect.Right() ) );
140 rComments->endElement( FSNS( XML_xdr, XML_row ) );
141 rComments->startElement(FSNS(XML_xdr, XML_rowOff));
142 rComments->writeEscaped( OUString::number( aRect.Bottom() ) );
143 rComments->endElement( FSNS( XML_xdr, XML_rowOff ) );
146 tools::Long lcl_hmm2output(tools::Long value, bool bInEMU)
148 return o3tl::convert(value, o3tl::Length::mm100, bInEMU ? o3tl::Length::emu : o3tl::Length::px);
151 void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_Int32 nTab, tools::Rectangle &aFrom, tools::Rectangle &aTo, bool bInEMU = false )
153 sal_Int32 nCol = 0, nRow = 0;
154 sal_Int32 nColOff = 0, nRowOff= 0;
156 const bool bRTL = rRoot.GetDoc().IsNegativePage( nTab );
157 if (!bRTL)
159 while(true)
161 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
162 if( r.Left() <= aRect.Left() )
164 nCol++;
165 nColOff = aRect.Left() - r.Left();
167 if( r.Top() <= aRect.Top() )
169 nRow++;
170 nRowOff = aRect.Top() - r.Top();
172 if( r.Left() > aRect.Left() && r.Top() > aRect.Top() )
174 aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
175 nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
176 break;
180 else
182 while(true)
184 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
185 if( r.Left() >= aRect.Left() )
187 nCol++;
188 nColOff = r.Left() - aRect.Left();
190 if( r.Top() <= aRect.Top() )
192 nRow++;
193 nRowOff = aRect.Top() - r.Top();
195 if( r.Left() < aRect.Left() && r.Top() > aRect.Top() )
197 aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
198 nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
199 break;
203 if (!bRTL)
205 while(true)
207 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
208 if( r.Right() < aRect.Right() )
209 nCol++;
210 if( r.Bottom() < aRect.Bottom() )
211 nRow++;
212 if( r.Right() >= aRect.Right() && r.Bottom() >= aRect.Bottom() )
214 aTo = tools::Rectangle( nCol, lcl_hmm2output( aRect.Right() - r.Left(), bInEMU ),
215 nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
216 break;
220 else
222 while(true)
224 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
225 if( r.Right() >= aRect.Right() )
226 nCol++;
227 if( r.Bottom() < aRect.Bottom() )
228 nRow++;
229 if( r.Right() < aRect.Right() && r.Bottom() >= aRect.Bottom() )
231 aTo = tools::Rectangle( nCol, lcl_hmm2output( r.Left() - aRect.Right(), bInEMU ),
232 nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
233 break;
239 } // namespace
241 // Escher client anchor =======================================================
243 XclExpDffAnchorBase::XclExpDffAnchorBase( const XclExpRoot& rRoot, sal_uInt16 nFlags ) :
244 XclExpRoot( rRoot ),
245 mnFlags( nFlags )
249 void XclExpDffAnchorBase::SetFlags( const SdrObject& rSdrObj )
251 ImplSetFlags( rSdrObj );
254 void XclExpDffAnchorBase::SetSdrObject( const SdrObject& rSdrObj )
256 ImplSetFlags( rSdrObj );
257 ImplCalcAnchorRect( rSdrObj.GetCurrentBoundRect(), MapUnit::Map100thMM );
260 void XclExpDffAnchorBase::WriteDffData( EscherEx& rEscherEx ) const
262 rEscherEx.AddAtom( 18, ESCHER_ClientAnchor );
263 rEscherEx.GetStream().WriteUInt16( mnFlags );
264 WriteXclObjAnchor( rEscherEx.GetStream(), maAnchor );
267 void XclExpDffAnchorBase::WriteData( EscherEx& rEscherEx, const tools::Rectangle& rRect )
269 // the passed rectangle is in twips
270 ImplCalcAnchorRect( rRect, MapUnit::MapTwip );
271 WriteDffData( rEscherEx );
274 void XclExpDffAnchorBase::ImplSetFlags( const SdrObject& )
276 OSL_FAIL( "XclExpDffAnchorBase::ImplSetFlags - not implemented" );
279 void XclExpDffAnchorBase::ImplCalcAnchorRect( const tools::Rectangle&, MapUnit )
281 OSL_FAIL( "XclExpDffAnchorBase::ImplCalcAnchorRect - not implemented" );
284 XclExpDffSheetAnchor::XclExpDffSheetAnchor( const XclExpRoot& rRoot ) :
285 XclExpDffAnchorBase( rRoot ),
286 mnScTab( rRoot.GetCurrScTab() )
290 void XclExpDffSheetAnchor::ImplSetFlags( const SdrObject& rSdrObj )
292 // set flags for cell/page anchoring
293 if ( ScDrawLayer::GetAnchorType( rSdrObj ) == SCA_CELL )
294 mnFlags = 0;
295 else
296 mnFlags = EXC_ESC_ANCHOR_LOCKED;
299 void XclExpDffSheetAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
301 maAnchor.SetRect( GetRoot(), mnScTab, rRect, eMapUnit );
304 XclExpDffEmbeddedAnchor::XclExpDffEmbeddedAnchor( const XclExpRoot& rRoot,
305 const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
306 XclExpDffAnchorBase( rRoot ),
307 maPageSize( rPageSize ),
308 mnScaleX( nScaleX ),
309 mnScaleY( nScaleY )
313 void XclExpDffEmbeddedAnchor::ImplSetFlags( const SdrObject& /*rSdrObj*/ )
315 // TODO (unsupported feature): fixed size
318 void XclExpDffEmbeddedAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
320 maAnchor.SetRect( maPageSize, mnScaleX, mnScaleY, rRect, eMapUnit );
323 XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot& rRoot, const tools::Rectangle& rRect ) :
324 XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_SIZELOCKED )
326 maAnchor.SetRect( rRoot, rRoot.GetCurrScTab(), rRect, MapUnit::Map100thMM );
329 XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
330 XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_POSLOCKED )
332 GetAddressConverter().ConvertAddress( maAnchor.maFirst, rScPos, true );
333 maAnchor.maLast.mnCol = maAnchor.maFirst.mnCol + 1;
334 maAnchor.maLast.mnRow = maAnchor.maFirst.mnRow + 1;
335 maAnchor.mnLX = maAnchor.mnTY = maAnchor.mnRX = maAnchor.mnBY = 0;
338 // MSODRAWING* records ========================================================
340 XclExpMsoDrawingBase::XclExpMsoDrawingBase( XclEscherEx& rEscherEx, sal_uInt16 nRecId ) :
341 XclExpRecord( nRecId ),
342 mrEscherEx( rEscherEx ),
343 mnFragmentKey( rEscherEx.InitNextDffFragment() )
347 void XclExpMsoDrawingBase::WriteBody( XclExpStream& rStrm )
349 OSL_ENSURE( mrEscherEx.GetStreamPos() == mrEscherEx.GetDffFragmentPos( mnFragmentKey ),
350 "XclExpMsoDrawingBase::WriteBody - DFF stream position mismatch" );
351 rStrm.CopyFromStream( mrEscherEx.GetStream(), mrEscherEx.GetDffFragmentSize( mnFragmentKey ) );
354 XclExpMsoDrawingGroup::XclExpMsoDrawingGroup( XclEscherEx& rEscherEx ) :
355 XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWINGGROUP )
357 SvStream& rDffStrm = mrEscherEx.GetStream();
359 // write the DGGCONTAINER with some default settings
360 mrEscherEx.OpenContainer( ESCHER_DggContainer );
362 // TODO: stuff the OPT atom with our own document defaults?
363 static const sal_uInt8 spnDffOpt[] = {
364 0xBF, 0x00, 0x08, 0x00, 0x08, 0x00, 0x81, 0x01,
365 0x09, 0x00, 0x00, 0x08, 0xC0, 0x01, 0x40, 0x00,
366 0x00, 0x08
368 mrEscherEx.AddAtom( sizeof( spnDffOpt ), ESCHER_OPT, 3, 3 );
369 rDffStrm.WriteBytes(spnDffOpt, sizeof(spnDffOpt));
371 // SPLITMENUCOLORS contains colors in toolbar
372 static const sal_uInt8 spnDffSplitMenuColors[] = {
373 0x0D, 0x00, 0x00, 0x08, 0x0C, 0x00, 0x00, 0x08,
374 0x17, 0x00, 0x00, 0x08, 0xF7, 0x00, 0x00, 0x10
376 mrEscherEx.AddAtom( sizeof( spnDffSplitMenuColors ), ESCHER_SplitMenuColors, 0, 4 );
377 rDffStrm.WriteBytes(spnDffSplitMenuColors, sizeof(spnDffSplitMenuColors));
379 // close the DGGCONTAINER
380 mrEscherEx.CloseContainer();
381 mrEscherEx.UpdateDffFragmentEnd();
384 XclExpMsoDrawing::XclExpMsoDrawing( XclEscherEx& rEscherEx ) :
385 XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWING )
389 XclExpImgData::XclExpImgData( const Graphic& rGraphic, sal_uInt16 nRecId ) :
390 maGraphic( rGraphic ),
391 mnRecId( nRecId )
395 void XclExpImgData::Save( XclExpStream& rStrm )
397 Bitmap aBmp = maGraphic.GetBitmapEx().GetBitmap();
398 if (aBmp.getPixelFormat() != vcl::PixelFormat::N24_BPP)
399 aBmp.Convert( BmpConversion::N24Bit );
401 Bitmap::ScopedReadAccess pAccess(aBmp);
402 if( !pAccess )
403 return;
405 sal_Int32 nWidth = ::std::min< sal_Int32 >( pAccess->Width(), 0xFFFF );
406 sal_Int32 nHeight = ::std::min< sal_Int32 >( pAccess->Height(), 0xFFFF );
407 if( (nWidth <= 0) || (nHeight <= 0) )
408 return;
410 sal_uInt8 nPadding = static_cast< sal_uInt8 >( nWidth & 0x03 );
411 sal_uInt32 nTmpSize = static_cast< sal_uInt32 >( (nWidth * 3 + nPadding) * nHeight + 12 );
413 rStrm.StartRecord( mnRecId, nTmpSize + 4 );
415 rStrm << EXC_IMGDATA_BMP // BMP format
416 << EXC_IMGDATA_WIN // Windows
417 << nTmpSize // size after _this_ field
418 << sal_uInt32( 12 ) // BITMAPCOREHEADER size
419 << static_cast< sal_uInt16 >( nWidth ) // width
420 << static_cast< sal_uInt16 >( nHeight ) // height
421 << sal_uInt16( 1 ) // planes
422 << sal_uInt16( 24 ); // bits per pixel
424 for( sal_Int32 nY = nHeight - 1; nY >= 0; --nY )
426 Scanline pScanline = pAccess->GetScanline( nY );
427 for( sal_Int32 nX = 0; nX < nWidth; ++nX )
429 const BitmapColor& rBmpColor = pAccess->GetPixelFromData( pScanline, nX );
430 rStrm << rBmpColor.GetBlue() << rBmpColor.GetGreen() << rBmpColor.GetRed();
432 rStrm.WriteZeroBytes( nPadding );
435 rStrm.EndRecord();
438 void XclExpImgData::SaveXml( XclExpXmlStream& rStrm )
440 sax_fastparser::FSHelperPtr pWorksheet = rStrm.GetCurrentStream();
442 DrawingML aDML(pWorksheet, &rStrm, drawingml::DOCUMENT_XLSX);
443 OUString rId = aDML.WriteImage( maGraphic );
444 pWorksheet->singleElement(XML_picture, FSNS(XML_r, XML_id), rId);
447 XclExpControlHelper::XclExpControlHelper( const XclExpRoot& rRoot ) :
448 XclExpRoot( rRoot ),
449 mnEntryCount( 0 )
453 XclExpControlHelper::~XclExpControlHelper()
457 void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > const & xShape )
459 mxCellLink.reset();
460 mxCellLinkAddress.SetInvalid();
461 mxSrcRange.reset();
462 mnEntryCount = 0;
464 // get control model
465 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
466 if( !xCtrlModel.is() )
467 return;
469 // *** cell link *** ------------------------------------------------------
471 Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
472 if( xBindable.is() )
474 Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
475 if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
477 ScfPropertySet aBindProp( xServInfo );
478 CellAddress aApiAddress;
479 if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
481 ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
482 if( GetTabInfo().IsExportTab( mxCellLinkAddress.Tab() ) )
483 mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, mxCellLinkAddress );
488 // *** source range *** ---------------------------------------------------
490 Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY );
491 if( !xEntrySink.is() )
492 return;
494 Reference< XServiceInfo > xServInfo( xEntrySink->getListEntrySource(), UNO_QUERY );
495 if( !(xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_LISTSOURCE )) )
496 return;
498 ScfPropertySet aSinkProp( xServInfo );
499 CellRangeAddress aApiRange;
500 if( aSinkProp.GetProperty( aApiRange, SC_UNONAME_CELLRANGE ) )
502 ScRange aSrcRange;
503 ScUnoConversion::FillScRange( aSrcRange, aApiRange );
504 if( (aSrcRange.aStart.Tab() == aSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( aSrcRange.aStart.Tab() ) )
505 mxSrcRange = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aSrcRange );
506 mnEntryCount = static_cast< sal_uInt16 >( aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1 );
510 void XclExpControlHelper::WriteFormula( XclExpStream& rStrm, const XclTokenArray& rTokArr )
512 sal_uInt16 nFmlaSize = rTokArr.GetSize();
513 rStrm << nFmlaSize << sal_uInt32( 0 );
514 rTokArr.WriteArray( rStrm );
515 if( nFmlaSize & 1 ) // pad to 16-bit
516 rStrm << sal_uInt8( 0 );
519 void XclExpControlHelper::WriteFormulaSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId, const XclTokenArray& rTokArr )
521 rStrm.StartRecord( nSubRecId, (rTokArr.GetSize() + 5) & ~1 );
522 WriteFormula( rStrm, rTokArr );
523 rStrm.EndRecord();
526 //delete for exporting OCX
527 //#if EXC_EXP_OCX_CTRL
529 XclExpOcxControlObj::XclExpOcxControlObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape,
530 const tools::Rectangle* pChildAnchor, const OUString& rClassName, sal_uInt32 nStrmStart, sal_uInt32 nStrmSize ) :
531 XclObj( rObjMgr, EXC_OBJTYPE_PICTURE, true ),
532 XclExpControlHelper( rObjMgr.GetRoot() ),
533 maClassName( rClassName ),
534 mnStrmStart( nStrmStart ),
535 mnStrmSize( nStrmSize )
537 ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
539 // OBJ record flags
540 SetLocked( true );
541 SetPrintable( aCtrlProp.GetBoolProperty( "Printable" ) );
542 SetAutoFill( false );
543 SetAutoLine( false );
545 // fill DFF property set
546 mrEscherEx.OpenContainer( ESCHER_SpContainer );
547 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl,
548 ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape );
549 tools::Rectangle aDummyRect;
550 EscherPropertyContainer aPropOpt( mrEscherEx.GetGraphicProvider(), mrEscherEx.QueryPictureStream(), aDummyRect );
551 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field
552 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x08000040 );
553 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
555 // #i51348# name of the control, may overwrite shape name
556 OUString aCtrlName;
557 if( aCtrlProp.GetProperty( aCtrlName, "Name" ) && !aCtrlName.isEmpty() )
558 aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
560 // meta file
561 //TODO - needs check
562 Reference< XPropertySet > xShapePS( xShape, UNO_QUERY );
563 if( xShapePS.is() && aPropOpt.CreateGraphicProperties( xShapePS, "MetaFile", false ) )
565 sal_uInt32 nBlipId;
566 if( aPropOpt.GetOpt( ESCHER_Prop_pib, nBlipId ) )
567 aPropOpt.AddOpt( ESCHER_Prop_pictureId, nBlipId );
570 // write DFF property set to stream
571 aPropOpt.Commit( mrEscherEx.GetStream() );
573 // anchor
574 ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
576 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
577 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
578 mrEscherEx.UpdateDffFragmentEnd();
580 // spreadsheet links
581 ConvertSheetLinks( xShape );
584 void XclExpOcxControlObj::WriteSubRecs( XclExpStream& rStrm )
586 // OBJCF - clipboard format
587 rStrm.StartRecord( EXC_ID_OBJCF, 2 );
588 rStrm << sal_uInt16( 2 );
589 rStrm.EndRecord();
591 // OBJFLAGS
592 rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 );
593 rStrm << sal_uInt16( 0x0031 );
594 rStrm.EndRecord();
596 // OBJPICTFMLA
597 XclExpString aClass( maClassName );
598 sal_uInt16 nClassNameSize = static_cast< sal_uInt16 >( aClass.GetSize() );
599 sal_uInt16 nClassNamePad = nClassNameSize & 1;
600 sal_uInt16 nFirstPartSize = 12 + nClassNameSize + nClassNamePad;
602 const XclTokenArray* pCellLink = GetCellLinkTokArr();
603 sal_uInt16 nCellLinkSize = pCellLink ? ((pCellLink->GetSize() + 7) & 0xFFFE) : 0;
605 const XclTokenArray* pSrcRange = GetSourceRangeTokArr();
606 sal_uInt16 nSrcRangeSize = pSrcRange ? ((pSrcRange->GetSize() + 7) & 0xFFFE) : 0;
608 sal_uInt16 nPictFmlaSize = nFirstPartSize + nCellLinkSize + nSrcRangeSize + 18;
609 rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nPictFmlaSize );
611 rStrm << nFirstPartSize // size of first part
612 << sal_uInt16( 5 ) // formula size
613 << sal_uInt32( 0 ) // unknown ID
614 << sal_uInt8( 0x02 ) << sal_uInt32( 0 ) // tTbl token with unknown ID
615 << sal_uInt8( 3 ) // pad to word
616 << aClass; // "Forms.***.1"
617 rStrm.WriteZeroBytes( nClassNamePad ); // pad to word
618 rStrm << mnStrmStart // start in 'Ctls' stream
619 << mnStrmSize // size in 'Ctls' stream
620 << sal_uInt32( 0 ); // class ID size
621 // cell link
622 rStrm << nCellLinkSize;
623 if( pCellLink )
624 WriteFormula( rStrm, *pCellLink );
625 // list source range
626 rStrm << nSrcRangeSize;
627 if( pSrcRange )
628 WriteFormula( rStrm, *pSrcRange );
630 rStrm.EndRecord();
633 //#else
635 XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference< XShape > const & xShape , const tools::Rectangle* pChildAnchor ) :
636 XclObj( rRoot, EXC_OBJTYPE_UNKNOWN, true ),
637 XclMacroHelper( rRoot ),
638 mxShape( xShape ),
639 meEventType( EXC_TBX_EVENT_ACTION ),
640 mnHeight( 0 ),
641 mnState( 0 ),
642 mnLineCount( 0 ),
643 mnSelEntry( 0 ),
644 mnScrollValue( 0 ),
645 mnScrollMin( 0 ),
646 mnScrollMax( 100 ),
647 mnScrollStep( 1 ),
648 mnScrollPage( 10 ),
649 mbFlatButton( false ),
650 mbFlatBorder( false ),
651 mbMultiSel( false ),
652 mbScrollHor( false ),
653 mbPrint( false ),
654 mbVisible( false ),
655 mnShapeId( 0 ),
656 mrRoot(rRoot)
658 namespace FormCompType = css::form::FormComponentType;
659 namespace AwtVisualEffect = css::awt::VisualEffect;
660 namespace AwtScrollOrient = css::awt::ScrollBarOrientation;
662 ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
663 if( !xShape.is() || !aCtrlProp.Is() )
664 return;
666 mnHeight = xShape->getSize().Height;
667 if( mnHeight <= 0 )
668 return;
670 // control type
671 sal_Int16 nClassId = 0;
672 if( aCtrlProp.GetProperty( nClassId, "ClassId" ) )
674 switch( nClassId )
676 case FormCompType::COMMANDBUTTON: mnObjType = EXC_OBJTYPE_BUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
677 case FormCompType::RADIOBUTTON: mnObjType = EXC_OBJTYPE_OPTIONBUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
678 case FormCompType::CHECKBOX: mnObjType = EXC_OBJTYPE_CHECKBOX; meEventType = EXC_TBX_EVENT_ACTION; break;
679 case FormCompType::LISTBOX: mnObjType = EXC_OBJTYPE_LISTBOX; meEventType = EXC_TBX_EVENT_CHANGE; break;
680 case FormCompType::COMBOBOX: mnObjType = EXC_OBJTYPE_DROPDOWN; meEventType = EXC_TBX_EVENT_CHANGE; break;
681 case FormCompType::GROUPBOX: mnObjType = EXC_OBJTYPE_GROUPBOX; meEventType = EXC_TBX_EVENT_MOUSE; break;
682 case FormCompType::FIXEDTEXT: mnObjType = EXC_OBJTYPE_LABEL; meEventType = EXC_TBX_EVENT_MOUSE; break;
683 case FormCompType::SCROLLBAR: mnObjType = EXC_OBJTYPE_SCROLLBAR; meEventType = EXC_TBX_EVENT_VALUE; break;
684 case FormCompType::SPINBUTTON: mnObjType = EXC_OBJTYPE_SPIN; meEventType = EXC_TBX_EVENT_VALUE; break;
687 if( mnObjType == EXC_OBJTYPE_UNKNOWN )
688 return;
690 // OBJ record flags
691 SetLocked( true );
692 mbPrint = aCtrlProp.GetBoolProperty( "Printable" );
693 SetPrintable( mbPrint );
694 SetAutoFill( false );
695 SetAutoLine( false );
697 // fill DFF property set
698 mrEscherEx.OpenContainer( ESCHER_SpContainer );
699 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
700 EscherPropertyContainer aPropOpt;
701 mbVisible = aCtrlProp.GetBoolProperty( "EnableVisible" );
702 aPropOpt.AddOpt( ESCHER_Prop_fPrint, mbVisible ? 0x00080000 : 0x00080002 ); // visible flag
704 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01000100 ); // bool field
705 aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 ); // Text ID
706 aPropOpt.AddOpt( ESCHER_Prop_WrapText, 0x00000001 );
707 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x001A0008 ); // bool field
708 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00100000 ); // bool field
709 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
711 // #i51348# name of the control, may overwrite shape name
712 if( aCtrlProp.GetProperty( msCtrlName, "Name" ) && !msCtrlName.isEmpty() )
713 aPropOpt.AddOpt( ESCHER_Prop_wzName, msCtrlName );
715 //Export description as alt text
716 if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
718 OUString aAltTxt;
719 OUString aDescrText = pSdrObj->GetDescription();
720 if(!aDescrText.isEmpty())
721 aAltTxt = aDescrText.copy( 0, std::min<sal_Int32>(MSPROP_DESCRIPTION_MAX_LEN, aDescrText.getLength()) );
722 aPropOpt.AddOpt( ESCHER_Prop_wzDescription, aAltTxt );
725 // write DFF property set to stream
726 aPropOpt.Commit( mrEscherEx.GetStream() );
728 // anchor
729 ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
731 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
732 mrEscherEx.UpdateDffFragmentEnd();
734 // control label
735 if( aCtrlProp.GetProperty( msLabel, "Label" ) )
737 /* Be sure to construct the MSODRAWING record containing the
738 ClientTextbox atom after the base OBJ's MSODRAWING record data is
739 completed. */
740 pClientTextbox.reset( new XclExpMsoDrawing( mrEscherEx ) );
741 mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record
742 mrEscherEx.UpdateDffFragmentEnd();
744 sal_uInt16 nXclFont = EXC_FONT_APP;
745 if( !msLabel.isEmpty() )
747 XclFontData aFontData;
748 GetFontPropSetHelper().ReadFontProperties( aFontData, aCtrlProp, EXC_FONTPROPSET_CONTROL );
749 if( (!aFontData.maName.isEmpty() ) && (aFontData.mnHeight > 0) )
750 nXclFont = GetFontBuffer().Insert( aFontData, EXC_COLOR_CTRLTEXT );
753 pTxo.reset( new XclTxo( msLabel, nXclFont ) );
754 pTxo->SetHorAlign( (mnObjType == EXC_OBJTYPE_BUTTON) ? EXC_OBJ_HOR_CENTER : EXC_OBJ_HOR_LEFT );
755 pTxo->SetVerAlign( EXC_OBJ_VER_CENTER );
758 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
760 // other properties
761 aCtrlProp.GetProperty( mnLineCount, "LineCount" );
763 // border style
764 sal_Int16 nApiButton = AwtVisualEffect::LOOK3D;
765 sal_Int16 nApiBorder = AwtVisualEffect::LOOK3D;
766 switch( nClassId )
768 case FormCompType::LISTBOX:
769 case FormCompType::COMBOBOX:
770 aCtrlProp.GetProperty( nApiBorder, "Border" );
771 break;
772 case FormCompType::CHECKBOX:
773 case FormCompType::RADIOBUTTON:
774 aCtrlProp.GetProperty( nApiButton, "VisualEffect" );
775 nApiBorder = AwtVisualEffect::NONE;
776 break;
777 // Push button cannot be set to flat in Excel
778 case FormCompType::COMMANDBUTTON:
779 nApiBorder = AwtVisualEffect::LOOK3D;
780 break;
781 // Label does not support a border in Excel
782 case FormCompType::FIXEDTEXT:
783 nApiBorder = AwtVisualEffect::NONE;
784 break;
785 /* Scroll bar and spin button have a "Border" property, but it is
786 really used for a border, and not for own 3D/flat look (#i34712#). */
787 case FormCompType::SCROLLBAR:
788 case FormCompType::SPINBUTTON:
789 nApiButton = AwtVisualEffect::LOOK3D;
790 nApiBorder = AwtVisualEffect::NONE;
791 break;
792 // Group box does not support flat style (#i34712#)
793 case FormCompType::GROUPBOX:
794 nApiBorder = AwtVisualEffect::LOOK3D;
795 break;
797 mbFlatButton = nApiButton != AwtVisualEffect::LOOK3D;
798 mbFlatBorder = nApiBorder != AwtVisualEffect::LOOK3D;
800 // control state
801 sal_Int16 nApiState = 0;
802 if( aCtrlProp.GetProperty( nApiState, "State" ) )
804 switch( nApiState )
806 case 0: mnState = EXC_OBJ_CHECKBOX_UNCHECKED; break;
807 case 1: mnState = EXC_OBJ_CHECKBOX_CHECKED; break;
808 case 2: mnState = EXC_OBJ_CHECKBOX_TRISTATE; break;
812 // special control contents
813 switch( nClassId )
815 case FormCompType::LISTBOX:
817 mbMultiSel = aCtrlProp.GetBoolProperty( "MultiSelection" );
818 Sequence< sal_Int16 > aSelection;
819 if( aCtrlProp.GetProperty( aSelection, "SelectedItems" ) )
821 if( aSelection.hasElements() )
823 mnSelEntry = aSelection[ 0 ] + 1;
824 comphelper::sequenceToContainer(maMultiSel, aSelection);
828 // convert listbox with dropdown button to Excel dropdown
829 if( aCtrlProp.GetBoolProperty( "Dropdown" ) )
830 mnObjType = EXC_OBJTYPE_DROPDOWN;
832 break;
834 case FormCompType::COMBOBOX:
836 Sequence< OUString > aStringList;
837 OUString aDefText;
838 if( aCtrlProp.GetProperty( aStringList, "StringItemList" ) &&
839 aCtrlProp.GetProperty( aDefText, "Text" ) &&
840 aStringList.hasElements() && !aDefText.isEmpty() )
842 auto nIndex = comphelper::findValue(aStringList, aDefText);
843 if( nIndex != -1 )
844 mnSelEntry = static_cast< sal_Int16 >( nIndex + 1 ); // 1-based
845 if( mnSelEntry > 0 )
846 maMultiSel.resize( 1, mnSelEntry - 1 );
849 // convert combobox without dropdown button to Excel listbox
850 if( !aCtrlProp.GetBoolProperty( "Dropdown" ) )
851 mnObjType = EXC_OBJTYPE_LISTBOX;
853 break;
855 case FormCompType::SCROLLBAR:
857 sal_Int32 nApiValue = 0;
858 if( aCtrlProp.GetProperty( nApiValue, "ScrollValueMin" ) )
859 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
860 if( aCtrlProp.GetProperty( nApiValue, "ScrollValueMax" ) )
861 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
862 if( aCtrlProp.GetProperty( nApiValue, "ScrollValue" ) )
863 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
864 if( aCtrlProp.GetProperty( nApiValue, "LineIncrement" ) )
865 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
866 if( aCtrlProp.GetProperty( nApiValue, "BlockIncrement" ) )
867 mnScrollPage = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
868 if( aCtrlProp.GetProperty( nApiValue, "Orientation" ) )
869 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
871 break;
873 case FormCompType::SPINBUTTON:
875 sal_Int32 nApiValue = 0;
876 if( aCtrlProp.GetProperty( nApiValue, "SpinValueMin" ) )
877 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
878 if( aCtrlProp.GetProperty( nApiValue, "SpinValueMax" ) )
879 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
880 if( aCtrlProp.GetProperty( nApiValue, "SpinValue" ) )
881 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
882 if( aCtrlProp.GetProperty( nApiValue, "SpinIncrement" ) )
883 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
884 if( aCtrlProp.GetProperty( nApiValue, "Orientation" ) )
885 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
887 break;
891 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
892 if( xCtrlModel.is() )
894 Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
895 if( xBindable.is() )
897 Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
898 if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
900 ScfPropertySet aBindProp( xServInfo );
901 CellAddress aApiAddress;
902 if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
904 ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
905 if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
906 lcl_GetFromTo( rRoot, pSdrObj->GetLogicRect(), mxCellLinkAddress.Tab(), maAreaFrom, maAreaTo, true );
913 // spreadsheet links
914 ConvertSheetLinks( xShape );
917 bool XclExpTbxControlObj::SetMacroLink( const ScriptEventDescriptor& rEvent )
919 return XclMacroHelper::SetMacroLink( rEvent, meEventType );
922 void XclExpTbxControlObj::WriteSubRecs( XclExpStream& rStrm )
924 switch( mnObjType )
926 // *** Push buttons, labels ***
928 case EXC_OBJTYPE_BUTTON:
929 case EXC_OBJTYPE_LABEL:
930 // ftMacro - macro link
931 WriteMacroSubRec( rStrm );
932 break;
934 // *** Check boxes, option buttons ***
936 case EXC_OBJTYPE_CHECKBOX:
937 case EXC_OBJTYPE_OPTIONBUTTON:
939 // ftCbls - box properties
940 sal_uInt16 nStyle = 0;
941 ::set_flag( nStyle, EXC_OBJ_CHECKBOX_FLAT, mbFlatButton );
943 rStrm.StartRecord( EXC_ID_OBJCBLS, 12 );
944 rStrm << mnState;
945 rStrm.WriteZeroBytes( 8 );
946 rStrm << nStyle;
947 rStrm.EndRecord();
949 // ftMacro - macro link
950 WriteMacroSubRec( rStrm );
951 // ftCblsFmla subrecord - cell link
952 WriteCellLinkSubRec( rStrm, EXC_ID_OBJCBLSFMLA );
954 // ftCblsData subrecord - box properties, again
955 rStrm.StartRecord( EXC_ID_OBJCBLS, 8 );
956 rStrm << mnState;
957 rStrm.WriteZeroBytes( 4 );
958 rStrm << nStyle;
959 rStrm.EndRecord();
961 break;
963 // *** List boxes, combo boxes ***
965 case EXC_OBJTYPE_LISTBOX:
966 case EXC_OBJTYPE_DROPDOWN:
968 sal_uInt16 nEntryCount = GetSourceEntryCount();
970 // ftSbs subrecord - Scroll bars
971 sal_Int32 nLineHeight = XclTools::GetHmmFromTwips( 200 ); // always 10pt
972 if( mnObjType == EXC_OBJTYPE_LISTBOX )
973 mnLineCount = static_cast< sal_uInt16 >( mnHeight / nLineHeight );
974 mnScrollValue = 0;
975 mnScrollMin = 0;
976 sal_uInt16 nInvisLines = (nEntryCount >= mnLineCount) ? (nEntryCount - mnLineCount) : 0;
977 mnScrollMax = limit_cast< sal_uInt16 >( nInvisLines, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
978 mnScrollStep = 1;
979 mnScrollPage = limit_cast< sal_uInt16 >( mnLineCount, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
980 mbScrollHor = false;
981 WriteSbs( rStrm );
983 // ftMacro - macro link
984 WriteMacroSubRec( rStrm );
985 // ftSbsFmla subrecord - cell link
986 WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
988 // ftLbsData - source data range and box properties
989 sal_uInt16 nStyle = 0;
990 ::insert_value( nStyle, mbMultiSel ? EXC_OBJ_LISTBOX_MULTI : EXC_OBJ_LISTBOX_SINGLE, 4, 2 );
991 ::set_flag( nStyle, EXC_OBJ_LISTBOX_FLAT, mbFlatBorder );
993 rStrm.StartRecord( EXC_ID_OBJLBSDATA, 0 );
995 if( const XclTokenArray* pSrcRange = GetSourceRangeTokArr() )
997 rStrm << static_cast< sal_uInt16 >( (pSrcRange->GetSize() + 7) & 0xFFFE );
998 WriteFormula( rStrm, *pSrcRange );
1000 else
1001 rStrm << sal_uInt16( 0 );
1003 rStrm << nEntryCount << mnSelEntry << nStyle << sal_uInt16( 0 );
1004 if( mnObjType == EXC_OBJTYPE_LISTBOX )
1006 if( nEntryCount )
1008 ScfUInt8Vec aSelEx( nEntryCount, 0 );
1009 for( const auto& rItem : maMultiSel )
1010 if( rItem < nEntryCount )
1011 aSelEx[ rItem ] = 1;
1012 rStrm.Write( aSelEx.data(), aSelEx.size() );
1015 else if( mnObjType == EXC_OBJTYPE_DROPDOWN )
1017 rStrm << sal_uInt16( 0 ) << mnLineCount << sal_uInt16( 0 ) << sal_uInt16( 0 );
1020 rStrm.EndRecord();
1022 break;
1024 // *** Spin buttons, scrollbars ***
1026 case EXC_OBJTYPE_SPIN:
1027 case EXC_OBJTYPE_SCROLLBAR:
1029 // ftSbs subrecord - scroll bars
1030 WriteSbs( rStrm );
1031 // ftMacro - macro link
1032 WriteMacroSubRec( rStrm );
1033 // ftSbsFmla subrecord - cell link
1034 WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
1036 break;
1038 // *** Group boxes ***
1040 case EXC_OBJTYPE_GROUPBOX:
1042 // ftMacro - macro link
1043 WriteMacroSubRec( rStrm );
1045 // ftGboData subrecord - group box properties
1046 sal_uInt16 nStyle = 0;
1047 ::set_flag( nStyle, EXC_OBJ_GROUPBOX_FLAT, mbFlatBorder );
1049 rStrm.StartRecord( EXC_ID_OBJGBODATA, 6 );
1050 rStrm << sal_uInt32( 0 )
1051 << nStyle;
1052 rStrm.EndRecord();
1054 break;
1058 void XclExpTbxControlObj::WriteCellLinkSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId )
1060 if( const XclTokenArray* pCellLink = GetCellLinkTokArr() )
1061 WriteFormulaSubRec( rStrm, nSubRecId, *pCellLink );
1064 void XclExpTbxControlObj::WriteSbs( XclExpStream& rStrm )
1066 sal_uInt16 nOrient = 0;
1067 ::set_flag( nOrient, EXC_OBJ_SCROLLBAR_HOR, mbScrollHor );
1068 sal_uInt16 nStyle = EXC_OBJ_SCROLLBAR_DEFFLAGS;
1069 ::set_flag( nStyle, EXC_OBJ_SCROLLBAR_FLAT, mbFlatButton );
1071 rStrm.StartRecord( EXC_ID_OBJSBS, 20 );
1072 rStrm << sal_uInt32( 0 ) // reserved
1073 << mnScrollValue // thumb position
1074 << mnScrollMin // thumb min pos
1075 << mnScrollMax // thumb max pos
1076 << mnScrollStep // line increment
1077 << mnScrollPage // page increment
1078 << nOrient // 0 = vertical, 1 = horizontal
1079 << sal_uInt16( 15 ) // thumb width
1080 << nStyle; // flags/style
1081 rStrm.EndRecord();
1084 void XclExpTbxControlObj::setShapeId(sal_Int32 aShapeId)
1086 mnShapeId = aShapeId;
1089 namespace
1091 /// Handles the VML export of form controls (e.g. checkboxes).
1092 class VmlFormControlExporter : public oox::vml::VMLExport
1094 sal_uInt16 m_nObjType;
1095 tools::Rectangle m_aAreaFrom;
1096 tools::Rectangle m_aAreaTo;
1097 OUString m_aLabel;
1098 OUString m_aMacroName;
1100 public:
1101 VmlFormControlExporter(const sax_fastparser::FSHelperPtr& p, sal_uInt16 nObjType,
1102 const tools::Rectangle& rAreaFrom, const tools::Rectangle& rAreaTo,
1103 const OUString& rLabel, const OUString& rMacroName);
1105 protected:
1106 using VMLExport::StartShape;
1107 sal_Int32 StartShape() override;
1108 using VMLExport::EndShape;
1109 void EndShape(sal_Int32 nShapeElement) override;
1112 VmlFormControlExporter::VmlFormControlExporter(const sax_fastparser::FSHelperPtr& p,
1113 sal_uInt16 nObjType,
1114 const tools::Rectangle& rAreaFrom,
1115 const tools::Rectangle& rAreaTo,
1116 const OUString& rLabel, const OUString& rMacroName)
1117 : VMLExport(p)
1118 , m_nObjType(nObjType)
1119 , m_aAreaFrom(rAreaFrom)
1120 , m_aAreaTo(rAreaTo)
1121 , m_aLabel(rLabel)
1122 , m_aMacroName(rMacroName)
1126 sal_Int32 VmlFormControlExporter::StartShape()
1128 // Host control.
1129 AddShapeAttribute(XML_type, "#_x0000_t201");
1130 return VMLExport::StartShape();
1133 void VmlFormControlExporter::EndShape(sal_Int32 nShapeElement)
1135 sax_fastparser::FSHelperPtr pVmlDrawing = GetFS();
1137 pVmlDrawing->startElement(FSNS(XML_v, XML_textbox));
1138 pVmlDrawing->startElement(XML_div);
1139 pVmlDrawing->write(m_aLabel);
1140 pVmlDrawing->endElement(XML_div);
1141 pVmlDrawing->endElement(FSNS(XML_v, XML_textbox));
1143 OString aObjectType;
1144 switch (m_nObjType)
1146 case EXC_OBJTYPE_CHECKBOX:
1147 aObjectType = "Checkbox";
1148 break;
1149 case EXC_OBJTYPE_BUTTON:
1150 aObjectType = "Button";
1151 break;
1153 pVmlDrawing->startElement(FSNS(XML_x, XML_ClientData), XML_ObjectType, aObjectType);
1154 OString aAnchor
1155 = OString::number(m_aAreaFrom.Left()) + ", " + OString::number(m_aAreaFrom.Top()) + ", "
1156 + OString::number(m_aAreaFrom.Right()) + ", " + OString::number(m_aAreaFrom.Bottom()) + ", "
1157 + OString::number(m_aAreaTo.Left()) + ", " + OString::number(m_aAreaTo.Top()) + ", "
1158 + OString::number(m_aAreaTo.Right()) + ", " + OString::number(m_aAreaTo.Bottom());
1159 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_Anchor), aAnchor);
1161 if (!m_aMacroName.isEmpty())
1163 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_FmlaMacro), m_aMacroName);
1166 // XclExpOcxControlObj::WriteSubRecs() has the same fixed values.
1167 if (m_nObjType == EXC_OBJTYPE_BUTTON)
1169 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_TextHAlign), "Center");
1171 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_TextVAlign), "Center");
1173 pVmlDrawing->endElement(FSNS(XML_x, XML_ClientData));
1174 VMLExport::EndShape(nShapeElement);
1179 /// Save into xl/drawings/vmlDrawing1.vml.
1180 void XclExpTbxControlObj::SaveVml(XclExpXmlStream& rStrm)
1182 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1183 tools::Rectangle aAreaFrom;
1184 tools::Rectangle aAreaTo;
1185 // Unlike XclExpTbxControlObj::SaveXml(), this is not calculated in EMUs.
1186 lcl_GetFromTo(mrRoot, pObj->GetLogicRect(), GetTab(), aAreaFrom, aAreaTo);
1187 VmlFormControlExporter aFormControlExporter(rStrm.GetCurrentStream(), GetObjType(), aAreaFrom,
1188 aAreaTo, msLabel, GetMacroName());
1189 aFormControlExporter.AddSdrObject(*pObj, /*bIsFollowingTextFlow=*/false, /*eHOri=*/-1,
1190 /*eVOri=*/-1, /*eHRel=*/-1, /*eVRel=*/-1,
1191 /*pWrapAttrList=*/nullptr, /*bOOxmlExport=*/true);
1194 // save into xl\drawings\drawing1.xml
1195 void XclExpTbxControlObj::SaveXml( XclExpXmlStream& rStrm )
1197 sax_fastparser::FSHelperPtr& pDrawing = rStrm.GetCurrentStream();
1199 pDrawing->startElement(FSNS(XML_mc, XML_AlternateContent),
1200 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)));
1201 pDrawing->startElement(FSNS(XML_mc, XML_Choice),
1202 FSNS(XML_xmlns, XML_a14), rStrm.getNamespaceURL(OOX_NS(a14)),
1203 XML_Requires, "a14");
1205 pDrawing->startElement(FSNS(XML_xdr, XML_twoCellAnchor), XML_editAs, "oneCell");
1207 pDrawing->startElement(FSNS(XML_xdr, XML_from));
1208 lcl_WriteAnchorVertex(pDrawing, maAreaFrom);
1209 pDrawing->endElement(FSNS(XML_xdr, XML_from));
1210 pDrawing->startElement(FSNS(XML_xdr, XML_to));
1211 lcl_WriteAnchorVertex(pDrawing, maAreaTo);
1212 pDrawing->endElement(FSNS(XML_xdr, XML_to));
1214 pDrawing->startElement(FSNS(XML_xdr, XML_sp));
1216 // xdr:nvSpPr
1217 pDrawing->startElement(FSNS(XML_xdr, XML_nvSpPr));
1219 pDrawing->singleElement(FSNS(XML_xdr, XML_cNvPr),
1220 XML_id, OString::number(mnShapeId).getStr(),
1221 XML_name, msCtrlName, // control name
1222 XML_descr, msLabel, // description as alt text
1223 XML_hidden, mbVisible ? "0" : "1");
1224 pDrawing->singleElement(FSNS(XML_xdr, XML_cNvSpPr));
1226 pDrawing->endElement(FSNS(XML_xdr, XML_nvSpPr));
1228 // xdr:spPr
1229 pDrawing->startElement(FSNS(XML_xdr, XML_spPr));
1231 // a:xfrm
1232 pDrawing->startElement(FSNS(XML_a, XML_xfrm));
1234 pDrawing->singleElement(FSNS(XML_a, XML_off),
1235 XML_x, "0",
1236 XML_y, "0");
1237 pDrawing->singleElement(FSNS(XML_a, XML_ext),
1238 XML_cx, "0",
1239 XML_cy, "0");
1241 pDrawing->endElement(FSNS(XML_a, XML_xfrm));
1243 // a:prstGeom
1244 pDrawing->startElement(FSNS(XML_a, XML_prstGeom), XML_prst, "rect");
1246 pDrawing->singleElement(FSNS(XML_a, XML_avLst));
1248 pDrawing->endElement(FSNS(XML_a, XML_prstGeom));
1250 pDrawing->endElement(FSNS(XML_xdr, XML_spPr));
1252 // xdr:txBody
1254 pDrawing->startElement(FSNS(XML_xdr, XML_txBody));
1256 #define DEFLRINS 254
1257 #define DEFTBINS 127
1258 sal_Int32 nLeft, nRight, nTop, nBottom;
1259 nLeft = nRight = DEFLRINS;
1260 nTop = nBottom = DEFTBINS;
1262 // top inset looks a bit different compared to ppt export
1263 // check if something related doesn't work as expected
1264 Reference< XPropertySet > rXPropSet(mxShape, UNO_QUERY);
1268 css::uno::Any mAny;
1270 mAny = rXPropSet->getPropertyValue("TextLeftDistance");
1271 if (mAny.hasValue())
1272 mAny >>= nLeft;
1274 mAny = rXPropSet->getPropertyValue("TextRightDistance");
1275 if (mAny.hasValue())
1276 mAny >>= nRight;
1278 mAny = rXPropSet->getPropertyValue("TextUpperDistance");
1279 if (mAny.hasValue())
1280 mAny >>= nTop;
1282 mAny = rXPropSet->getPropertyValue("TextLowerDistance");
1283 if (mAny.hasValue())
1284 mAny >>= nBottom;
1286 catch (...)
1290 // Specifies the inset of the bounding rectangle.
1291 // Insets are used just as internal margins for text boxes within shapes.
1292 // If this attribute is omitted, then a value of 45720 or 0.05 inches is implied.
1293 pDrawing->startElementNS(XML_a, XML_bodyPr,
1294 XML_lIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nLeft)), nLeft != DEFLRINS),
1295 XML_rIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nRight)), nRight != DEFLRINS),
1296 XML_tIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nTop)), nTop != DEFTBINS),
1297 XML_bIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nBottom)), nBottom != DEFTBINS),
1298 XML_anchor, "ctr");
1301 bool bTextAutoGrowHeight = false;
1305 css::uno::Any mAny;
1307 mAny = rXPropSet->getPropertyValue("TextAutoGrowHeight");
1308 if (mAny.hasValue())
1309 mAny >>= bTextAutoGrowHeight;
1311 catch (...)
1315 pDrawing->singleElementNS(XML_a, (bTextAutoGrowHeight ? XML_spAutoFit : XML_noAutofit));
1318 pDrawing->endElementNS(XML_a, XML_bodyPr);
1321 pDrawing->startElementNS(XML_a, XML_p);
1322 pDrawing->startElementNS(XML_a, XML_r);
1323 pDrawing->startElementNS(XML_a, XML_t);
1324 pDrawing->write(msLabel);
1325 pDrawing->endElementNS(XML_a, XML_t);
1326 pDrawing->endElementNS(XML_a, XML_r);
1327 pDrawing->endElementNS(XML_a, XML_p);
1330 pDrawing->endElement(FSNS(XML_xdr, XML_txBody));
1333 pDrawing->endElement(FSNS(XML_xdr, XML_sp));
1334 pDrawing->singleElement(FSNS(XML_xdr, XML_clientData));
1336 pDrawing->endElement(FSNS(XML_xdr, XML_twoCellAnchor));
1337 pDrawing->endElement( FSNS( XML_mc, XML_Choice ) );
1338 pDrawing->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1341 // output into ctrlProp1.xml
1342 OUString XclExpTbxControlObj::SaveControlPropertiesXml(XclExpXmlStream& rStrm) const
1344 OUString sIdFormControlPr;
1346 switch (mnObjType)
1348 case EXC_OBJTYPE_CHECKBOX:
1350 const sal_Int32 nDrawing = DrawingML::getNewDrawingUniqueId();
1351 sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream(
1352 XclXmlUtils::GetStreamName( "xl/", "ctrlProps/ctrlProps", nDrawing ),
1353 XclXmlUtils::GetStreamName( "../", "ctrlProps/ctrlProps", nDrawing ),
1354 rStrm.GetCurrentStream()->getOutputStream(),
1355 "application/vnd.ms-excel.controlproperties+xml",
1356 oox::getRelationship(Relationship::CTRLPROP),
1357 &sIdFormControlPr );
1359 rStrm.PushStream( pFormControl );
1360 // checkbox
1361 // <formControlPr
1362 // xmlns="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
1363 // objectType="CheckBox" checked="Checked" lockText="1" noThreeD="1"/>
1365 pFormControl->write("<formControlPr xmlns=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\" objectType=\"CheckBox\"");
1366 if (mnState == EXC_OBJ_CHECKBOX_CHECKED)
1367 pFormControl->write(" checked=\"Checked\"");
1369 pFormControl->write(" autoLine=\"false\"");
1371 if (mbPrint)
1372 pFormControl->write(" print=\"true\"");
1373 else
1374 pFormControl->write(" print=\"false\"");
1376 if (mxCellLinkAddress.IsValid())
1378 OUString aCellLink = mxCellLinkAddress.Format(ScRefFlags::ADDR_ABS,
1379 &GetDoc(),
1380 ScAddress::Details(::formula::FormulaGrammar::CONV_XL_A1));
1382 // "Sheet1!$C$5"
1383 pFormControl->write(" fmlaLink=\"");
1384 if (aCellLink.indexOf('!') < 0)
1386 pFormControl->write(GetTabInfo().GetScTabName(mxCellLinkAddress.Tab()));
1387 pFormControl->write("!");
1389 pFormControl->write(aCellLink);
1390 pFormControl->write("\"");
1393 pFormControl->write(" lockText=\"1\" noThreeD=\"1\"/>");
1394 rStrm.PopStream();
1396 break;
1398 case EXC_OBJTYPE_BUTTON:
1400 sal_Int32 nDrawing = DrawingML::getNewDrawingUniqueId();
1401 sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream(
1402 XclXmlUtils::GetStreamName("xl/", "ctrlProps/ctrlProps", nDrawing),
1403 XclXmlUtils::GetStreamName("../", "ctrlProps/ctrlProps", nDrawing),
1404 rStrm.GetCurrentStream()->getOutputStream(),
1405 "application/vnd.ms-excel.controlproperties+xml",
1406 oox::getRelationship(Relationship::CTRLPROP), &sIdFormControlPr);
1408 pFormControl->singleElement(XML_formControlPr, XML_xmlns,
1409 rStrm.getNamespaceURL(OOX_NS(xls14Lst)), XML_objectType,
1410 "Button", XML_lockText, "1");
1411 break;
1415 return sIdFormControlPr;
1418 // output into sheet1.xml
1419 void XclExpTbxControlObj::SaveSheetXml(XclExpXmlStream& rStrm, const OUString& aIdFormControlPr) const
1421 switch (mnObjType)
1423 case EXC_OBJTYPE_CHECKBOX:
1425 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1427 rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent),
1428 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)));
1429 rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
1431 rWorksheet->startElement(
1432 XML_control,
1433 XML_shapeId, OString::number(mnShapeId).getStr(),
1434 FSNS(XML_r, XML_id), aIdFormControlPr,
1435 XML_name, msLabel); // text to display with checkbox button
1437 rWorksheet->write("<controlPr defaultSize=\"0\" locked=\"1\" autoFill=\"0\" autoLine=\"0\" autoPict=\"0\"");
1439 if (mbPrint)
1440 rWorksheet->write(" print=\"true\"");
1441 else
1442 rWorksheet->write(" print=\"false\"");
1444 if (!msCtrlName.isEmpty())
1446 rWorksheet->write(" altText=\"");
1447 rWorksheet->write(msCtrlName); // alt text
1448 rWorksheet->write("\"");
1451 rWorksheet->write(">");
1453 rWorksheet->startElement(XML_anchor, XML_moveWithCells, "true", XML_sizeWithCells, "false");
1454 rWorksheet->startElement(XML_from);
1455 lcl_WriteAnchorVertex(rWorksheet, maAreaFrom);
1456 rWorksheet->endElement(XML_from);
1457 rWorksheet->startElement(XML_to);
1458 lcl_WriteAnchorVertex(rWorksheet, maAreaTo);
1459 rWorksheet->endElement(XML_to);
1460 rWorksheet->endElement( XML_anchor );
1462 rWorksheet->write("</controlPr>");
1464 rWorksheet->endElement(XML_control);
1465 rWorksheet->endElement( FSNS( XML_mc, XML_Choice ) );
1466 rWorksheet->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1468 break;
1470 case EXC_OBJTYPE_BUTTON:
1472 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1474 rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent), FSNS(XML_xmlns, XML_mc),
1475 rStrm.getNamespaceURL(OOX_NS(mce)));
1476 rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
1478 rWorksheet->startElement(XML_control, XML_shapeId, OString::number(mnShapeId).getStr(),
1479 FSNS(XML_r, XML_id), aIdFormControlPr, XML_name, msCtrlName);
1481 OString aMacroName = GetMacroName().toUtf8();
1482 // Omit the macro attribute if it would be empty.
1483 const char* pMacroName = aMacroName.isEmpty() ? nullptr : aMacroName.getStr();
1484 rWorksheet->startElement(XML_controlPr, XML_defaultSize, "0", XML_print,
1485 mbPrint ? "true" : "false", XML_autoFill, "0", XML_autoPict,
1486 "0", XML_macro, pMacroName);
1488 rWorksheet->startElement(XML_anchor, XML_moveWithCells, "true", XML_sizeWithCells,
1489 "false");
1491 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1492 tools::Rectangle aAreaFrom;
1493 tools::Rectangle aAreaTo;
1494 lcl_GetFromTo(mrRoot, pObj->GetLogicRect(), GetTab(), aAreaFrom, aAreaTo,
1495 /*bInEMU=*/true);
1497 rWorksheet->startElement(XML_from);
1498 lcl_WriteAnchorVertex(rWorksheet, aAreaFrom);
1499 rWorksheet->endElement(XML_from);
1500 rWorksheet->startElement(XML_to);
1501 lcl_WriteAnchorVertex(rWorksheet, aAreaTo);
1502 rWorksheet->endElement(XML_to);
1503 rWorksheet->endElement(XML_anchor);
1505 rWorksheet->endElement(XML_controlPr);
1507 rWorksheet->endElement(XML_control);
1508 rWorksheet->endElement(FSNS(XML_mc, XML_Choice));
1509 rWorksheet->endElement(FSNS(XML_mc, XML_AlternateContent));
1510 break;
1515 //#endif
1517 XclExpChartObj::XclExpChartObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor, ScDocument* pDoc ) :
1518 XclObj( rObjMgr, EXC_OBJTYPE_CHART ),
1519 XclExpRoot( rObjMgr.GetRoot() ), mxShape( xShape ),
1520 mpDoc(pDoc)
1522 // create the MSODRAWING record contents for the chart object
1523 mrEscherEx.OpenContainer( ESCHER_SpContainer );
1524 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
1525 EscherPropertyContainer aPropOpt;
1526 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 );
1527 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 );
1528 aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x0800004E );
1529 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x0800004D );
1530 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 );
1531 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x0800004D );
1532 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080008 );
1533 aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00020000 );
1534 aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 );
1535 aPropOpt.Commit( mrEscherEx.GetStream() );
1537 // anchor
1538 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
1539 ImplWriteAnchor( pSdrObj, pChildAnchor );
1541 // client data (the following OBJ record)
1542 mrEscherEx.AddAtom( 0, ESCHER_ClientData );
1543 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
1544 mrEscherEx.UpdateDffFragmentEnd();
1546 // load the chart OLE object
1547 if( SdrOle2Obj* pSdrOleObj = dynamic_cast< SdrOle2Obj* >( pSdrObj ) )
1548 svt::EmbeddedObjectRef::TryRunningState( pSdrOleObj->GetObjRef() );
1550 // create the chart substream object
1551 ScfPropertySet aShapeProp( xShape );
1552 css::awt::Rectangle aBoundRect;
1553 aShapeProp.GetProperty( aBoundRect, "BoundRect" );
1554 tools::Rectangle aChartRect( Point( aBoundRect.X, aBoundRect.Y ), Size( aBoundRect.Width, aBoundRect.Height ) );
1555 mxChart = std::make_shared<XclExpChart>(GetRoot(), GetChartDoc(), aChartRect);
1558 XclExpChartObj::~XclExpChartObj()
1562 void XclExpChartObj::Save( XclExpStream& rStrm )
1564 // content of OBJ record
1565 XclObj::Save( rStrm );
1566 // chart substream
1567 mxChart->Save( rStrm );
1570 void XclExpChartObj::SaveXml( XclExpXmlStream& rStrm )
1572 sax_fastparser::FSHelperPtr pDrawing = rStrm.GetCurrentStream();
1574 // FIXME: two cell? it seems the two cell anchor is incorrect.
1575 pDrawing->startElement( FSNS( XML_xdr, XML_twoCellAnchor ), // OOXTODO: oneCellAnchor, absoluteAnchor
1576 XML_editAs, "oneCell" );
1577 Reference< XPropertySet > xPropSet( mxShape, UNO_QUERY );
1578 if (xPropSet.is())
1580 XclObjAny::WriteFromTo( rStrm, mxShape, GetTab() );
1581 ChartExport aChartExport(XML_xdr, pDrawing, GetChartDoc(), &rStrm, drawingml::DOCUMENT_XLSX);
1582 auto pURLTransformer = std::make_shared<ScURLTransformer>(*mpDoc);
1583 aChartExport.SetURLTranslator(pURLTransformer);
1584 static sal_Int32 nChartCount = 0;
1585 nChartCount++;
1586 sal_Int32 nID = rStrm.GetUniqueId();
1587 aChartExport.WriteChartObj( mxShape, nID, nChartCount );
1588 // TODO: get the correcto chart number
1591 pDrawing->singleElement( FSNS( XML_xdr, XML_clientData)
1592 // OOXTODO: XML_fLocksWithSheet
1593 // OOXTODO: XML_fPrintsWithSheet
1595 pDrawing->endElement( FSNS( XML_xdr, XML_twoCellAnchor ) );
1598 css::uno::Reference<css::chart::XChartDocument> XclExpChartObj::GetChartDoc() const
1600 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1601 if (!pObj || pObj->GetObjIdentifier() != OBJ_OLE2)
1602 return {};
1603 // May load here - makes sure that we are working with actually loaded OLE object
1604 return css::uno::Reference<css::chart::XChartDocument>(
1605 static_cast<SdrOle2Obj*>(pObj)->getXModel(), css::uno::UNO_QUERY);
1608 XclExpNote::XclExpNote(const XclExpRoot& rRoot, const ScAddress& rScPos,
1609 const ScPostIt* pScNote, std::u16string_view rAddText)
1610 : XclExpRecord(EXC_ID_NOTE)
1611 , mrRoot(rRoot)
1612 , maScPos(rScPos)
1613 , mnObjId(EXC_OBJ_INVALID_ID)
1614 , mbVisible(pScNote && pScNote->IsCaptionShown())
1615 , meTHA(SDRTEXTHORZADJUST_LEFT)
1616 , meTVA(SDRTEXTVERTADJUST_TOP)
1617 , mbAutoScale(false)
1618 , mbLocked(false)
1619 , mbAutoFill(false)
1620 , mbColHidden(false)
1621 , mbRowHidden(false)
1623 // get the main note text
1624 OUString aNoteText;
1625 if( pScNote )
1627 aNoteText = pScNote->GetText();
1628 const EditTextObject *pEditObj = pScNote->GetEditTextObject();
1629 if( pEditObj )
1630 mpNoteContents = XclExpStringHelper::CreateString( rRoot, *pEditObj );
1632 // append additional text
1633 aNoteText = ScGlobal::addToken( aNoteText, rAddText, '\n', 2 );
1635 // initialize record dependent on BIFF type
1636 switch( rRoot.GetBiff() )
1638 case EXC_BIFF5:
1639 maNoteText = OUStringToOString(aNoteText, rRoot.GetTextEncoding());
1640 break;
1642 case EXC_BIFF8:
1644 // TODO: additional text
1645 if( pScNote )
1647 if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ) )
1649 lcl_GetFromTo( rRoot, pCaption->GetLogicRect(), maScPos.Tab(), maCommentFrom, maCommentTo );
1650 if( const OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
1651 mnObjId = rRoot.GetObjectManager().AddObj( std::make_unique<XclObjComment>( rRoot.GetObjectManager(), pCaption->GetLogicRect(), pOPO->GetTextObject(), pCaption, mbVisible, maScPos, maCommentFrom, maCommentTo ) );
1653 SfxItemSet aItemSet = pCaption->GetMergedItemSet();
1654 meTVA = pCaption->GetTextVerticalAdjust();
1655 meTHA = pCaption->GetTextHorizontalAdjust();
1656 mbAutoScale = pCaption->GetFitToSize() != drawing::TextFitToSizeType_NONE;
1657 mbLocked = pCaption->IsMoveProtect() || pCaption->IsResizeProtect();
1659 // AutoFill style would change if Postit.cxx object creation values are changed
1660 OUString aCol(aItemSet.Get(XATTR_FILLCOLOR).GetValue());
1661 mbAutoFill = aCol.isEmpty() && (aItemSet.Get(XATTR_FILLSTYLE).GetValue() == drawing::FillStyle_SOLID);
1662 mbRowHidden = (rRoot.GetDoc().RowHidden(maScPos.Row(),maScPos.Tab()));
1663 mbColHidden = (rRoot.GetDoc().ColHidden(maScPos.Col(),maScPos.Tab()));
1665 // stAuthor (variable): An XLUnicodeString that specifies the name of the comment
1666 // author. String length MUST be greater than or equal to 1 and less than or equal
1667 // to 54.
1668 if( pScNote->GetAuthor().isEmpty() )
1669 maAuthor = XclExpString( " " );
1670 else
1671 maAuthor = XclExpString( pScNote->GetAuthor(), XclStrFlags::NONE, 54 );
1674 SetRecSize( 9 + maAuthor.GetSize() );
1676 break;
1678 default: DBG_ERROR_BIFF();
1682 void XclExpNote::Save( XclExpStream& rStrm )
1684 switch( rStrm.GetRoot().GetBiff() )
1686 case EXC_BIFF5:
1688 // write the NOTE record directly, there may be the need to create more than one
1689 const char* pcBuffer = maNoteText.getStr();
1690 sal_uInt16 nCharsLeft = static_cast< sal_uInt16 >( maNoteText.getLength() );
1692 while( nCharsLeft )
1694 sal_uInt16 nWriteChars = ::std::min( nCharsLeft, EXC_NOTE5_MAXLEN );
1696 rStrm.StartRecord( EXC_ID_NOTE, 6 + nWriteChars );
1697 if( pcBuffer == maNoteText.getStr() )
1699 // first record: row, col, length of complete text
1700 rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
1701 << static_cast< sal_uInt16 >( maScPos.Col() )
1702 << nCharsLeft; // still contains full length
1704 else
1706 // next records: -1, 0, length of current text segment
1707 rStrm << sal_uInt16( 0xFFFF )
1708 << sal_uInt16( 0 )
1709 << nWriteChars;
1711 rStrm.Write( pcBuffer, nWriteChars );
1712 rStrm.EndRecord();
1714 pcBuffer += nWriteChars;
1715 nCharsLeft = nCharsLeft - nWriteChars;
1718 break;
1720 case EXC_BIFF8:
1721 if( mnObjId != EXC_OBJ_INVALID_ID )
1722 XclExpRecord::Save( rStrm );
1723 break;
1725 default: DBG_ERROR_BIFF();
1729 void XclExpNote::WriteBody( XclExpStream& rStrm )
1731 // BIFF5/BIFF7 is written separately
1732 OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
1734 sal_uInt16 nFlags = 0;
1735 ::set_flag( nFlags, EXC_NOTE_VISIBLE, mbVisible );
1737 rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
1738 << static_cast< sal_uInt16 >( maScPos.Col() )
1739 << nFlags
1740 << mnObjId
1741 << maAuthor
1742 << sal_uInt8( 0 );
1745 void XclExpNote::WriteXml( sal_Int32 nAuthorId, XclExpXmlStream& rStrm )
1747 sax_fastparser::FSHelperPtr rComments = rStrm.GetCurrentStream();
1749 rComments->startElement( XML_comment,
1750 XML_ref, XclXmlUtils::ToOString(mrRoot.GetDoc(), maScPos),
1751 XML_authorId, OString::number(nAuthorId)
1752 // OOXTODO: XML_guid
1754 rComments->startElement(XML_text);
1755 // OOXTODO: phoneticPr, rPh, r
1756 if( mpNoteContents )
1757 mpNoteContents->WriteXml( rStrm );
1758 rComments->endElement( XML_text );
1761 Export of commentPr is disabled, since the current (Oct 2010)
1762 version of MSO 2010 doesn't yet support commentPr
1764 #if 1//def XLSX_OOXML_FUTURE
1765 if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1767 rComments->startElement(FSNS(XML_mc, XML_AlternateContent));
1768 rComments->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "v2");
1769 rComments->startElement( XML_commentPr,
1770 XML_autoFill, ToPsz( mbAutoFill ),
1771 XML_autoScale, ToPsz( mbAutoScale ),
1772 XML_colHidden, ToPsz( mbColHidden ),
1773 XML_locked, ToPsz( mbLocked ),
1774 XML_rowHidden, ToPsz( mbRowHidden ),
1775 XML_textHAlign, ToHorizAlign( meTHA ),
1776 XML_textVAlign, ToVertAlign( meTVA ) );
1777 rComments->startElement(XML_anchor, XML_moveWithCells, "false", XML_sizeWithCells, "false");
1778 rComments->startElement(FSNS(XML_xdr, XML_from));
1779 lcl_WriteAnchorVertex( rComments, maCommentFrom );
1780 rComments->endElement( FSNS( XML_xdr, XML_from ) );
1781 rComments->startElement(FSNS(XML_xdr, XML_to));
1782 lcl_WriteAnchorVertex( rComments, maCommentTo );
1783 rComments->endElement( FSNS( XML_xdr, XML_to ) );
1784 rComments->endElement( XML_anchor );
1785 rComments->endElement( XML_commentPr );
1787 rComments->endElement( FSNS( XML_mc, XML_Choice ) );
1788 rComments->startElement(FSNS(XML_mc, XML_Fallback));
1789 // Any fallback code ?
1790 rComments->endElement( FSNS( XML_mc, XML_Fallback ) );
1791 rComments->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1793 #endif
1794 rComments->endElement( XML_comment );
1797 XclMacroHelper::XclMacroHelper( const XclExpRoot& rRoot ) :
1798 XclExpControlHelper( rRoot )
1802 XclMacroHelper::~XclMacroHelper()
1806 void XclMacroHelper::WriteMacroSubRec( XclExpStream& rStrm )
1808 if( mxMacroLink )
1809 WriteFormulaSubRec( rStrm, EXC_ID_OBJMACRO, *mxMacroLink );
1812 const OUString& XclMacroHelper::GetMacroName() const { return maMacroName; }
1814 bool
1815 XclMacroHelper::SetMacroLink( const ScriptEventDescriptor& rEvent, const XclTbxEventType& nEventType )
1817 maMacroName = XclControlHelper::ExtractFromMacroDescriptor(rEvent, nEventType);
1818 if (!maMacroName.isEmpty())
1820 return SetMacroLink(maMacroName);
1822 return false;
1825 bool
1826 XclMacroHelper::SetMacroLink( const OUString& rMacroName )
1828 // OOXML documents do not store any defined name for VBA macros (while BIFF documents do).
1829 bool bOOXML = GetOutput() == EXC_OUTPUT_XML_2007;
1830 if (!rMacroName.isEmpty() && !bOOXML)
1832 sal_uInt16 nExtSheet = GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC );
1833 sal_uInt16 nNameIdx
1834 = GetNameManager().InsertMacroCall(rMacroName, /*bVBasic=*/true, /*bFunc=*/false);
1835 mxMacroLink = GetFormulaCompiler().CreateNameXFormula( nExtSheet, nNameIdx );
1836 return true;
1838 return false;
1841 XclExpShapeObj::XclExpShapeObj( XclExpObjectManager& rRoot, css::uno::Reference< css::drawing::XShape > const & xShape, ScDocument* pDoc ) :
1842 XclObjAny( rRoot, xShape, pDoc ),
1843 XclMacroHelper( rRoot )
1845 if (SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(xShape))
1847 ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pSdrObj );
1848 if ( pInfo && !pInfo->GetMacro().isEmpty() )
1849 // FIXME ooo330-m2: XclControlHelper::GetXclMacroName was removed in upstream sources; they started to call XclTools::GetXclMacroName instead; is this enough? it has only one parameter
1850 // SetMacroLink( XclControlHelper::GetXclMacroName( pInfo->GetMacro(), rRoot.GetDocShell() ) );
1851 SetMacroLink( XclTools::GetXclMacroName( pInfo->GetMacro() ) );
1855 XclExpShapeObj::~XclExpShapeObj()
1859 void XclExpShapeObj::WriteSubRecs( XclExpStream& rStrm )
1861 XclObjAny::WriteSubRecs( rStrm );
1862 WriteMacroSubRec( rStrm );
1865 XclExpComments::XclExpComments( SCTAB nTab, XclExpRecordList< XclExpNote >& rNotes )
1866 : mnTab( nTab ), mrNotes( rNotes )
1870 void XclExpComments::SaveXml( XclExpXmlStream& rStrm )
1872 if( mrNotes.IsEmpty() )
1873 return;
1875 sax_fastparser::FSHelperPtr rComments = rStrm.CreateOutputStream(
1876 XclXmlUtils::GetStreamName( "xl/", "comments", mnTab + 1 ),
1877 XclXmlUtils::GetStreamName( "../", "comments", mnTab + 1 ),
1878 rStrm.GetCurrentStream()->getOutputStream(),
1879 "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
1880 oox::getRelationship(Relationship::COMMENTS));
1881 rStrm.PushStream( rComments );
1883 if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1884 rComments->startElement( XML_comments,
1885 XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)),
1886 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)),
1887 FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)),
1888 FSNS(XML_xmlns, XML_v2), rStrm.getNamespaceURL(OOX_NS(mceTest)),
1889 FSNS( XML_mc, XML_Ignorable ), "v2" );
1890 else
1891 rComments->startElement( XML_comments,
1892 XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)),
1893 FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)) );
1895 rComments->startElement(XML_authors);
1897 typedef std::set<OUString> Authors;
1898 Authors aAuthors;
1900 size_t nNotes = mrNotes.GetSize();
1901 for( size_t i = 0; i < nNotes; ++i )
1903 aAuthors.insert( XclXmlUtils::ToOUString( mrNotes.GetRecord( i )->GetAuthor() ) );
1906 for( const auto& rAuthor : aAuthors )
1908 rComments->startElement(XML_author);
1909 rComments->writeEscaped( rAuthor );
1910 rComments->endElement( XML_author );
1913 rComments->endElement( XML_authors );
1914 rComments->startElement(XML_commentList);
1916 Authors::const_iterator aAuthorsBegin = aAuthors.begin();
1917 for( size_t i = 0; i < nNotes; ++i )
1919 XclExpRecordList< XclExpNote >::RecordRefType xNote = mrNotes.GetRecord( i );
1920 Authors::const_iterator aAuthor = aAuthors.find(
1921 XclXmlUtils::ToOUString( xNote->GetAuthor() ) );
1922 sal_Int32 nAuthorId = distance( aAuthorsBegin, aAuthor );
1923 xNote->WriteXml( nAuthorId, rStrm );
1926 rComments->endElement( XML_commentList );
1927 rComments->endElement( XML_comments );
1929 rStrm.PopStream();
1932 // object manager =============================================================
1934 XclExpObjectManager::XclExpObjectManager( const XclExpRoot& rRoot ) :
1935 XclExpRoot( rRoot )
1937 InitStream( true );
1938 mxEscherEx = std::make_shared<XclEscherEx>( GetRoot(), *this, *mxDffStrm );
1941 XclExpObjectManager::XclExpObjectManager( const XclExpObjectManager& rParent ) :
1942 XclExpRoot( rParent.GetRoot() )
1944 InitStream( false );
1945 mxEscherEx = std::make_shared<XclEscherEx>( GetRoot(), *this, *mxDffStrm, rParent.mxEscherEx.get() );
1948 XclExpObjectManager::~XclExpObjectManager()
1952 XclExpDffAnchorBase* XclExpObjectManager::CreateDffAnchor() const
1954 return new XclExpDffSheetAnchor( GetRoot() );
1957 rtl::Reference< XclExpRecordBase > XclExpObjectManager::CreateDrawingGroup()
1959 return new XclExpMsoDrawingGroup( *mxEscherEx );
1962 void XclExpObjectManager::StartSheet()
1964 mxObjList = new XclExpObjList( GetRoot(), *mxEscherEx );
1967 rtl::Reference< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const SdrPage* pSdrPage )
1969 if( pSdrPage )
1970 mxEscherEx->AddSdrPage( *pSdrPage, GetOutput() != EXC_OUTPUT_BINARY );
1971 // the first dummy object may still be open
1972 OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1973 while( mxEscherEx->GetGroupLevel() )
1974 mxEscherEx->LeaveGroup();
1975 mxObjList->EndSheet();
1976 return mxObjList;
1979 rtl::Reference< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const Reference< XShapes >& rxShapes )
1981 if( rxShapes.is() )
1982 mxEscherEx->AddUnoShapes( rxShapes, GetOutput() != EXC_OUTPUT_BINARY );
1983 // the first dummy object may still be open
1984 OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1985 while( mxEscherEx->GetGroupLevel() )
1986 mxEscherEx->LeaveGroup();
1987 mxObjList->EndSheet();
1988 return mxObjList;
1991 void XclExpObjectManager::EndDocument()
1993 mxEscherEx->EndDocument();
1996 XclExpMsoDrawing* XclExpObjectManager::GetMsodrawingPerSheet()
1998 return mxObjList->GetMsodrawingPerSheet();
2001 bool XclExpObjectManager::HasObj() const
2003 return !mxObjList->empty();
2006 sal_uInt16 XclExpObjectManager::AddObj( std::unique_ptr<XclObj> pObjRec )
2008 return mxObjList->Add( std::move(pObjRec) );
2011 std::unique_ptr<XclObj> XclExpObjectManager::RemoveLastObj()
2013 return mxObjList->pop_back();
2016 void XclExpObjectManager::InitStream( bool bTempFile )
2018 if( bTempFile )
2020 mxTempFile = std::make_shared<::utl::TempFile>();
2021 if( mxTempFile->IsValid() )
2023 mxTempFile->EnableKillingFile();
2024 mxDffStrm = ::utl::UcbStreamHelper::CreateStream( mxTempFile->GetURL(), StreamMode::STD_READWRITE );
2028 if( !mxDffStrm )
2029 mxDffStrm = std::make_unique<SvMemoryStream>();
2031 mxDffStrm->SetEndian( SvStreamEndian::LITTLE );
2034 XclExpEmbeddedObjectManager::XclExpEmbeddedObjectManager(
2035 const XclExpObjectManager& rParent, const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
2036 XclExpObjectManager( rParent ),
2037 maPageSize( rPageSize ),
2038 mnScaleX( nScaleX ),
2039 mnScaleY( nScaleY )
2043 XclExpDffAnchorBase* XclExpEmbeddedObjectManager::CreateDffAnchor() const
2045 return new XclExpDffEmbeddedAnchor( GetRoot(), maPageSize, mnScaleX, mnScaleY );
2048 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */