use insert function instead of for loop
[LibreOffice.git] / sc / source / filter / excel / xeescher.cxx
blob043d78fa89170a4038959730ab2540537e3bd009
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 <utility>
21 #include <xeescher.hxx>
23 #include <com/sun/star/lang/XServiceInfo.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 <unotools/securityoptions.hxx>
42 #include <svtools/embedhlp.hxx>
44 #include <unonames.hxx>
45 #include <convuno.hxx>
46 #include <postit.hxx>
48 #include <fapihelper.hxx>
49 #include <xcl97esc.hxx>
50 #include <xechart.hxx>
51 #include <xeformula.hxx>
52 #include <xehelper.hxx>
53 #include <xelink.hxx>
54 #include <xename.hxx>
55 #include <xestyle.hxx>
56 #include <xllink.hxx>
57 #include <xltools.hxx>
58 #include <userdat.hxx>
59 #include <drwlayer.hxx>
60 #include <svl/itemset.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::awt::XControlModel;
85 using ::com::sun::star::form::binding::XBindableValue;
86 using ::com::sun::star::form::binding::XListEntrySink;
87 using ::com::sun::star::script::ScriptEventDescriptor;
88 using ::com::sun::star::table::CellAddress;
89 using ::com::sun::star::table::CellRangeAddress;
90 using ::oox::drawingml::DrawingML;
91 using ::oox::drawingml::ChartExport;
92 using namespace oox;
94 namespace
97 const char *ToHorizAlign( SdrTextHorzAdjust eAdjust )
99 switch( eAdjust )
101 case SDRTEXTHORZADJUST_CENTER:
102 return "center";
103 case SDRTEXTHORZADJUST_RIGHT:
104 return "right";
105 case SDRTEXTHORZADJUST_BLOCK:
106 return "justify";
107 case SDRTEXTHORZADJUST_LEFT:
108 default:
109 return "left";
113 const char *ToVertAlign( SdrTextVertAdjust eAdjust )
115 switch( eAdjust )
117 case SDRTEXTVERTADJUST_CENTER:
118 return "center";
119 case SDRTEXTVERTADJUST_BOTTOM:
120 return "bottom";
121 case SDRTEXTVERTADJUST_BLOCK:
122 return "justify";
123 case SDRTEXTVERTADJUST_TOP:
124 default:
125 return "top";
129 void lcl_WriteAnchorVertex( sax_fastparser::FSHelperPtr const & rComments, const tools::Rectangle &aRect )
131 rComments->startElement(FSNS(XML_xdr, XML_col));
132 rComments->writeEscaped( OUString::number( aRect.Left() ) );
133 rComments->endElement( FSNS( XML_xdr, XML_col ) );
134 rComments->startElement(FSNS(XML_xdr, XML_colOff));
135 rComments->writeEscaped( OUString::number( aRect.Top() ) );
136 rComments->endElement( FSNS( XML_xdr, XML_colOff ) );
137 rComments->startElement(FSNS(XML_xdr, XML_row));
138 rComments->writeEscaped( OUString::number( aRect.Right() ) );
139 rComments->endElement( FSNS( XML_xdr, XML_row ) );
140 rComments->startElement(FSNS(XML_xdr, XML_rowOff));
141 rComments->writeEscaped( OUString::number( aRect.Bottom() ) );
142 rComments->endElement( FSNS( XML_xdr, XML_rowOff ) );
145 tools::Long lcl_hmm2output(tools::Long value, bool bInEMU)
147 return o3tl::convert(value, o3tl::Length::mm100, bInEMU ? o3tl::Length::emu : o3tl::Length::px);
150 void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_Int32 nTab, tools::Rectangle &aFrom, tools::Rectangle &aTo, bool bInEMU = false )
152 sal_Int32 nCol = 0, nRow = 0;
153 sal_Int32 nColOff = 0, nRowOff= 0;
155 const bool bRTL = rRoot.GetDoc().IsNegativePage( nTab );
156 if (!bRTL)
158 while(true)
160 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
161 if( r.Left() <= aRect.Left() )
163 nCol++;
164 nColOff = aRect.Left() - r.Left();
166 if( r.Top() <= aRect.Top() )
168 nRow++;
169 nRowOff = aRect.Top() - r.Top();
171 if( r.Left() > aRect.Left() && r.Top() > aRect.Top() )
173 aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
174 nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
175 break;
179 else
181 while(true)
183 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
184 if( r.Left() >= aRect.Left() )
186 nCol++;
187 nColOff = r.Left() - aRect.Left();
189 if( r.Top() <= aRect.Top() )
191 nRow++;
192 nRowOff = aRect.Top() - r.Top();
194 if( r.Left() < aRect.Left() && r.Top() > aRect.Top() )
196 aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
197 nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
198 break;
202 if (!bRTL)
204 while(true)
206 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
207 if( r.Right() < aRect.Right() )
208 nCol++;
209 if( r.Bottom() < aRect.Bottom() )
210 nRow++;
211 if( r.Right() >= aRect.Right() && r.Bottom() >= aRect.Bottom() )
213 aTo = tools::Rectangle( nCol, lcl_hmm2output( aRect.Right() - r.Left(), bInEMU ),
214 nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
215 break;
219 else
221 while(true)
223 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
224 if( r.Right() >= aRect.Right() )
225 nCol++;
226 if( r.Bottom() < aRect.Bottom() )
227 nRow++;
228 if( r.Right() < aRect.Right() && r.Bottom() >= aRect.Bottom() )
230 aTo = tools::Rectangle( nCol, lcl_hmm2output( r.Left() - aRect.Right(), bInEMU ),
231 nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
232 break;
238 } // namespace
240 // Escher client anchor =======================================================
242 XclExpDffAnchorBase::XclExpDffAnchorBase( const XclExpRoot& rRoot, sal_uInt16 nFlags ) :
243 XclExpRoot( rRoot ),
244 mnFlags( nFlags )
248 void XclExpDffAnchorBase::SetFlags( const SdrObject& rSdrObj )
250 ImplSetFlags( rSdrObj );
253 void XclExpDffAnchorBase::SetSdrObject( const SdrObject& rSdrObj )
255 ImplSetFlags( rSdrObj );
256 ImplCalcAnchorRect( rSdrObj.GetCurrentBoundRect(), MapUnit::Map100thMM );
259 void XclExpDffAnchorBase::WriteDffData( EscherEx& rEscherEx ) const
261 rEscherEx.AddAtom( 18, ESCHER_ClientAnchor );
262 rEscherEx.GetStream().WriteUInt16( mnFlags );
263 WriteXclObjAnchor( rEscherEx.GetStream(), maAnchor );
266 void XclExpDffAnchorBase::WriteData( EscherEx& rEscherEx, const tools::Rectangle& rRect )
268 // the passed rectangle is in twips
269 ImplCalcAnchorRect( rRect, MapUnit::MapTwip );
270 WriteDffData( rEscherEx );
273 void XclExpDffAnchorBase::ImplSetFlags( const SdrObject& )
275 OSL_FAIL( "XclExpDffAnchorBase::ImplSetFlags - not implemented" );
278 void XclExpDffAnchorBase::ImplCalcAnchorRect( const tools::Rectangle&, MapUnit )
280 OSL_FAIL( "XclExpDffAnchorBase::ImplCalcAnchorRect - not implemented" );
283 XclExpDffSheetAnchor::XclExpDffSheetAnchor( const XclExpRoot& rRoot ) :
284 XclExpDffAnchorBase( rRoot ),
285 mnScTab( rRoot.GetCurrScTab() )
289 void XclExpDffSheetAnchor::ImplSetFlags( const SdrObject& rSdrObj )
291 // set flags for cell/page anchoring
292 if ( ScDrawLayer::GetAnchorType( rSdrObj ) == SCA_CELL )
293 mnFlags = 0;
294 else
295 mnFlags = EXC_ESC_ANCHOR_LOCKED;
298 void XclExpDffSheetAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
300 maAnchor.SetRect( GetRoot(), mnScTab, rRect, eMapUnit );
303 XclExpDffEmbeddedAnchor::XclExpDffEmbeddedAnchor( const XclExpRoot& rRoot,
304 const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
305 XclExpDffAnchorBase( rRoot ),
306 maPageSize( rPageSize ),
307 mnScaleX( nScaleX ),
308 mnScaleY( nScaleY )
312 void XclExpDffEmbeddedAnchor::ImplSetFlags( const SdrObject& /*rSdrObj*/ )
314 // TODO (unsupported feature): fixed size
317 void XclExpDffEmbeddedAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
319 maAnchor.SetRect( maPageSize, mnScaleX, mnScaleY, rRect, eMapUnit );
322 XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot& rRoot, const tools::Rectangle& rRect ) :
323 XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_SIZELOCKED )
325 maAnchor.SetRect( rRoot, rRoot.GetCurrScTab(), rRect, MapUnit::Map100thMM );
328 XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
329 XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_POSLOCKED )
331 GetAddressConverter().ConvertAddress( maAnchor.maFirst, rScPos, true );
332 maAnchor.maLast.mnCol = maAnchor.maFirst.mnCol + 1;
333 maAnchor.maLast.mnRow = maAnchor.maFirst.mnRow + 1;
334 maAnchor.mnLX = maAnchor.mnTY = maAnchor.mnRX = maAnchor.mnBY = 0;
337 // MSODRAWING* records ========================================================
339 XclExpMsoDrawingBase::XclExpMsoDrawingBase( XclEscherEx& rEscherEx, sal_uInt16 nRecId ) :
340 XclExpRecord( nRecId ),
341 mrEscherEx( rEscherEx ),
342 mnFragmentKey( rEscherEx.InitNextDffFragment() )
346 void XclExpMsoDrawingBase::WriteBody( XclExpStream& rStrm )
348 OSL_ENSURE( mrEscherEx.GetStreamPos() == mrEscherEx.GetDffFragmentPos( mnFragmentKey ),
349 "XclExpMsoDrawingBase::WriteBody - DFF stream position mismatch" );
350 rStrm.CopyFromStream( mrEscherEx.GetStream(), mrEscherEx.GetDffFragmentSize( mnFragmentKey ) );
353 XclExpMsoDrawingGroup::XclExpMsoDrawingGroup( XclEscherEx& rEscherEx ) :
354 XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWINGGROUP )
356 SvStream& rDffStrm = mrEscherEx.GetStream();
358 // write the DGGCONTAINER with some default settings
359 mrEscherEx.OpenContainer( ESCHER_DggContainer );
361 // TODO: stuff the OPT atom with our own document defaults?
362 static const sal_uInt8 spnDffOpt[] = {
363 0xBF, 0x00, 0x08, 0x00, 0x08, 0x00, 0x81, 0x01,
364 0x09, 0x00, 0x00, 0x08, 0xC0, 0x01, 0x40, 0x00,
365 0x00, 0x08
367 mrEscherEx.AddAtom( sizeof( spnDffOpt ), ESCHER_OPT, 3, 3 );
368 rDffStrm.WriteBytes(spnDffOpt, sizeof(spnDffOpt));
370 // SPLITMENUCOLORS contains colors in toolbar
371 static const sal_uInt8 spnDffSplitMenuColors[] = {
372 0x0D, 0x00, 0x00, 0x08, 0x0C, 0x00, 0x00, 0x08,
373 0x17, 0x00, 0x00, 0x08, 0xF7, 0x00, 0x00, 0x10
375 mrEscherEx.AddAtom( sizeof( spnDffSplitMenuColors ), ESCHER_SplitMenuColors, 0, 4 );
376 rDffStrm.WriteBytes(spnDffSplitMenuColors, sizeof(spnDffSplitMenuColors));
378 // close the DGGCONTAINER
379 mrEscherEx.CloseContainer();
380 mrEscherEx.UpdateDffFragmentEnd();
383 XclExpMsoDrawing::XclExpMsoDrawing( XclEscherEx& rEscherEx ) :
384 XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWING )
388 XclExpImgData::XclExpImgData( Graphic aGraphic, sal_uInt16 nRecId ) :
389 maGraphic(std::move( aGraphic )),
390 mnRecId( nRecId )
394 void XclExpImgData::Save( XclExpStream& rStrm )
396 Bitmap aBmp = maGraphic.GetBitmapEx().GetBitmap();
397 if (aBmp.getPixelFormat() != vcl::PixelFormat::N24_BPP)
398 aBmp.Convert( BmpConversion::N24Bit );
400 BitmapScopedReadAccess pAccess(aBmp);
401 if( !pAccess )
402 return;
404 sal_Int32 nWidth = ::std::min< sal_Int32 >( pAccess->Width(), 0xFFFF );
405 sal_Int32 nHeight = ::std::min< sal_Int32 >( pAccess->Height(), 0xFFFF );
406 if( (nWidth <= 0) || (nHeight <= 0) )
407 return;
409 sal_uInt8 nPadding = static_cast< sal_uInt8 >( nWidth & 0x03 );
410 sal_uInt32 nTmpSize = static_cast< sal_uInt32 >( (nWidth * 3 + nPadding) * nHeight + 12 );
412 rStrm.StartRecord( mnRecId, nTmpSize + 4 );
414 rStrm << EXC_IMGDATA_BMP // BMP format
415 << EXC_IMGDATA_WIN // Windows
416 << nTmpSize // size after _this_ field
417 << sal_uInt32( 12 ) // BITMAPCOREHEADER size
418 << static_cast< sal_uInt16 >( nWidth ) // width
419 << static_cast< sal_uInt16 >( nHeight ) // height
420 << sal_uInt16( 1 ) // planes
421 << sal_uInt16( 24 ); // bits per pixel
423 for( sal_Int32 nY = nHeight - 1; nY >= 0; --nY )
425 Scanline pScanline = pAccess->GetScanline( nY );
426 for( sal_Int32 nX = 0; nX < nWidth; ++nX )
428 const BitmapColor aBmpColor = pAccess->GetPixelFromData( pScanline, nX );
429 rStrm << aBmpColor.GetBlue() << aBmpColor.GetGreen() << aBmpColor.GetRed();
431 rStrm.WriteZeroBytes( nPadding );
434 rStrm.EndRecord();
437 void XclExpImgData::SaveXml( XclExpXmlStream& rStrm )
439 sax_fastparser::FSHelperPtr pWorksheet = rStrm.GetCurrentStream();
441 DrawingML aDML(pWorksheet, &rStrm, drawingml::DOCUMENT_XLSX);
442 OUString rId = aDML.writeGraphicToStorage(maGraphic);
443 pWorksheet->singleElement(XML_picture, FSNS(XML_r, XML_id), rId);
446 XclExpControlHelper::XclExpControlHelper( const XclExpRoot& rRoot ) :
447 XclExpRoot( rRoot ),
448 mnEntryCount( 0 )
452 XclExpControlHelper::~XclExpControlHelper()
456 void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > const & xShape )
458 mxCellLink.reset();
459 mxCellLinkAddress.SetInvalid();
460 mxSrcRange.reset();
461 mnEntryCount = 0;
463 // get control model
464 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
465 if( !xCtrlModel.is() )
466 return;
468 // *** cell link *** ------------------------------------------------------
470 Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
471 if( xBindable.is() )
473 Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
474 if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
476 ScfPropertySet aBindProp( xServInfo );
477 CellAddress aApiAddress;
478 if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
480 ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
481 if( GetTabInfo().IsExportTab( mxCellLinkAddress.Tab() ) )
482 mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, mxCellLinkAddress );
487 // *** source range *** ---------------------------------------------------
489 Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY );
490 if( !xEntrySink.is() )
491 return;
493 Reference< XServiceInfo > xServInfo( xEntrySink->getListEntrySource(), UNO_QUERY );
494 if( !(xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_LISTSOURCE )) )
495 return;
497 ScfPropertySet aSinkProp( xServInfo );
498 CellRangeAddress aApiRange;
499 if( aSinkProp.GetProperty( aApiRange, SC_UNONAME_CELLRANGE ) )
501 ScRange aSrcRange;
502 ScUnoConversion::FillScRange( aSrcRange, aApiRange );
503 if( (aSrcRange.aStart.Tab() == aSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( aSrcRange.aStart.Tab() ) )
504 mxSrcRange = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aSrcRange );
505 mnEntryCount = static_cast< sal_uInt16 >( aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1 );
509 void XclExpControlHelper::WriteFormula( XclExpStream& rStrm, const XclTokenArray& rTokArr )
511 sal_uInt16 nFmlaSize = rTokArr.GetSize();
512 rStrm << nFmlaSize << sal_uInt32( 0 );
513 rTokArr.WriteArray( rStrm );
514 if( nFmlaSize & 1 ) // pad to 16-bit
515 rStrm << sal_uInt8( 0 );
518 void XclExpControlHelper::WriteFormulaSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId, const XclTokenArray& rTokArr )
520 rStrm.StartRecord( nSubRecId, (rTokArr.GetSize() + 5) & ~1 );
521 WriteFormula( rStrm, rTokArr );
522 rStrm.EndRecord();
525 //delete for exporting OCX
526 //#if EXC_EXP_OCX_CTRL
528 XclExpOcxControlObj::XclExpOcxControlObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape,
529 const tools::Rectangle* pChildAnchor, OUString aClassName, sal_uInt32 nStrmStart, sal_uInt32 nStrmSize ) :
530 XclObj( rObjMgr, EXC_OBJTYPE_PICTURE, true ),
531 XclExpControlHelper( rObjMgr.GetRoot() ),
532 maClassName(std::move( aClassName )),
533 mnStrmStart( nStrmStart ),
534 mnStrmSize( nStrmSize )
536 ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
538 // OBJ record flags
539 SetLocked( true );
540 SetPrintable( aCtrlProp.GetBoolProperty( u"Printable"_ustr ) );
541 SetAutoFill( false );
542 SetAutoLine( false );
544 // fill DFF property set
545 mrEscherEx.OpenContainer( ESCHER_SpContainer );
546 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl,
547 ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape );
548 tools::Rectangle aDummyRect;
549 EscherPropertyContainer aPropOpt( mrEscherEx.GetGraphicProvider(), mrEscherEx.QueryPictureStream(), aDummyRect );
550 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field
551 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x08000040 );
552 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
554 // #i51348# name of the control, may overwrite shape name
555 OUString aCtrlName;
556 if( aCtrlProp.GetProperty( aCtrlName, u"Name"_ustr ) && !aCtrlName.isEmpty() )
557 aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
559 // meta file
560 //TODO - needs check
561 Reference< XPropertySet > xShapePS( xShape, UNO_QUERY );
562 if( xShapePS.is() && aPropOpt.CreateGraphicProperties( xShapePS, u"MetaFile"_ustr, false ) )
564 sal_uInt32 nBlipId;
565 if( aPropOpt.GetOpt( ESCHER_Prop_pib, nBlipId ) )
566 aPropOpt.AddOpt( ESCHER_Prop_pictureId, nBlipId );
569 // write DFF property set to stream
570 aPropOpt.Commit( mrEscherEx.GetStream() );
572 // anchor
573 ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
575 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
576 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
577 mrEscherEx.UpdateDffFragmentEnd();
579 // spreadsheet links
580 ConvertSheetLinks( xShape );
583 void XclExpOcxControlObj::WriteSubRecs( XclExpStream& rStrm )
585 // OBJCF - clipboard format
586 rStrm.StartRecord( EXC_ID_OBJCF, 2 );
587 rStrm << sal_uInt16( 2 );
588 rStrm.EndRecord();
590 // OBJFLAGS
591 rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 );
592 rStrm << sal_uInt16( 0x0031 );
593 rStrm.EndRecord();
595 // OBJPICTFMLA
596 XclExpString aClass( maClassName );
597 sal_uInt16 nClassNameSize = static_cast< sal_uInt16 >( aClass.GetSize() );
598 sal_uInt16 nClassNamePad = nClassNameSize & 1;
599 sal_uInt16 nFirstPartSize = 12 + nClassNameSize + nClassNamePad;
601 const XclTokenArray* pCellLink = GetCellLinkTokArr();
602 sal_uInt16 nCellLinkSize = pCellLink ? ((pCellLink->GetSize() + 7) & 0xFFFE) : 0;
604 const XclTokenArray* pSrcRange = GetSourceRangeTokArr();
605 sal_uInt16 nSrcRangeSize = pSrcRange ? ((pSrcRange->GetSize() + 7) & 0xFFFE) : 0;
607 sal_uInt16 nPictFmlaSize = nFirstPartSize + nCellLinkSize + nSrcRangeSize + 18;
608 rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nPictFmlaSize );
610 rStrm << nFirstPartSize // size of first part
611 << sal_uInt16( 5 ) // formula size
612 << sal_uInt32( 0 ) // unknown ID
613 << sal_uInt8( 0x02 ) << sal_uInt32( 0 ) // tTbl token with unknown ID
614 << sal_uInt8( 3 ) // pad to word
615 << aClass; // "Forms.***.1"
616 rStrm.WriteZeroBytes( nClassNamePad ); // pad to word
617 rStrm << mnStrmStart // start in 'Ctls' stream
618 << mnStrmSize // size in 'Ctls' stream
619 << sal_uInt32( 0 ); // class ID size
620 // cell link
621 rStrm << nCellLinkSize;
622 if( pCellLink )
623 WriteFormula( rStrm, *pCellLink );
624 // list source range
625 rStrm << nSrcRangeSize;
626 if( pSrcRange )
627 WriteFormula( rStrm, *pSrcRange );
629 rStrm.EndRecord();
632 //#else
634 XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference< XShape > const & xShape , const tools::Rectangle* pChildAnchor ) :
635 XclObj( rRoot, EXC_OBJTYPE_UNKNOWN, true ),
636 XclMacroHelper( rRoot ),
637 mxShape( xShape ),
638 meEventType( EXC_TBX_EVENT_ACTION ),
639 mnHeight( 0 ),
640 mnState( 0 ),
641 mnLineCount( 0 ),
642 mnSelEntry( 0 ),
643 mnScrollValue( 0 ),
644 mnScrollMin( 0 ),
645 mnScrollMax( 100 ),
646 mnScrollStep( 1 ),
647 mnScrollPage( 10 ),
648 mbFlatButton( false ),
649 mbFlatBorder( false ),
650 mbMultiSel( false ),
651 mbScrollHor( false ),
652 mbPrint( false ),
653 mbVisible( false ),
654 mnShapeId( 0 ),
655 mrRoot(rRoot)
657 namespace FormCompType = css::form::FormComponentType;
658 namespace AwtVisualEffect = css::awt::VisualEffect;
659 namespace AwtScrollOrient = css::awt::ScrollBarOrientation;
661 ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
662 if( !xShape.is() || !aCtrlProp.Is() )
663 return;
665 mnHeight = xShape->getSize().Height;
666 if( mnHeight <= 0 )
667 return;
669 // control type
670 sal_Int16 nClassId = 0;
671 if( aCtrlProp.GetProperty( nClassId, u"ClassId"_ustr ) )
673 switch( nClassId )
675 case FormCompType::COMMANDBUTTON: mnObjType = EXC_OBJTYPE_BUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
676 case FormCompType::RADIOBUTTON: mnObjType = EXC_OBJTYPE_OPTIONBUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
677 case FormCompType::CHECKBOX: mnObjType = EXC_OBJTYPE_CHECKBOX; meEventType = EXC_TBX_EVENT_ACTION; break;
678 case FormCompType::LISTBOX: mnObjType = EXC_OBJTYPE_LISTBOX; meEventType = EXC_TBX_EVENT_CHANGE; break;
679 case FormCompType::COMBOBOX: mnObjType = EXC_OBJTYPE_DROPDOWN; meEventType = EXC_TBX_EVENT_CHANGE; break;
680 case FormCompType::GROUPBOX: mnObjType = EXC_OBJTYPE_GROUPBOX; meEventType = EXC_TBX_EVENT_MOUSE; break;
681 case FormCompType::FIXEDTEXT: mnObjType = EXC_OBJTYPE_LABEL; meEventType = EXC_TBX_EVENT_MOUSE; break;
682 case FormCompType::SCROLLBAR: mnObjType = EXC_OBJTYPE_SCROLLBAR; meEventType = EXC_TBX_EVENT_VALUE; break;
683 case FormCompType::SPINBUTTON: mnObjType = EXC_OBJTYPE_SPIN; meEventType = EXC_TBX_EVENT_VALUE; break;
686 if( mnObjType == EXC_OBJTYPE_UNKNOWN )
687 return;
689 // OBJ record flags
690 SetLocked( true );
691 mbPrint = aCtrlProp.GetBoolProperty( u"Printable"_ustr );
692 SetPrintable( mbPrint );
693 SetAutoFill( false );
694 SetAutoLine( false );
696 // fill DFF property set
697 mrEscherEx.OpenContainer( ESCHER_SpContainer );
698 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
699 EscherPropertyContainer aPropOpt;
700 mbVisible = aCtrlProp.GetBoolProperty( u"EnableVisible"_ustr );
701 aPropOpt.AddOpt( ESCHER_Prop_fPrint, mbVisible ? 0x00080000 : 0x00080002 ); // visible flag
703 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01000100 ); // bool field
704 aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 ); // Text ID
705 aPropOpt.AddOpt( ESCHER_Prop_WrapText, 0x00000001 );
706 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x001A0008 ); // bool field
707 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00100000 ); // bool field
708 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
710 // #i51348# name of the control, may overwrite shape name
711 if( aCtrlProp.GetProperty( msCtrlName, u"Name"_ustr ) && !msCtrlName.isEmpty() )
712 aPropOpt.AddOpt( ESCHER_Prop_wzName, msCtrlName );
714 //Export description as alt text
715 if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
717 OUString aAltTxt;
718 OUString aDescrText = pSdrObj->GetDescription();
719 if(!aDescrText.isEmpty())
720 aAltTxt = aDescrText.copy( 0, std::min<sal_Int32>(MSPROP_DESCRIPTION_MAX_LEN, aDescrText.getLength()) );
721 aPropOpt.AddOpt( ESCHER_Prop_wzDescription, aAltTxt );
724 // write DFF property set to stream
725 aPropOpt.Commit( mrEscherEx.GetStream() );
727 // anchor
728 ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
730 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
731 mrEscherEx.UpdateDffFragmentEnd();
733 // control label
734 if( aCtrlProp.GetProperty( msLabel, u"Label"_ustr ) )
736 /* Be sure to construct the MSODRAWING record containing the
737 ClientTextbox atom after the base OBJ's MSODRAWING record data is
738 completed. */
739 pClientTextbox.reset( new XclExpMsoDrawing( mrEscherEx ) );
740 mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record
741 mrEscherEx.UpdateDffFragmentEnd();
743 sal_uInt16 nXclFont = EXC_FONT_APP;
744 if( !msLabel.isEmpty() )
746 XclFontData aFontData;
747 GetFontPropSetHelper().ReadFontProperties( aFontData, aCtrlProp, EXC_FONTPROPSET_CONTROL );
748 if( (!aFontData.maName.isEmpty() ) && (aFontData.mnHeight > 0) )
749 nXclFont = GetFontBuffer().Insert( aFontData, EXC_COLOR_CTRLTEXT );
752 pTxo.reset( new XclTxo( msLabel, nXclFont ) );
753 pTxo->SetHorAlign( (mnObjType == EXC_OBJTYPE_BUTTON) ? EXC_OBJ_HOR_CENTER : EXC_OBJ_HOR_LEFT );
754 pTxo->SetVerAlign( EXC_OBJ_VER_CENTER );
757 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
759 // other properties
760 aCtrlProp.GetProperty( mnLineCount, u"LineCount"_ustr );
762 // border style
763 sal_Int16 nApiButton = AwtVisualEffect::LOOK3D;
764 sal_Int16 nApiBorder = AwtVisualEffect::LOOK3D;
765 switch( nClassId )
767 case FormCompType::LISTBOX:
768 case FormCompType::COMBOBOX:
769 aCtrlProp.GetProperty( nApiBorder, u"Border"_ustr );
770 break;
771 case FormCompType::CHECKBOX:
772 case FormCompType::RADIOBUTTON:
773 aCtrlProp.GetProperty( nApiButton, u"VisualEffect"_ustr );
774 nApiBorder = AwtVisualEffect::NONE;
775 break;
776 // Push button cannot be set to flat in Excel
777 case FormCompType::COMMANDBUTTON:
778 // Group box does not support flat style (#i34712#)
779 case FormCompType::GROUPBOX:
780 nApiBorder = AwtVisualEffect::LOOK3D;
781 break;
782 // Label does not support a border in Excel
783 case FormCompType::FIXEDTEXT:
784 nApiBorder = AwtVisualEffect::NONE;
785 break;
786 /* Scroll bar and spin button have a "Border" property, but it is
787 really used for a border, and not for own 3D/flat look (#i34712#). */
788 case FormCompType::SCROLLBAR:
789 case FormCompType::SPINBUTTON:
790 nApiButton = AwtVisualEffect::LOOK3D;
791 nApiBorder = AwtVisualEffect::NONE;
792 break;
794 mbFlatButton = nApiButton != AwtVisualEffect::LOOK3D;
795 mbFlatBorder = nApiBorder != AwtVisualEffect::LOOK3D;
797 // control state
798 sal_Int16 nApiState = 0;
799 if( aCtrlProp.GetProperty( nApiState, u"State"_ustr ) )
801 switch( nApiState )
803 case 0: mnState = EXC_OBJ_CHECKBOX_UNCHECKED; break;
804 case 1: mnState = EXC_OBJ_CHECKBOX_CHECKED; break;
805 case 2: mnState = EXC_OBJ_CHECKBOX_TRISTATE; break;
809 // special control contents
810 switch( nClassId )
812 case FormCompType::LISTBOX:
814 mbMultiSel = aCtrlProp.GetBoolProperty( u"MultiSelection"_ustr );
815 Sequence< sal_Int16 > aSelection;
816 if( aCtrlProp.GetProperty( aSelection, u"SelectedItems"_ustr ) )
818 if( aSelection.hasElements() )
820 mnSelEntry = aSelection[ 0 ] + 1;
821 comphelper::sequenceToContainer(maMultiSel, aSelection);
825 // convert listbox with dropdown button to Excel dropdown
826 if( aCtrlProp.GetBoolProperty( u"Dropdown"_ustr ) )
827 mnObjType = EXC_OBJTYPE_DROPDOWN;
829 break;
831 case FormCompType::COMBOBOX:
833 Sequence< OUString > aStringList;
834 OUString aDefText;
835 if( aCtrlProp.GetProperty( aStringList, u"StringItemList"_ustr ) &&
836 aCtrlProp.GetProperty( aDefText, u"Text"_ustr ) &&
837 aStringList.hasElements() && !aDefText.isEmpty() )
839 auto nIndex = comphelper::findValue(aStringList, aDefText);
840 if( nIndex != -1 )
841 mnSelEntry = static_cast< sal_Int16 >( nIndex + 1 ); // 1-based
842 if( mnSelEntry > 0 )
843 maMultiSel.resize( 1, mnSelEntry - 1 );
846 // convert combobox without dropdown button to Excel listbox
847 if( !aCtrlProp.GetBoolProperty( u"Dropdown"_ustr ) )
848 mnObjType = EXC_OBJTYPE_LISTBOX;
850 break;
852 case FormCompType::SCROLLBAR:
854 sal_Int32 nApiValue = 0;
855 if( aCtrlProp.GetProperty( nApiValue, u"ScrollValueMin"_ustr ) )
856 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
857 if( aCtrlProp.GetProperty( nApiValue, u"ScrollValueMax"_ustr ) )
858 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
859 if( aCtrlProp.GetProperty( nApiValue, u"ScrollValue"_ustr ) )
860 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
861 if( aCtrlProp.GetProperty( nApiValue, u"LineIncrement"_ustr ) )
862 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
863 if( aCtrlProp.GetProperty( nApiValue, u"BlockIncrement"_ustr ) )
864 mnScrollPage = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
865 if( aCtrlProp.GetProperty( nApiValue, u"Orientation"_ustr ) )
866 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
868 break;
870 case FormCompType::SPINBUTTON:
872 sal_Int32 nApiValue = 0;
873 if( aCtrlProp.GetProperty( nApiValue, u"SpinValueMin"_ustr ) )
874 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
875 if( aCtrlProp.GetProperty( nApiValue, u"SpinValueMax"_ustr ) )
876 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
877 if( aCtrlProp.GetProperty( nApiValue, u"SpinValue"_ustr ) )
878 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
879 if( aCtrlProp.GetProperty( nApiValue, u"SpinIncrement"_ustr ) )
880 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
881 if( aCtrlProp.GetProperty( nApiValue, u"Orientation"_ustr ) )
882 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
884 break;
888 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
889 if( xCtrlModel.is() )
891 Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
892 if( xBindable.is() )
894 Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
895 if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
897 ScfPropertySet aBindProp( xServInfo );
898 CellAddress aApiAddress;
899 if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
901 ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
902 if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
903 lcl_GetFromTo( rRoot, pSdrObj->GetLogicRect(), mxCellLinkAddress.Tab(), maAreaFrom, maAreaTo, true );
910 // spreadsheet links
911 ConvertSheetLinks( xShape );
914 bool XclExpTbxControlObj::SetMacroLink( const ScriptEventDescriptor& rEvent )
916 return XclMacroHelper::SetMacroLink( rEvent, meEventType );
919 void XclExpTbxControlObj::WriteSubRecs( XclExpStream& rStrm )
921 switch( mnObjType )
923 // *** Push buttons, labels ***
925 case EXC_OBJTYPE_BUTTON:
926 case EXC_OBJTYPE_LABEL:
927 // ftMacro - macro link
928 WriteMacroSubRec( rStrm );
929 break;
931 // *** Check boxes, option buttons ***
933 case EXC_OBJTYPE_CHECKBOX:
934 case EXC_OBJTYPE_OPTIONBUTTON:
936 // ftCbls - box properties
937 sal_uInt16 nStyle = 0;
938 ::set_flag( nStyle, EXC_OBJ_CHECKBOX_FLAT, mbFlatButton );
940 rStrm.StartRecord( EXC_ID_OBJCBLS, 12 );
941 rStrm << mnState;
942 rStrm.WriteZeroBytes( 8 );
943 rStrm << nStyle;
944 rStrm.EndRecord();
946 // ftMacro - macro link
947 WriteMacroSubRec( rStrm );
948 // ftCblsFmla subrecord - cell link
949 WriteCellLinkSubRec( rStrm, EXC_ID_OBJCBLSFMLA );
951 // ftCblsData subrecord - box properties, again
952 rStrm.StartRecord( EXC_ID_OBJCBLS, 8 );
953 rStrm << mnState;
954 rStrm.WriteZeroBytes( 4 );
955 rStrm << nStyle;
956 rStrm.EndRecord();
958 break;
960 // *** List boxes, combo boxes ***
962 case EXC_OBJTYPE_LISTBOX:
963 case EXC_OBJTYPE_DROPDOWN:
965 sal_uInt16 nEntryCount = GetSourceEntryCount();
967 // ftSbs subrecord - Scroll bars
968 sal_Int32 nLineHeight = XclTools::GetHmmFromTwips( 200 ); // always 10pt
969 if( mnObjType == EXC_OBJTYPE_LISTBOX )
970 mnLineCount = static_cast< sal_uInt16 >( mnHeight / nLineHeight );
971 mnScrollValue = 0;
972 mnScrollMin = 0;
973 sal_uInt16 nInvisLines = (nEntryCount >= mnLineCount) ? (nEntryCount - mnLineCount) : 0;
974 mnScrollMax = limit_cast< sal_uInt16 >( nInvisLines, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
975 mnScrollStep = 1;
976 mnScrollPage = limit_cast< sal_uInt16 >( mnLineCount, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
977 mbScrollHor = false;
978 WriteSbs( rStrm );
980 // ftMacro - macro link
981 WriteMacroSubRec( rStrm );
982 // ftSbsFmla subrecord - cell link
983 WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
985 // ftLbsData - source data range and box properties
986 sal_uInt16 nStyle = 0;
987 ::insert_value( nStyle, mbMultiSel ? EXC_OBJ_LISTBOX_MULTI : EXC_OBJ_LISTBOX_SINGLE, 4, 2 );
988 ::set_flag( nStyle, EXC_OBJ_LISTBOX_FLAT, mbFlatBorder );
990 rStrm.StartRecord( EXC_ID_OBJLBSDATA, 0 );
992 if( const XclTokenArray* pSrcRange = GetSourceRangeTokArr() )
994 rStrm << static_cast< sal_uInt16 >( (pSrcRange->GetSize() + 7) & 0xFFFE );
995 WriteFormula( rStrm, *pSrcRange );
997 else
998 rStrm << sal_uInt16( 0 );
1000 rStrm << nEntryCount << mnSelEntry << nStyle << sal_uInt16( 0 );
1001 if( mnObjType == EXC_OBJTYPE_LISTBOX )
1003 if( nEntryCount )
1005 ScfUInt8Vec aSelEx( nEntryCount, 0 );
1006 for( const auto& rItem : maMultiSel )
1007 if( rItem < nEntryCount )
1008 aSelEx[ rItem ] = 1;
1009 rStrm.Write( aSelEx.data(), aSelEx.size() );
1012 else if( mnObjType == EXC_OBJTYPE_DROPDOWN )
1014 rStrm << sal_uInt16( 0 ) << mnLineCount << sal_uInt16( 0 ) << sal_uInt16( 0 );
1017 rStrm.EndRecord();
1019 break;
1021 // *** Spin buttons, scrollbars ***
1023 case EXC_OBJTYPE_SPIN:
1024 case EXC_OBJTYPE_SCROLLBAR:
1026 // ftSbs subrecord - scroll bars
1027 WriteSbs( rStrm );
1028 // ftMacro - macro link
1029 WriteMacroSubRec( rStrm );
1030 // ftSbsFmla subrecord - cell link
1031 WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
1033 break;
1035 // *** Group boxes ***
1037 case EXC_OBJTYPE_GROUPBOX:
1039 // ftMacro - macro link
1040 WriteMacroSubRec( rStrm );
1042 // ftGboData subrecord - group box properties
1043 sal_uInt16 nStyle = 0;
1044 ::set_flag( nStyle, EXC_OBJ_GROUPBOX_FLAT, mbFlatBorder );
1046 rStrm.StartRecord( EXC_ID_OBJGBODATA, 6 );
1047 rStrm << sal_uInt32( 0 )
1048 << nStyle;
1049 rStrm.EndRecord();
1051 break;
1055 void XclExpTbxControlObj::WriteCellLinkSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId )
1057 if( const XclTokenArray* pCellLink = GetCellLinkTokArr() )
1058 WriteFormulaSubRec( rStrm, nSubRecId, *pCellLink );
1061 void XclExpTbxControlObj::WriteSbs( XclExpStream& rStrm )
1063 sal_uInt16 nOrient = 0;
1064 ::set_flag( nOrient, EXC_OBJ_SCROLLBAR_HOR, mbScrollHor );
1065 sal_uInt16 nStyle = EXC_OBJ_SCROLLBAR_DEFFLAGS;
1066 ::set_flag( nStyle, EXC_OBJ_SCROLLBAR_FLAT, mbFlatButton );
1068 rStrm.StartRecord( EXC_ID_OBJSBS, 20 );
1069 rStrm << sal_uInt32( 0 ) // reserved
1070 << mnScrollValue // thumb position
1071 << mnScrollMin // thumb min pos
1072 << mnScrollMax // thumb max pos
1073 << mnScrollStep // line increment
1074 << mnScrollPage // page increment
1075 << nOrient // 0 = vertical, 1 = horizontal
1076 << sal_uInt16( 15 ) // thumb width
1077 << nStyle; // flags/style
1078 rStrm.EndRecord();
1081 void XclExpTbxControlObj::setShapeId(sal_Int32 aShapeId)
1083 mnShapeId = aShapeId;
1086 namespace
1088 /// Handles the VML export of form controls (e.g. checkboxes).
1089 class VmlFormControlExporter : public oox::vml::VMLExport
1091 sal_uInt16 m_nObjType;
1092 tools::Rectangle m_aAreaFrom;
1093 tools::Rectangle m_aAreaTo;
1094 OUString m_sControlName;
1095 OUString m_sFmlaLink;
1096 OUString m_aLabel;
1097 OUString m_aMacroName;
1099 public:
1100 VmlFormControlExporter(const sax_fastparser::FSHelperPtr& p, sal_uInt16 nObjType,
1101 const tools::Rectangle& rAreaFrom, const tools::Rectangle& rAreaTo,
1102 const OUString& sControlName, const OUString& sFmlaLink,
1103 OUString aLabel, OUString aMacroName);
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& sControlName,
1117 const OUString& sFmlaLink,
1118 OUString aLabel, OUString aMacroName)
1119 : VMLExport(p)
1120 , m_nObjType(nObjType)
1121 , m_aAreaFrom(rAreaFrom)
1122 , m_aAreaTo(rAreaTo)
1123 , m_sControlName(sControlName)
1124 , m_sFmlaLink(sFmlaLink)
1125 , m_aLabel(std::move(aLabel))
1126 , m_aMacroName(std::move(aMacroName))
1130 sal_Int32 VmlFormControlExporter::StartShape()
1132 // Host control.
1133 AddShapeAttribute(XML_type, "#_x0000_t201");
1134 if (!m_sControlName.isEmpty())
1135 AddShapeAttribute(XML_id, m_sControlName.toUtf8());
1137 return VMLExport::StartShape();
1140 void VmlFormControlExporter::EndShape(sal_Int32 nShapeElement)
1142 sax_fastparser::FSHelperPtr pVmlDrawing = GetFS();
1144 pVmlDrawing->startElement(FSNS(XML_v, XML_textbox));
1145 pVmlDrawing->startElement(XML_div);
1146 pVmlDrawing->startElement(XML_font);
1147 pVmlDrawing->write(m_aLabel);
1148 pVmlDrawing->endElement(XML_font);
1149 pVmlDrawing->endElement(XML_div);
1150 pVmlDrawing->endElement(FSNS(XML_v, XML_textbox));
1152 OString aObjectType;
1153 switch (m_nObjType)
1155 case EXC_OBJTYPE_CHECKBOX:
1156 aObjectType = "Checkbox"_ostr;
1157 break;
1158 case EXC_OBJTYPE_BUTTON:
1159 aObjectType = "Button"_ostr;
1160 break;
1162 pVmlDrawing->startElement(FSNS(XML_x, XML_ClientData), XML_ObjectType, aObjectType);
1163 OString aAnchor
1164 = OString::number(m_aAreaFrom.Left()) + ", " + OString::number(m_aAreaFrom.Top()) + ", "
1165 + OString::number(m_aAreaFrom.Right()) + ", " + OString::number(m_aAreaFrom.Bottom()) + ", "
1166 + OString::number(m_aAreaTo.Left()) + ", " + OString::number(m_aAreaTo.Top()) + ", "
1167 + OString::number(m_aAreaTo.Right()) + ", " + OString::number(m_aAreaTo.Bottom());
1168 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_Anchor), aAnchor);
1170 if (!m_aMacroName.isEmpty())
1172 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_FmlaMacro), m_aMacroName);
1175 // XclExpOcxControlObj::WriteSubRecs() has the same fixed values.
1176 if (m_nObjType == EXC_OBJTYPE_BUTTON)
1178 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_TextHAlign), "Center");
1180 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_TextVAlign), "Center");
1182 if (!m_sFmlaLink.isEmpty())
1183 XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_FmlaLink), m_sFmlaLink);
1185 pVmlDrawing->endElement(FSNS(XML_x, XML_ClientData));
1186 VMLExport::EndShape(nShapeElement);
1191 /// Save into xl/drawings/vmlDrawing1.vml.
1192 void XclExpTbxControlObj::SaveVml(XclExpXmlStream& rStrm)
1194 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1195 tools::Rectangle aAreaFrom;
1196 tools::Rectangle aAreaTo;
1197 // Unlike XclExpTbxControlObj::SaveXml(), this is not calculated in EMUs.
1198 lcl_GetFromTo(mrRoot, pObj->GetLogicRect(), GetTab(), aAreaFrom, aAreaTo);
1200 const OUString sCellLink
1201 = mxCellLinkAddress.IsValid()
1202 ? mxCellLinkAddress.Format(ScRefFlags::ADDR_ABS, &GetDoc(),
1203 ScAddress::Details(formula::FormulaGrammar::CONV_XL_A1))
1204 : OUString();
1206 VmlFormControlExporter aFormControlExporter(rStrm.GetCurrentStream(), GetObjType(), aAreaFrom,
1207 aAreaTo, msCtrlName, sCellLink, msLabel, GetMacroName());
1208 aFormControlExporter.SetSkipwzName(true); // use XML_id for legacyid, not XML_ID
1209 aFormControlExporter.OverrideShapeIDGen(true, "_x0000_s"_ostr);
1210 aFormControlExporter.AddSdrObject(*pObj, /*bIsFollowingTextFlow=*/false, /*eHOri=*/-1,
1211 /*eVOri=*/-1, /*eHRel=*/-1, /*eVRel=*/-1,
1212 /*pWrapAttrList=*/nullptr, /*bOOxmlExport=*/true, mnShapeId);
1215 // save into xl\drawings\drawing1.xml
1216 void XclExpTbxControlObj::SaveXml( XclExpXmlStream& rStrm )
1218 sax_fastparser::FSHelperPtr& pDrawing = rStrm.GetCurrentStream();
1220 pDrawing->startElement(FSNS(XML_mc, XML_AlternateContent),
1221 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)));
1222 pDrawing->startElement(FSNS(XML_mc, XML_Choice),
1223 FSNS(XML_xmlns, XML_a14), rStrm.getNamespaceURL(OOX_NS(a14)),
1224 XML_Requires, "a14");
1226 pDrawing->startElement(FSNS(XML_xdr, XML_twoCellAnchor), XML_editAs, "oneCell");
1228 pDrawing->startElement(FSNS(XML_xdr, XML_from));
1229 lcl_WriteAnchorVertex(pDrawing, maAreaFrom);
1230 pDrawing->endElement(FSNS(XML_xdr, XML_from));
1231 pDrawing->startElement(FSNS(XML_xdr, XML_to));
1232 lcl_WriteAnchorVertex(pDrawing, maAreaTo);
1233 pDrawing->endElement(FSNS(XML_xdr, XML_to));
1235 pDrawing->startElement(FSNS(XML_xdr, XML_sp));
1237 // xdr:nvSpPr
1238 pDrawing->startElement(FSNS(XML_xdr, XML_nvSpPr));
1240 pDrawing->singleElement(FSNS(XML_xdr, XML_cNvPr),
1241 XML_id, OString::number(mnShapeId),
1242 XML_name, msCtrlName, // control name
1243 XML_descr, msLabel, // description as alt text
1244 XML_hidden, mbVisible ? "0" : "1");
1245 pDrawing->singleElement(FSNS(XML_xdr, XML_cNvSpPr));
1247 pDrawing->endElement(FSNS(XML_xdr, XML_nvSpPr));
1249 // xdr:spPr
1250 pDrawing->startElement(FSNS(XML_xdr, XML_spPr));
1252 // a:xfrm
1253 pDrawing->startElement(FSNS(XML_a, XML_xfrm));
1255 pDrawing->singleElement(FSNS(XML_a, XML_off),
1256 XML_x, "0",
1257 XML_y, "0");
1258 pDrawing->singleElement(FSNS(XML_a, XML_ext),
1259 XML_cx, "0",
1260 XML_cy, "0");
1262 pDrawing->endElement(FSNS(XML_a, XML_xfrm));
1264 // a:prstGeom
1265 pDrawing->startElement(FSNS(XML_a, XML_prstGeom), XML_prst, "rect");
1267 pDrawing->singleElement(FSNS(XML_a, XML_avLst));
1269 pDrawing->endElement(FSNS(XML_a, XML_prstGeom));
1271 pDrawing->endElement(FSNS(XML_xdr, XML_spPr));
1273 // xdr:txBody
1275 pDrawing->startElement(FSNS(XML_xdr, XML_txBody));
1277 #define DEFLRINS 254
1278 #define DEFTBINS 127
1279 sal_Int32 nLeft, nRight, nTop, nBottom;
1280 nLeft = nRight = DEFLRINS;
1281 nTop = nBottom = DEFTBINS;
1283 // top inset looks a bit different compared to ppt export
1284 // check if something related doesn't work as expected
1285 Reference< XPropertySet > rXPropSet(mxShape, UNO_QUERY);
1289 css::uno::Any mAny;
1291 mAny = rXPropSet->getPropertyValue(u"TextLeftDistance"_ustr);
1292 if (mAny.hasValue())
1293 mAny >>= nLeft;
1295 mAny = rXPropSet->getPropertyValue(u"TextRightDistance"_ustr);
1296 if (mAny.hasValue())
1297 mAny >>= nRight;
1299 mAny = rXPropSet->getPropertyValue(u"TextUpperDistance"_ustr);
1300 if (mAny.hasValue())
1301 mAny >>= nTop;
1303 mAny = rXPropSet->getPropertyValue(u"TextLowerDistance"_ustr);
1304 if (mAny.hasValue())
1305 mAny >>= nBottom;
1307 catch (...)
1311 // Specifies the inset of the bounding rectangle.
1312 // Insets are used just as internal margins for text boxes within shapes.
1313 // If this attribute is omitted, then a value of 45720 or 0.05 inches is implied.
1314 pDrawing->startElementNS(XML_a, XML_bodyPr,
1315 XML_lIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nLeft)), nLeft != DEFLRINS),
1316 XML_rIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nRight)), nRight != DEFLRINS),
1317 XML_tIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nTop)), nTop != DEFTBINS),
1318 XML_bIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nBottom)), nBottom != DEFTBINS),
1319 XML_anchor, "ctr");
1322 bool bTextAutoGrowHeight = false;
1326 css::uno::Any mAny;
1328 mAny = rXPropSet->getPropertyValue(u"TextAutoGrowHeight"_ustr);
1329 if (mAny.hasValue())
1330 mAny >>= bTextAutoGrowHeight;
1332 catch (...)
1336 pDrawing->singleElementNS(XML_a, (bTextAutoGrowHeight ? XML_spAutoFit : XML_noAutofit));
1339 pDrawing->endElementNS(XML_a, XML_bodyPr);
1342 pDrawing->startElementNS(XML_a, XML_p);
1343 pDrawing->startElementNS(XML_a, XML_r);
1344 pDrawing->startElementNS(XML_a, XML_t);
1345 pDrawing->write(msLabel);
1346 pDrawing->endElementNS(XML_a, XML_t);
1347 pDrawing->endElementNS(XML_a, XML_r);
1348 pDrawing->endElementNS(XML_a, XML_p);
1351 pDrawing->endElement(FSNS(XML_xdr, XML_txBody));
1354 pDrawing->endElement(FSNS(XML_xdr, XML_sp));
1355 pDrawing->singleElement(FSNS(XML_xdr, XML_clientData));
1357 pDrawing->endElement(FSNS(XML_xdr, XML_twoCellAnchor));
1358 pDrawing->endElement( FSNS( XML_mc, XML_Choice ) );
1359 pDrawing->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1362 // output into ctrlProp1.xml
1363 OUString XclExpTbxControlObj::SaveControlPropertiesXml(XclExpXmlStream& rStrm) const
1365 OUString sIdFormControlPr;
1367 switch (mnObjType)
1369 case EXC_OBJTYPE_CHECKBOX:
1371 const sal_Int32 nDrawing = DrawingML::getNewDrawingUniqueId();
1372 sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream(
1373 XclXmlUtils::GetStreamName( "xl/", "ctrlProps/ctrlProps", nDrawing ),
1374 XclXmlUtils::GetStreamName( "../", "ctrlProps/ctrlProps", nDrawing ),
1375 rStrm.GetCurrentStream()->getOutputStream(),
1376 "application/vnd.ms-excel.controlproperties+xml",
1377 oox::getRelationship(Relationship::CTRLPROP),
1378 &sIdFormControlPr );
1380 rStrm.PushStream( pFormControl );
1381 // checkbox
1382 // <formControlPr
1383 // xmlns="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
1384 // objectType="CheckBox" checked="Checked" lockText="1" noThreeD="1"/>
1386 pFormControl->write("<formControlPr xmlns=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\" objectType=\"CheckBox\"");
1387 if (mnState == EXC_OBJ_CHECKBOX_CHECKED)
1388 pFormControl->write(" checked=\"Checked\"");
1390 pFormControl->write(" autoLine=\"false\"");
1392 if (mbPrint)
1393 pFormControl->write(" print=\"true\"");
1394 else
1395 pFormControl->write(" print=\"false\"");
1397 if (mxCellLinkAddress.IsValid())
1399 OUString aCellLink = mxCellLinkAddress.Format(ScRefFlags::ADDR_ABS,
1400 &GetDoc(),
1401 ScAddress::Details(::formula::FormulaGrammar::CONV_XL_A1));
1403 // "Sheet1!$C$5"
1404 pFormControl->write(" fmlaLink=\"");
1405 if (aCellLink.indexOf('!') < 0)
1407 pFormControl->write(GetTabInfo().GetScTabName(mxCellLinkAddress.Tab()));
1408 pFormControl->write("!");
1410 pFormControl->write(aCellLink);
1411 pFormControl->write("\"");
1414 pFormControl->write(" lockText=\"1\" noThreeD=\"1\"/>");
1415 rStrm.PopStream();
1417 break;
1419 case EXC_OBJTYPE_BUTTON:
1421 sal_Int32 nDrawing = DrawingML::getNewDrawingUniqueId();
1422 sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream(
1423 XclXmlUtils::GetStreamName("xl/", "ctrlProps/ctrlProps", nDrawing),
1424 XclXmlUtils::GetStreamName("../", "ctrlProps/ctrlProps", nDrawing),
1425 rStrm.GetCurrentStream()->getOutputStream(),
1426 "application/vnd.ms-excel.controlproperties+xml",
1427 oox::getRelationship(Relationship::CTRLPROP), &sIdFormControlPr);
1429 pFormControl->singleElement(XML_formControlPr, XML_xmlns,
1430 rStrm.getNamespaceURL(OOX_NS(xls14Lst)), XML_objectType,
1431 "Button", XML_lockText, "1");
1432 break;
1436 return sIdFormControlPr;
1439 // output into sheet1.xml
1440 void XclExpTbxControlObj::SaveSheetXml(XclExpXmlStream& rStrm, const OUString& aIdFormControlPr) const
1442 switch (mnObjType)
1444 case EXC_OBJTYPE_CHECKBOX:
1446 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1448 rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent),
1449 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)));
1450 rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
1452 rWorksheet->startElement(
1453 XML_control,
1454 XML_shapeId, OString::number(mnShapeId),
1455 FSNS(XML_r, XML_id), aIdFormControlPr,
1456 XML_name, msLabel); // text to display with checkbox button
1458 rWorksheet->write("<controlPr defaultSize=\"0\" locked=\"1\" autoFill=\"0\" autoLine=\"0\" autoPict=\"0\"");
1460 if (mbPrint)
1461 rWorksheet->write(" print=\"true\"");
1462 else
1463 rWorksheet->write(" print=\"false\"");
1465 if (!msCtrlName.isEmpty())
1467 rWorksheet->write(" altText=\"");
1468 rWorksheet->write(msCtrlName); // alt text
1469 rWorksheet->write("\"");
1472 rWorksheet->write(">");
1474 rWorksheet->startElement(XML_anchor, XML_moveWithCells, "true", XML_sizeWithCells, "false");
1475 rWorksheet->startElement(XML_from);
1476 lcl_WriteAnchorVertex(rWorksheet, maAreaFrom);
1477 rWorksheet->endElement(XML_from);
1478 rWorksheet->startElement(XML_to);
1479 lcl_WriteAnchorVertex(rWorksheet, maAreaTo);
1480 rWorksheet->endElement(XML_to);
1481 rWorksheet->endElement( XML_anchor );
1483 rWorksheet->write("</controlPr>");
1485 rWorksheet->endElement(XML_control);
1486 rWorksheet->endElement( FSNS( XML_mc, XML_Choice ) );
1487 rWorksheet->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1489 break;
1491 case EXC_OBJTYPE_BUTTON:
1493 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1495 rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent), FSNS(XML_xmlns, XML_mc),
1496 rStrm.getNamespaceURL(OOX_NS(mce)));
1497 rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
1499 rWorksheet->startElement(XML_control, XML_shapeId, OString::number(mnShapeId),
1500 FSNS(XML_r, XML_id), aIdFormControlPr, XML_name, msCtrlName);
1502 OUString aMacroName = GetMacroName();
1503 // Omit the macro attribute if it would be empty.
1504 rWorksheet->startElement(XML_controlPr, XML_defaultSize, "0", XML_print,
1505 mbPrint ? "true" : "false", XML_autoFill, "0", XML_autoPict,
1506 "0", XML_macro, sax_fastparser::UseIf(aMacroName, !aMacroName.isEmpty()));
1508 rWorksheet->startElement(XML_anchor, XML_moveWithCells, "true", XML_sizeWithCells,
1509 "false");
1511 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1512 tools::Rectangle aAreaFrom;
1513 tools::Rectangle aAreaTo;
1514 lcl_GetFromTo(mrRoot, pObj->GetLogicRect(), GetTab(), aAreaFrom, aAreaTo,
1515 /*bInEMU=*/true);
1517 rWorksheet->startElement(XML_from);
1518 lcl_WriteAnchorVertex(rWorksheet, aAreaFrom);
1519 rWorksheet->endElement(XML_from);
1520 rWorksheet->startElement(XML_to);
1521 lcl_WriteAnchorVertex(rWorksheet, aAreaTo);
1522 rWorksheet->endElement(XML_to);
1523 rWorksheet->endElement(XML_anchor);
1525 rWorksheet->endElement(XML_controlPr);
1527 rWorksheet->endElement(XML_control);
1528 rWorksheet->endElement(FSNS(XML_mc, XML_Choice));
1529 rWorksheet->endElement(FSNS(XML_mc, XML_AlternateContent));
1530 break;
1535 //#endif
1537 XclExpChartObj::XclExpChartObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor, ScDocument* pDoc ) :
1538 XclObj( rObjMgr, EXC_OBJTYPE_CHART ),
1539 XclExpRoot( rObjMgr.GetRoot() ), mxShape( xShape ),
1540 mpDoc(pDoc)
1542 // create the MSODRAWING record contents for the chart object
1543 mrEscherEx.OpenContainer( ESCHER_SpContainer );
1544 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
1545 EscherPropertyContainer aPropOpt;
1546 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 );
1547 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 );
1548 aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x0800004E );
1549 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x0800004D );
1550 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 );
1551 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x0800004D );
1552 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080008 );
1553 aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00020000 );
1554 aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 );
1555 aPropOpt.Commit( mrEscherEx.GetStream() );
1557 // anchor
1558 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
1559 ImplWriteAnchor( pSdrObj, pChildAnchor );
1561 // client data (the following OBJ record)
1562 mrEscherEx.AddAtom( 0, ESCHER_ClientData );
1563 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
1564 mrEscherEx.UpdateDffFragmentEnd();
1566 // load the chart OLE object
1567 if( SdrOle2Obj* pSdrOleObj = dynamic_cast< SdrOle2Obj* >( pSdrObj ) )
1568 (void)svt::EmbeddedObjectRef::TryRunningState(pSdrOleObj->GetObjRef());
1570 // create the chart substream object
1571 ScfPropertySet aShapeProp( xShape );
1572 css::awt::Rectangle aBoundRect;
1573 aShapeProp.GetProperty( aBoundRect, u"BoundRect"_ustr );
1574 tools::Rectangle aChartRect( Point( aBoundRect.X, aBoundRect.Y ), Size( aBoundRect.Width, aBoundRect.Height ) );
1575 mxChart = std::make_shared<XclExpChart>(GetRoot(), GetChartDoc(), aChartRect);
1578 XclExpChartObj::~XclExpChartObj()
1582 void XclExpChartObj::Save( XclExpStream& rStrm )
1584 // content of OBJ record
1585 XclObj::Save( rStrm );
1586 // chart substream
1587 mxChart->Save( rStrm );
1590 void XclExpChartObj::SaveXml( XclExpXmlStream& rStrm )
1592 sax_fastparser::FSHelperPtr pDrawing = rStrm.GetCurrentStream();
1594 // FIXME: two cell? it seems the two cell anchor is incorrect.
1595 pDrawing->startElement( FSNS( XML_xdr, XML_twoCellAnchor ), // OOXTODO: oneCellAnchor, absoluteAnchor
1596 XML_editAs, "oneCell" );
1597 Reference< XPropertySet > xPropSet( mxShape, UNO_QUERY );
1598 if (xPropSet.is())
1600 XclObjAny::WriteFromTo( rStrm, mxShape, GetTab() );
1601 ChartExport aChartExport(XML_xdr, pDrawing, GetChartDoc(), &rStrm, drawingml::DOCUMENT_XLSX);
1602 auto pURLTransformer = std::make_shared<ScURLTransformer>(*mpDoc);
1603 aChartExport.SetURLTranslator(pURLTransformer);
1604 sal_Int32 nChartCount = oox::drawingml::DrawingML::getNewChartUniqueId();
1605 sal_Int32 nID = rStrm.GetUniqueId();
1606 aChartExport.WriteChartObj( mxShape, nID, nChartCount );
1607 // TODO: get the correcto chart number
1610 pDrawing->singleElement( FSNS( XML_xdr, XML_clientData)
1611 // OOXTODO: XML_fLocksWithSheet
1612 // OOXTODO: XML_fPrintsWithSheet
1614 pDrawing->endElement( FSNS( XML_xdr, XML_twoCellAnchor ) );
1617 css::uno::Reference<css::chart::XChartDocument> XclExpChartObj::GetChartDoc() const
1619 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
1620 if (!pObj || pObj->GetObjIdentifier() != SdrObjKind::OLE2)
1621 return {};
1622 // May load here - makes sure that we are working with actually loaded OLE object
1623 return css::uno::Reference<css::chart::XChartDocument>(
1624 static_cast<SdrOle2Obj*>(pObj)->getXModel(), css::uno::UNO_QUERY);
1627 XclExpNote::XclExpNote(const XclExpRoot& rRoot, const ScAddress& rScPos,
1628 const ScPostIt* pScNote, std::u16string_view rAddText)
1629 : XclExpRecord(EXC_ID_NOTE)
1630 , mrRoot(rRoot)
1631 , maScPos(rScPos)
1632 , mnObjId(EXC_OBJ_INVALID_ID)
1633 , mbVisible(pScNote && pScNote->IsCaptionShown())
1634 , meTHA(SDRTEXTHORZADJUST_LEFT)
1635 , meTVA(SDRTEXTVERTADJUST_TOP)
1636 , mbAutoScale(false)
1637 , mbLocked(false)
1638 , mbAutoFill(false)
1639 , mbColHidden(false)
1640 , mbRowHidden(false)
1641 , mpAuthorIDs(new SvtSecurityMapPersonalInfo)
1643 // get the main note text
1644 OUString aNoteText;
1645 if( pScNote )
1646 aNoteText = pScNote->GetText();
1648 // append additional text
1649 aNoteText = ScGlobal::addToken( aNoteText, rAddText, '\n', 2 );
1651 // initialize record dependent on BIFF type
1652 switch( rRoot.GetBiff() )
1654 case EXC_BIFF5:
1655 maNoteText = OUStringToOString(aNoteText, rRoot.GetTextEncoding());
1656 break;
1658 case EXC_BIFF8:
1660 // TODO: additional text
1661 if( pScNote )
1663 if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ) )
1665 lcl_GetFromTo( rRoot, pCaption->GetLogicRect(), maScPos.Tab(), maCommentFrom, maCommentTo );
1666 if( const OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
1667 mnObjId = rRoot.GetObjectManager().AddObj( std::make_unique<XclObjComment>( rRoot.GetObjectManager(), pCaption->GetLogicRect(), pOPO->GetTextObject(), pCaption, mbVisible, maScPos, maCommentFrom, maCommentTo ) );
1669 SfxItemSet aItemSet = pCaption->GetMergedItemSet();
1670 meTVA = pCaption->GetTextVerticalAdjust();
1671 meTHA = pCaption->GetTextHorizontalAdjust();
1672 mbAutoScale = pCaption->GetFitToSize() != drawing::TextFitToSizeType_NONE;
1673 mbLocked = pCaption->IsMoveProtect() || pCaption->IsResizeProtect();
1675 // AutoFill style would change if Postit.cxx object creation values are changed
1676 OUString aCol(aItemSet.Get(XATTR_FILLCOLOR).GetValue());
1677 mbAutoFill = aCol.isEmpty() && (aItemSet.Get(XATTR_FILLSTYLE).GetValue() == drawing::FillStyle_SOLID);
1678 mbRowHidden = (rRoot.GetDoc().RowHidden(maScPos.Row(),maScPos.Tab()));
1679 mbColHidden = (rRoot.GetDoc().ColHidden(maScPos.Col(),maScPos.Tab()));
1681 // stAuthor (variable): An XLUnicodeString that specifies the name of the comment
1682 // author. String length MUST be greater than or equal to 1 and less than or equal
1683 // to 54.
1684 bool bRemovePersonalInfo
1685 = SvtSecurityOptions::IsOptionSet(
1686 SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo)
1687 && !SvtSecurityOptions::IsOptionSet(
1688 SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo);
1689 if( pScNote->GetAuthor().isEmpty() )
1690 maAuthor = XclExpString( u" "_ustr );
1691 else if (bRemovePersonalInfo)
1692 maAuthor = XclExpString(
1693 "Author"
1694 + OUString::number(mpAuthorIDs->GetInfoID(pScNote->GetAuthor())),
1695 XclStrFlags::NONE, 54);
1696 else
1697 maAuthor = XclExpString( pScNote->GetAuthor(), XclStrFlags::NONE, 54 );
1699 if (const EditTextObject *pEditObj = pScNote->GetEditTextObject())
1700 mpNoteContents = XclExpStringHelper::CreateString( rRoot, *pEditObj );
1703 SetRecSize( 9 + maAuthor.GetSize() );
1705 break;
1707 default: DBG_ERROR_BIFF();
1711 void XclExpNote::Save( XclExpStream& rStrm )
1713 switch( rStrm.GetRoot().GetBiff() )
1715 case EXC_BIFF5:
1717 // write the NOTE record directly, there may be the need to create more than one
1718 const char* pcBuffer = maNoteText.getStr();
1719 sal_uInt16 nCharsLeft = static_cast< sal_uInt16 >( maNoteText.getLength() );
1721 while( nCharsLeft )
1723 sal_uInt16 nWriteChars = ::std::min( nCharsLeft, EXC_NOTE5_MAXLEN );
1725 rStrm.StartRecord( EXC_ID_NOTE, 6 + nWriteChars );
1726 if( pcBuffer == maNoteText.getStr() )
1728 // first record: row, col, length of complete text
1729 rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
1730 << static_cast< sal_uInt16 >( maScPos.Col() )
1731 << nCharsLeft; // still contains full length
1733 else
1735 // next records: -1, 0, length of current text segment
1736 rStrm << sal_uInt16( 0xFFFF )
1737 << sal_uInt16( 0 )
1738 << nWriteChars;
1740 rStrm.Write( pcBuffer, nWriteChars );
1741 rStrm.EndRecord();
1743 pcBuffer += nWriteChars;
1744 nCharsLeft = nCharsLeft - nWriteChars;
1747 break;
1749 case EXC_BIFF8:
1750 if( mnObjId != EXC_OBJ_INVALID_ID )
1751 XclExpRecord::Save( rStrm );
1752 break;
1754 default: DBG_ERROR_BIFF();
1758 void XclExpNote::WriteBody( XclExpStream& rStrm )
1760 // BIFF5/BIFF7 is written separately
1761 OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
1763 sal_uInt16 nFlags = 0;
1764 ::set_flag( nFlags, EXC_NOTE_VISIBLE, mbVisible );
1766 rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
1767 << static_cast< sal_uInt16 >( maScPos.Col() )
1768 << nFlags
1769 << mnObjId
1770 << maAuthor
1771 << sal_uInt8( 0 );
1774 void XclExpNote::WriteXml( sal_Int32 nAuthorId, XclExpXmlStream& rStrm )
1776 sax_fastparser::FSHelperPtr rComments = rStrm.GetCurrentStream();
1778 rComments->startElement( XML_comment,
1779 XML_ref, XclXmlUtils::ToOString(mrRoot.GetDoc(), ScRange(maScPos)),
1780 XML_authorId, OString::number(nAuthorId)
1781 // OOXTODO: XML_guid
1783 rComments->startElement(XML_text);
1784 // OOXTODO: phoneticPr, rPh, r
1785 if( mpNoteContents )
1786 mpNoteContents->WriteXml( rStrm );
1787 rComments->endElement( XML_text );
1790 Export of commentPr is disabled, since the current (Oct 2010)
1791 version of MSO 2010 doesn't yet support commentPr
1793 #if 1//def XLSX_OOXML_FUTURE
1794 if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1796 rComments->startElement(FSNS(XML_mc, XML_AlternateContent));
1797 rComments->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "v2");
1798 rComments->startElement( XML_commentPr,
1799 XML_autoFill, ToPsz( mbAutoFill ),
1800 XML_autoScale, ToPsz( mbAutoScale ),
1801 XML_colHidden, ToPsz( mbColHidden ),
1802 XML_locked, ToPsz( mbLocked ),
1803 XML_rowHidden, ToPsz( mbRowHidden ),
1804 XML_textHAlign, ToHorizAlign( meTHA ),
1805 XML_textVAlign, ToVertAlign( meTVA ) );
1806 rComments->startElement(XML_anchor, XML_moveWithCells, "false", XML_sizeWithCells, "false");
1807 rComments->startElement(FSNS(XML_xdr, XML_from));
1808 lcl_WriteAnchorVertex( rComments, maCommentFrom );
1809 rComments->endElement( FSNS( XML_xdr, XML_from ) );
1810 rComments->startElement(FSNS(XML_xdr, XML_to));
1811 lcl_WriteAnchorVertex( rComments, maCommentTo );
1812 rComments->endElement( FSNS( XML_xdr, XML_to ) );
1813 rComments->endElement( XML_anchor );
1814 rComments->endElement( XML_commentPr );
1816 rComments->endElement( FSNS( XML_mc, XML_Choice ) );
1817 rComments->startElement(FSNS(XML_mc, XML_Fallback));
1818 // Any fallback code ?
1819 rComments->endElement( FSNS( XML_mc, XML_Fallback ) );
1820 rComments->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1822 #endif
1823 rComments->endElement( XML_comment );
1826 XclMacroHelper::XclMacroHelper( const XclExpRoot& rRoot ) :
1827 XclExpControlHelper( rRoot )
1831 XclMacroHelper::~XclMacroHelper()
1835 void XclMacroHelper::WriteMacroSubRec( XclExpStream& rStrm )
1837 if( mxMacroLink )
1838 WriteFormulaSubRec( rStrm, EXC_ID_OBJMACRO, *mxMacroLink );
1841 const OUString& XclMacroHelper::GetMacroName() const { return maMacroName; }
1843 bool
1844 XclMacroHelper::SetMacroLink( const ScriptEventDescriptor& rEvent, const XclTbxEventType& nEventType )
1846 maMacroName = XclControlHelper::ExtractFromMacroDescriptor(rEvent, nEventType);
1847 if (!maMacroName.isEmpty())
1849 return SetMacroLink(maMacroName);
1851 return false;
1854 bool
1855 XclMacroHelper::SetMacroLink( const OUString& rMacroName )
1857 // OOXML documents do not store any defined name for VBA macros (while BIFF documents do).
1858 bool bOOXML = GetOutput() == EXC_OUTPUT_XML_2007;
1859 if (!rMacroName.isEmpty() && !bOOXML)
1861 sal_uInt16 nExtSheet = GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC );
1862 sal_uInt16 nNameIdx
1863 = GetNameManager().InsertMacroCall(rMacroName, /*bVBasic=*/true, /*bFunc=*/false);
1864 mxMacroLink = GetFormulaCompiler().CreateNameXFormula( nExtSheet, nNameIdx );
1865 return true;
1867 return false;
1870 XclExpShapeObj::XclExpShapeObj( XclExpObjectManager& rRoot, css::uno::Reference< css::drawing::XShape > const & xShape, ScDocument* pDoc ) :
1871 XclObjAny( rRoot, xShape, pDoc ),
1872 XclMacroHelper( rRoot )
1874 if (SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(xShape))
1876 ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pSdrObj );
1877 if ( pInfo && !pInfo->GetMacro().isEmpty() )
1878 // 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
1879 // SetMacroLink( XclControlHelper::GetXclMacroName( pInfo->GetMacro(), rRoot.GetDocShell() ) );
1880 SetMacroLink( XclTools::GetXclMacroName( pInfo->GetMacro() ) );
1884 XclExpShapeObj::~XclExpShapeObj()
1888 void XclExpShapeObj::WriteSubRecs( XclExpStream& rStrm )
1890 XclObjAny::WriteSubRecs( rStrm );
1891 WriteMacroSubRec( rStrm );
1894 XclExpComments::XclExpComments( SCTAB nTab, XclExpRecordList< XclExpNote >& rNotes )
1895 : mnTab( nTab ), mrNotes( rNotes )
1899 void XclExpComments::SaveXml( XclExpXmlStream& rStrm )
1901 if( mrNotes.IsEmpty() )
1902 return;
1904 sax_fastparser::FSHelperPtr rComments = rStrm.CreateOutputStream(
1905 XclXmlUtils::GetStreamName( "xl/", "comments", mnTab + 1 ),
1906 XclXmlUtils::GetStreamName( "../", "comments", mnTab + 1 ),
1907 rStrm.GetCurrentStream()->getOutputStream(),
1908 "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
1909 oox::getRelationship(Relationship::COMMENTS));
1910 rStrm.PushStream( rComments );
1912 if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1913 rComments->startElement( XML_comments,
1914 XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)),
1915 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)),
1916 FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)),
1917 FSNS(XML_xmlns, XML_v2), rStrm.getNamespaceURL(OOX_NS(mceTest)),
1918 FSNS( XML_mc, XML_Ignorable ), "v2" );
1919 else
1920 rComments->startElement( XML_comments,
1921 XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)),
1922 FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)) );
1924 rComments->startElement(XML_authors);
1926 typedef std::set<OUString> Authors;
1927 Authors aAuthors;
1929 size_t nNotes = mrNotes.GetSize();
1930 for( size_t i = 0; i < nNotes; ++i )
1932 aAuthors.insert( XclXmlUtils::ToOUString( mrNotes.GetRecord( i )->GetAuthor() ) );
1935 for( const auto& rAuthor : aAuthors )
1937 rComments->startElement(XML_author);
1938 rComments->writeEscaped( rAuthor );
1939 rComments->endElement( XML_author );
1942 rComments->endElement( XML_authors );
1943 rComments->startElement(XML_commentList);
1945 Authors::const_iterator aAuthorsBegin = aAuthors.begin();
1946 for( size_t i = 0; i < nNotes; ++i )
1948 XclExpRecordList< XclExpNote >::RecordRefType xNote = mrNotes.GetRecord( i );
1949 Authors::const_iterator aAuthor = aAuthors.find(
1950 XclXmlUtils::ToOUString( xNote->GetAuthor() ) );
1951 sal_Int32 nAuthorId = distance( aAuthorsBegin, aAuthor );
1952 xNote->WriteXml( nAuthorId, rStrm );
1955 rComments->endElement( XML_commentList );
1956 rComments->endElement( XML_comments );
1958 rStrm.PopStream();
1961 // object manager =============================================================
1963 XclExpObjectManager::XclExpObjectManager( const XclExpRoot& rRoot ) :
1964 XclExpRoot( rRoot )
1966 InitStream( true );
1967 assert(mpDffStrm);
1968 mxEscherEx = std::make_shared<XclEscherEx>( GetRoot(), *this, *mpDffStrm );
1971 XclExpObjectManager::XclExpObjectManager( const XclExpObjectManager& rParent ) :
1972 XclExpRoot( rParent.GetRoot() )
1974 InitStream( false );
1975 assert(mpDffStrm);
1976 mxEscherEx = std::make_shared<XclEscherEx>( GetRoot(), *this, *mpDffStrm, rParent.mxEscherEx.get() );
1979 XclExpObjectManager::~XclExpObjectManager()
1983 XclExpDffAnchorBase* XclExpObjectManager::CreateDffAnchor() const
1985 return new XclExpDffSheetAnchor( GetRoot() );
1988 rtl::Reference< XclExpRecordBase > XclExpObjectManager::CreateDrawingGroup()
1990 return new XclExpMsoDrawingGroup( *mxEscherEx );
1993 void XclExpObjectManager::StartSheet()
1995 mxObjList = new XclExpObjList( GetRoot(), *mxEscherEx );
1998 rtl::Reference< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const SdrPage* pSdrPage )
2000 if( pSdrPage )
2001 mxEscherEx->AddSdrPage( *pSdrPage, GetOutput() != EXC_OUTPUT_BINARY );
2002 // the first dummy object may still be open
2003 OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
2004 while( mxEscherEx->GetGroupLevel() )
2005 mxEscherEx->LeaveGroup();
2006 mxObjList->EndSheet();
2007 return mxObjList;
2010 rtl::Reference< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const Reference< XShapes >& rxShapes )
2012 if( rxShapes.is() )
2013 mxEscherEx->AddUnoShapes( rxShapes, GetOutput() != EXC_OUTPUT_BINARY );
2014 // the first dummy object may still be open
2015 OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
2016 while( mxEscherEx->GetGroupLevel() )
2017 mxEscherEx->LeaveGroup();
2018 mxObjList->EndSheet();
2019 return mxObjList;
2022 void XclExpObjectManager::EndDocument()
2024 mxEscherEx->EndDocument();
2027 XclExpMsoDrawing* XclExpObjectManager::GetMsodrawingPerSheet()
2029 return mxObjList->GetMsodrawingPerSheet();
2032 bool XclExpObjectManager::HasObj() const
2034 return !mxObjList->empty();
2037 sal_uInt16 XclExpObjectManager::AddObj( std::unique_ptr<XclObj> pObjRec )
2039 return mxObjList->Add( std::move(pObjRec) );
2042 std::unique_ptr<XclObj> XclExpObjectManager::RemoveLastObj()
2044 return mxObjList->pop_back();
2047 void XclExpObjectManager::InitStream( bool bTempFile )
2049 if( bTempFile )
2051 moTempFile.emplace();
2052 mpDffStrm = moTempFile->GetStream( StreamMode::STD_READWRITE );
2055 if( !mpDffStrm )
2057 mpBackupStrm = std::make_unique<SvMemoryStream>();
2058 mpDffStrm = mpBackupStrm.get();
2061 assert(mpDffStrm);
2063 mpDffStrm->SetEndian( SvStreamEndian::LITTLE );
2066 XclExpEmbeddedObjectManager::XclExpEmbeddedObjectManager(
2067 const XclExpObjectManager& rParent, const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
2068 XclExpObjectManager( rParent ),
2069 maPageSize( rPageSize ),
2070 mnScaleX( nScaleX ),
2071 mnScaleY( nScaleY )
2075 XclExpDffAnchorBase* XclExpEmbeddedObjectManager::CreateDffAnchor() const
2077 return new XclExpDffEmbeddedAnchor( GetRoot(), maPageSize, mnScaleX, mnScaleY );
2080 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */