Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / excel / xeescher.cxx
blobc49e6a709177ec99080f25605c34f45c64001621
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/drawing/XShape.hpp>
28 #include <com/sun/star/form/binding/XBindableValue.hpp>
29 #include <com/sun/star/form/binding/XListEntrySink.hpp>
30 #include <com/sun/star/awt/Size.hpp>
31 #include <com/sun/star/chart/XChartDocument.hpp>
33 #include <set>
34 #include <vcl/bitmapaccess.hxx>
35 #include <svx/svdoole2.hxx>
36 #include <svx/svdocapt.hxx>
37 #include <editeng/outlobj.hxx>
38 #include <unotools/tempfile.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <svtools/embedhlp.hxx>
42 #include <unonames.hxx>
43 #include <convuno.hxx>
44 #include <postit.hxx>
46 #include <fapihelper.hxx>
47 #include <xcl97esc.hxx>
48 #include <xechart.hxx>
49 #include <xeformula.hxx>
50 #include <xehelper.hxx>
51 #include <xelink.hxx>
52 #include <xename.hxx>
53 #include <xestyle.hxx>
54 #include <xllink.hxx>
55 #include <xltools.hxx>
56 #include <userdat.hxx>
57 #include <drwlayer.hxx>
58 #include <svl/itemset.hxx>
59 #include <svx/unoapi.hxx>
60 #include <svx/sdtaitm.hxx>
61 #include <document.hxx>
62 #include <svx/xfillit0.hxx>
63 #include <svx/xflclit.hxx>
65 #include <comphelper/sequence.hxx>
66 #include <oox/token/tokens.hxx>
67 #include <oox/token/relationship.hxx>
68 #include <oox/export/drawingml.hxx>
69 #include <oox/export/chartexport.hxx>
70 #include <oox/export/utils.hxx>
71 #include <oox/token/namespaces.hxx>
72 #include <memory>
74 using namespace com::sun::star;
75 using ::com::sun::star::uno::UNO_QUERY;
76 using ::com::sun::star::uno::Reference;
77 using ::com::sun::star::uno::Sequence;
78 using ::com::sun::star::lang::XServiceInfo;
79 using ::com::sun::star::beans::XPropertySet;
80 using ::com::sun::star::drawing::XShape;
81 using ::com::sun::star::drawing::XShapes;
82 using ::com::sun::star::frame::XModel;
83 using ::com::sun::star::awt::XControlModel;
84 using ::com::sun::star::form::binding::XBindableValue;
85 using ::com::sun::star::form::binding::XListEntrySink;
86 using ::com::sun::star::script::ScriptEventDescriptor;
87 using ::com::sun::star::table::CellAddress;
88 using ::com::sun::star::table::CellRangeAddress;
89 using ::oox::drawingml::DrawingML;
90 using ::oox::drawingml::ChartExport;
91 using namespace oox;
93 namespace
96 long lcl_hmm2px(long nPixel)
98 return static_cast<long>(nPixel*PIXEL_PER_INCH/1000.0/CM_PER_INCH + 0.5);
101 const char *ToHorizAlign( SdrTextHorzAdjust eAdjust )
103 switch( eAdjust )
105 case SDRTEXTHORZADJUST_CENTER:
106 return "center";
107 case SDRTEXTHORZADJUST_RIGHT:
108 return "right";
109 case SDRTEXTHORZADJUST_BLOCK:
110 return "justify";
111 case SDRTEXTHORZADJUST_LEFT:
112 default:
113 return "left";
117 const char *ToVertAlign( SdrTextVertAdjust eAdjust )
119 switch( eAdjust )
121 case SDRTEXTVERTADJUST_CENTER:
122 return "center";
123 case SDRTEXTVERTADJUST_BOTTOM:
124 return "bottom";
125 case SDRTEXTVERTADJUST_BLOCK:
126 return "justify";
127 case SDRTEXTVERTADJUST_TOP:
128 default:
129 return "top";
133 void lcl_WriteAnchorVertex( sax_fastparser::FSHelperPtr const & rComments, const tools::Rectangle &aRect )
135 rComments->startElement(FSNS(XML_xdr, XML_col));
136 rComments->writeEscaped( OUString::number( aRect.Left() ) );
137 rComments->endElement( FSNS( XML_xdr, XML_col ) );
138 rComments->startElement(FSNS(XML_xdr, XML_colOff));
139 rComments->writeEscaped( OUString::number( aRect.Top() ) );
140 rComments->endElement( FSNS( XML_xdr, XML_colOff ) );
141 rComments->startElement(FSNS(XML_xdr, XML_row));
142 rComments->writeEscaped( OUString::number( aRect.Right() ) );
143 rComments->endElement( FSNS( XML_xdr, XML_row ) );
144 rComments->startElement(FSNS(XML_xdr, XML_rowOff));
145 rComments->writeEscaped( OUString::number( aRect.Bottom() ) );
146 rComments->endElement( FSNS( XML_xdr, XML_rowOff ) );
149 void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_Int32 nTab, tools::Rectangle &aFrom, tools::Rectangle &aTo )
151 sal_Int32 nCol = 0, nRow = 0;
152 sal_Int32 nColOff = 0, nRowOff= 0;
154 const bool bRTL = rRoot.GetDoc().IsNegativePage( nTab );
155 if (!bRTL)
157 while(true)
159 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
160 if( r.Left() <= aRect.Left() )
162 nCol++;
163 nColOff = aRect.Left() - r.Left();
165 if( r.Top() <= aRect.Top() )
167 nRow++;
168 nRowOff = aRect.Top() - r.Top();
170 if( r.Left() > aRect.Left() && r.Top() > aRect.Top() )
172 aFrom = tools::Rectangle( nCol-1, lcl_hmm2px( nColOff ),
173 nRow-1, lcl_hmm2px( nRowOff ) );
174 break;
178 else
180 while(true)
182 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
183 if( r.Left() >= aRect.Left() )
185 nCol++;
186 nColOff = r.Left() - aRect.Left();
188 if( r.Top() <= aRect.Top() )
190 nRow++;
191 nRowOff = aRect.Top() - r.Top();
193 if( r.Left() < aRect.Left() && r.Top() > aRect.Top() )
195 aFrom = tools::Rectangle( nCol-1, lcl_hmm2px( nColOff ),
196 nRow-1, lcl_hmm2px( nRowOff ) );
197 break;
201 if (!bRTL)
203 while(true)
205 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
206 if( r.Right() < aRect.Right() )
207 nCol++;
208 if( r.Bottom() < aRect.Bottom() )
209 nRow++;
210 if( r.Right() >= aRect.Right() && r.Bottom() >= aRect.Bottom() )
212 aTo = tools::Rectangle( nCol, lcl_hmm2px( aRect.Right() - r.Left() ),
213 nRow, lcl_hmm2px( aRect.Bottom() - r.Top() ));
214 break;
218 else
220 while(true)
222 tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
223 if( r.Right() >= aRect.Right() )
224 nCol++;
225 if( r.Bottom() < aRect.Bottom() )
226 nRow++;
227 if( r.Right() < aRect.Right() && r.Bottom() >= aRect.Bottom() )
229 aTo = tools::Rectangle( nCol, lcl_hmm2px( r.Left() - aRect.Right() ),
230 nRow, lcl_hmm2px( aRect.Bottom() - r.Top() ));
231 break;
237 } // namespace
239 // Escher client anchor =======================================================
241 XclExpDffAnchorBase::XclExpDffAnchorBase( const XclExpRoot& rRoot, sal_uInt16 nFlags ) :
242 XclExpRoot( rRoot ),
243 mnFlags( nFlags )
247 void XclExpDffAnchorBase::SetFlags( const SdrObject& rSdrObj )
249 ImplSetFlags( rSdrObj );
252 void XclExpDffAnchorBase::SetSdrObject( const SdrObject& rSdrObj )
254 ImplSetFlags( rSdrObj );
255 ImplCalcAnchorRect( rSdrObj.GetCurrentBoundRect(), MapUnit::Map100thMM );
258 void XclExpDffAnchorBase::WriteDffData( EscherEx& rEscherEx ) const
260 rEscherEx.AddAtom( 18, ESCHER_ClientAnchor );
261 rEscherEx.GetStream().WriteUInt16( mnFlags );
262 WriteXclObjAnchor( rEscherEx.GetStream(), maAnchor );
265 void XclExpDffAnchorBase::WriteData( EscherEx& rEscherEx, const tools::Rectangle& rRect )
267 // the passed rectangle is in twips
268 ImplCalcAnchorRect( rRect, MapUnit::MapTwip );
269 WriteDffData( rEscherEx );
272 void XclExpDffAnchorBase::ImplSetFlags( const SdrObject& )
274 OSL_FAIL( "XclExpDffAnchorBase::ImplSetFlags - not implemented" );
277 void XclExpDffAnchorBase::ImplCalcAnchorRect( const tools::Rectangle&, MapUnit )
279 OSL_FAIL( "XclExpDffAnchorBase::ImplCalcAnchorRect - not implemented" );
282 XclExpDffSheetAnchor::XclExpDffSheetAnchor( const XclExpRoot& rRoot ) :
283 XclExpDffAnchorBase( rRoot ),
284 mnScTab( rRoot.GetCurrScTab() )
288 void XclExpDffSheetAnchor::ImplSetFlags( const SdrObject& rSdrObj )
290 // set flags for cell/page anchoring
291 if ( ScDrawLayer::GetAnchorType( rSdrObj ) == SCA_CELL )
292 mnFlags = 0;
293 else
294 mnFlags = EXC_ESC_ANCHOR_LOCKED;
297 void XclExpDffSheetAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
299 maAnchor.SetRect( GetRoot(), mnScTab, rRect, eMapUnit );
302 XclExpDffEmbeddedAnchor::XclExpDffEmbeddedAnchor( const XclExpRoot& rRoot,
303 const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
304 XclExpDffAnchorBase( rRoot ),
305 maPageSize( rPageSize ),
306 mnScaleX( nScaleX ),
307 mnScaleY( nScaleY )
311 void XclExpDffEmbeddedAnchor::ImplSetFlags( const SdrObject& /*rSdrObj*/ )
313 // TODO (unsupported feature): fixed size
316 void XclExpDffEmbeddedAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
318 maAnchor.SetRect( maPageSize, mnScaleX, mnScaleY, rRect, eMapUnit );
321 XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot& rRoot, const tools::Rectangle& rRect ) :
322 XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_SIZELOCKED )
324 maAnchor.SetRect( rRoot, rRoot.GetCurrScTab(), rRect, MapUnit::Map100thMM );
327 XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
328 XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_POSLOCKED )
330 GetAddressConverter().ConvertAddress( maAnchor.maFirst, rScPos, true );
331 maAnchor.maLast.mnCol = maAnchor.maFirst.mnCol + 1;
332 maAnchor.maLast.mnRow = maAnchor.maFirst.mnRow + 1;
333 maAnchor.mnLX = maAnchor.mnTY = maAnchor.mnRX = maAnchor.mnBY = 0;
336 // MSODRAWING* records ========================================================
338 XclExpMsoDrawingBase::XclExpMsoDrawingBase( XclEscherEx& rEscherEx, sal_uInt16 nRecId ) :
339 XclExpRecord( nRecId ),
340 mrEscherEx( rEscherEx ),
341 mnFragmentKey( rEscherEx.InitNextDffFragment() )
345 void XclExpMsoDrawingBase::WriteBody( XclExpStream& rStrm )
347 OSL_ENSURE( mrEscherEx.GetStreamPos() == mrEscherEx.GetDffFragmentPos( mnFragmentKey ),
348 "XclExpMsoDrawingBase::WriteBody - DFF stream position mismatch" );
349 rStrm.CopyFromStream( mrEscherEx.GetStream(), mrEscherEx.GetDffFragmentSize( mnFragmentKey ) );
352 XclExpMsoDrawingGroup::XclExpMsoDrawingGroup( XclEscherEx& rEscherEx ) :
353 XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWINGGROUP )
355 SvStream& rDffStrm = mrEscherEx.GetStream();
357 // write the DGGCONTAINER with some default settings
358 mrEscherEx.OpenContainer( ESCHER_DggContainer );
360 // TODO: stuff the OPT atom with our own document defaults?
361 static const sal_uInt8 spnDffOpt[] = {
362 0xBF, 0x00, 0x08, 0x00, 0x08, 0x00, 0x81, 0x01,
363 0x09, 0x00, 0x00, 0x08, 0xC0, 0x01, 0x40, 0x00,
364 0x00, 0x08
366 mrEscherEx.AddAtom( sizeof( spnDffOpt ), ESCHER_OPT, 3, 3 );
367 rDffStrm.WriteBytes(spnDffOpt, sizeof(spnDffOpt));
369 // SPLITMENUCOLORS contains colors in toolbar
370 static const sal_uInt8 spnDffSplitMenuColors[] = {
371 0x0D, 0x00, 0x00, 0x08, 0x0C, 0x00, 0x00, 0x08,
372 0x17, 0x00, 0x00, 0x08, 0xF7, 0x00, 0x00, 0x10
374 mrEscherEx.AddAtom( sizeof( spnDffSplitMenuColors ), ESCHER_SplitMenuColors, 0, 4 );
375 rDffStrm.WriteBytes(spnDffSplitMenuColors, sizeof(spnDffSplitMenuColors));
377 // close the DGGCONTAINER
378 mrEscherEx.CloseContainer();
379 mrEscherEx.UpdateDffFragmentEnd();
382 XclExpMsoDrawing::XclExpMsoDrawing( XclEscherEx& rEscherEx ) :
383 XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWING )
387 XclExpImgData::XclExpImgData( const Graphic& rGraphic, sal_uInt16 nRecId ) :
388 maGraphic( rGraphic ),
389 mnRecId( nRecId )
393 void XclExpImgData::Save( XclExpStream& rStrm )
395 Bitmap aBmp = maGraphic.GetBitmapEx().GetBitmap();
396 if( aBmp.GetBitCount() != 24 )
397 aBmp.Convert( BmpConversion::N24Bit );
399 Bitmap::ScopedReadAccess pAccess(aBmp);
400 if( pAccess )
402 sal_Int32 nWidth = ::std::min< sal_Int32 >( pAccess->Width(), 0xFFFF );
403 sal_Int32 nHeight = ::std::min< sal_Int32 >( pAccess->Height(), 0xFFFF );
404 if( (nWidth > 0) && (nHeight > 0) )
406 sal_uInt8 nPadding = static_cast< sal_uInt8 >( nWidth & 0x03 );
407 sal_uInt32 nTmpSize = static_cast< sal_uInt32 >( (nWidth * 3 + nPadding) * nHeight + 12 );
409 rStrm.StartRecord( mnRecId, nTmpSize + 4 );
411 rStrm << EXC_IMGDATA_BMP // BMP format
412 << EXC_IMGDATA_WIN // Windows
413 << nTmpSize // size after _this_ field
414 << sal_uInt32( 12 ) // BITMAPCOREHEADER size
415 << static_cast< sal_uInt16 >( nWidth ) // width
416 << static_cast< sal_uInt16 >( nHeight ) // height
417 << sal_uInt16( 1 ) // planes
418 << sal_uInt16( 24 ); // bits per pixel
420 for( sal_Int32 nY = nHeight - 1; nY >= 0; --nY )
422 Scanline pScanline = pAccess->GetScanline( nY );
423 for( sal_Int32 nX = 0; nX < nWidth; ++nX )
425 const BitmapColor& rBmpColor = pAccess->GetPixelFromData( pScanline, nX );
426 rStrm << rBmpColor.GetBlue() << rBmpColor.GetGreen() << rBmpColor.GetRed();
428 rStrm.WriteZeroBytes( nPadding );
431 rStrm.EndRecord();
436 void XclExpImgData::SaveXml( XclExpXmlStream& rStrm )
438 sax_fastparser::FSHelperPtr pWorksheet = rStrm.GetCurrentStream();
440 DrawingML aDML(pWorksheet, &rStrm, drawingml::DOCUMENT_XLSX);
441 OUString rId = aDML.WriteImage( maGraphic );
442 pWorksheet->singleElement(XML_picture, FSNS(XML_r, XML_id), rId.toUtf8());
445 XclExpControlHelper::XclExpControlHelper( const XclExpRoot& rRoot ) :
446 XclExpRoot( rRoot ),
447 mnEntryCount( 0 )
451 XclExpControlHelper::~XclExpControlHelper()
455 void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > const & xShape )
457 mxCellLink.reset();
458 mxSrcRange.reset();
459 mnEntryCount = 0;
461 // get control model
462 Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
463 if( !xCtrlModel.is() )
464 return;
466 // *** cell link *** ------------------------------------------------------
468 Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
469 if( xBindable.is() )
471 Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
472 if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
474 ScfPropertySet aBindProp( xServInfo );
475 CellAddress aApiAddress;
476 if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
478 ScAddress aCellLink;
479 ScUnoConversion::FillScAddress( aCellLink, aApiAddress );
480 if( GetTabInfo().IsExportTab( aCellLink.Tab() ) )
481 mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aCellLink );
486 // *** source range *** ---------------------------------------------------
488 Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY );
489 if( xEntrySink.is() )
491 Reference< XServiceInfo > xServInfo( xEntrySink->getListEntrySource(), UNO_QUERY );
492 if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_LISTSOURCE ) )
494 ScfPropertySet aSinkProp( xServInfo );
495 CellRangeAddress aApiRange;
496 if( aSinkProp.GetProperty( aApiRange, SC_UNONAME_CELLRANGE ) )
498 ScRange aSrcRange;
499 ScUnoConversion::FillScRange( aSrcRange, aApiRange );
500 if( (aSrcRange.aStart.Tab() == aSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( aSrcRange.aStart.Tab() ) )
501 mxSrcRange = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aSrcRange );
502 mnEntryCount = static_cast< sal_uInt16 >( aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1 );
508 void XclExpControlHelper::WriteFormula( XclExpStream& rStrm, const XclTokenArray& rTokArr )
510 sal_uInt16 nFmlaSize = rTokArr.GetSize();
511 rStrm << nFmlaSize << sal_uInt32( 0 );
512 rTokArr.WriteArray( rStrm );
513 if( nFmlaSize & 1 ) // pad to 16-bit
514 rStrm << sal_uInt8( 0 );
517 void XclExpControlHelper::WriteFormulaSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId, const XclTokenArray& rTokArr )
519 rStrm.StartRecord( nSubRecId, (rTokArr.GetSize() + 5) & ~1 );
520 WriteFormula( rStrm, rTokArr );
521 rStrm.EndRecord();
524 //delete for exporting OCX
525 //#if EXC_EXP_OCX_CTRL
527 XclExpOcxControlObj::XclExpOcxControlObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape,
528 const tools::Rectangle* pChildAnchor, const OUString& rClassName, sal_uInt32 nStrmStart, sal_uInt32 nStrmSize ) :
529 XclObj( rObjMgr, EXC_OBJTYPE_PICTURE, true ),
530 XclExpControlHelper( rObjMgr.GetRoot() ),
531 maClassName( rClassName ),
532 mnStrmStart( nStrmStart ),
533 mnStrmSize( nStrmSize )
535 ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
537 // OBJ record flags
538 SetLocked( true );
539 SetPrintable( aCtrlProp.GetBoolProperty( "Printable" ) );
540 SetAutoFill( false );
541 SetAutoLine( false );
543 // fill DFF property set
544 mrEscherEx.OpenContainer( ESCHER_SpContainer );
545 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl,
546 ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape );
547 tools::Rectangle aDummyRect;
548 EscherPropertyContainer aPropOpt( mrEscherEx.GetGraphicProvider(), mrEscherEx.QueryPictureStream(), aDummyRect );
549 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field
550 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x08000040 );
551 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
553 // #i51348# name of the control, may overwrite shape name
554 OUString aCtrlName;
555 if( aCtrlProp.GetProperty( aCtrlName, "Name" ) && !aCtrlName.isEmpty() )
556 aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
558 // meta file
559 //TODO - needs check
560 Reference< XPropertySet > xShapePS( xShape, UNO_QUERY );
561 if( xShapePS.is() && aPropOpt.CreateGraphicProperties( xShapePS, "MetaFile", false ) )
563 sal_uInt32 nBlipId;
564 if( aPropOpt.GetOpt( ESCHER_Prop_pib, nBlipId ) )
565 aPropOpt.AddOpt( ESCHER_Prop_pictureId, nBlipId );
568 // write DFF property set to stream
569 aPropOpt.Commit( mrEscherEx.GetStream() );
571 // anchor
572 ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
574 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
575 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
576 mrEscherEx.UpdateDffFragmentEnd();
578 // spreadsheet links
579 ConvertSheetLinks( xShape );
582 void XclExpOcxControlObj::WriteSubRecs( XclExpStream& rStrm )
584 // OBJCF - clipboard format
585 rStrm.StartRecord( EXC_ID_OBJCF, 2 );
586 rStrm << sal_uInt16( 2 );
587 rStrm.EndRecord();
589 // OBJFLAGS
590 rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 );
591 rStrm << sal_uInt16( 0x0031 );
592 rStrm.EndRecord();
594 // OBJPICTFMLA
595 XclExpString aClass( maClassName );
596 sal_uInt16 nClassNameSize = static_cast< sal_uInt16 >( aClass.GetSize() );
597 sal_uInt16 nClassNamePad = nClassNameSize & 1;
598 sal_uInt16 nFirstPartSize = 12 + nClassNameSize + nClassNamePad;
600 const XclTokenArray* pCellLink = GetCellLinkTokArr();
601 sal_uInt16 nCellLinkSize = pCellLink ? ((pCellLink->GetSize() + 7) & 0xFFFE) : 0;
603 const XclTokenArray* pSrcRange = GetSourceRangeTokArr();
604 sal_uInt16 nSrcRangeSize = pSrcRange ? ((pSrcRange->GetSize() + 7) & 0xFFFE) : 0;
606 sal_uInt16 nPictFmlaSize = nFirstPartSize + nCellLinkSize + nSrcRangeSize + 18;
607 rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nPictFmlaSize );
609 rStrm << nFirstPartSize // size of first part
610 << sal_uInt16( 5 ) // formula size
611 << sal_uInt32( 0 ) // unknown ID
612 << sal_uInt8( 0x02 ) << sal_uInt32( 0 ) // tTbl token with unknown ID
613 << sal_uInt8( 3 ) // pad to word
614 << aClass; // "Forms.***.1"
615 rStrm.WriteZeroBytes( nClassNamePad ); // pad to word
616 rStrm << mnStrmStart // start in 'Ctls' stream
617 << mnStrmSize // size in 'Ctls' stream
618 << sal_uInt32( 0 ); // class ID size
619 // cell link
620 rStrm << nCellLinkSize;
621 if( pCellLink )
622 WriteFormula( rStrm, *pCellLink );
623 // list source range
624 rStrm << nSrcRangeSize;
625 if( pSrcRange )
626 WriteFormula( rStrm, *pSrcRange );
628 rStrm.EndRecord();
631 //#else
633 XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference< XShape > const & xShape , const tools::Rectangle* pChildAnchor ) :
634 XclObj( rRoot, EXC_OBJTYPE_UNKNOWN, true ),
635 XclMacroHelper( rRoot ),
636 meEventType( EXC_TBX_EVENT_ACTION ),
637 mnHeight( 0 ),
638 mnState( 0 ),
639 mnLineCount( 0 ),
640 mnSelEntry( 0 ),
641 mnScrollValue( 0 ),
642 mnScrollMin( 0 ),
643 mnScrollMax( 100 ),
644 mnScrollStep( 1 ),
645 mnScrollPage( 10 ),
646 mbFlatButton( false ),
647 mbFlatBorder( false ),
648 mbMultiSel( false ),
649 mbScrollHor( false )
651 namespace FormCompType = css::form::FormComponentType;
652 namespace AwtVisualEffect = css::awt::VisualEffect;
653 namespace AwtScrollOrient = css::awt::ScrollBarOrientation;
655 ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
656 if( !xShape.is() || !aCtrlProp.Is() )
657 return;
659 mnHeight = xShape->getSize().Height;
660 if( mnHeight <= 0 )
661 return;
663 // control type
664 sal_Int16 nClassId = 0;
665 if( aCtrlProp.GetProperty( nClassId, "ClassId" ) )
667 switch( nClassId )
669 case FormCompType::COMMANDBUTTON: mnObjType = EXC_OBJTYPE_BUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
670 case FormCompType::RADIOBUTTON: mnObjType = EXC_OBJTYPE_OPTIONBUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
671 case FormCompType::CHECKBOX: mnObjType = EXC_OBJTYPE_CHECKBOX; meEventType = EXC_TBX_EVENT_ACTION; break;
672 case FormCompType::LISTBOX: mnObjType = EXC_OBJTYPE_LISTBOX; meEventType = EXC_TBX_EVENT_CHANGE; break;
673 case FormCompType::COMBOBOX: mnObjType = EXC_OBJTYPE_DROPDOWN; meEventType = EXC_TBX_EVENT_CHANGE; break;
674 case FormCompType::GROUPBOX: mnObjType = EXC_OBJTYPE_GROUPBOX; meEventType = EXC_TBX_EVENT_MOUSE; break;
675 case FormCompType::FIXEDTEXT: mnObjType = EXC_OBJTYPE_LABEL; meEventType = EXC_TBX_EVENT_MOUSE; break;
676 case FormCompType::SCROLLBAR: mnObjType = EXC_OBJTYPE_SCROLLBAR; meEventType = EXC_TBX_EVENT_VALUE; break;
677 case FormCompType::SPINBUTTON: mnObjType = EXC_OBJTYPE_SPIN; meEventType = EXC_TBX_EVENT_VALUE; break;
680 if( mnObjType == EXC_OBJTYPE_UNKNOWN )
681 return;
683 // OBJ record flags
684 SetLocked( true );
685 SetPrintable( aCtrlProp.GetBoolProperty( "Printable" ) );
686 SetAutoFill( false );
687 SetAutoLine( false );
689 // fill DFF property set
690 mrEscherEx.OpenContainer( ESCHER_SpContainer );
691 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
692 EscherPropertyContainer aPropOpt;
693 bool bVisible = aCtrlProp.GetBoolProperty( "EnableVisible" );
694 aPropOpt.AddOpt( ESCHER_Prop_fPrint, bVisible ? 0x00080000 : 0x00080002 ); // visible flag
696 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01000100 ); // bool field
697 aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 ); // Text ID
698 aPropOpt.AddOpt( ESCHER_Prop_WrapText, 0x00000001 );
699 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x001A0008 ); // bool field
700 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00100000 ); // bool field
701 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
703 // #i51348# name of the control, may overwrite shape name
704 OUString aCtrlName;
705 if( aCtrlProp.GetProperty( aCtrlName, "Name" ) && !aCtrlName.isEmpty() )
706 aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
708 //Export description as alt text
709 if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
711 OUString aAltTxt;
712 OUString aDescrText = pSdrObj->GetDescription();
713 if(!aDescrText.isEmpty())
714 aAltTxt = aDescrText.copy( 0, std::min<sal_Int32>(MSPROP_DESCRIPTION_MAX_LEN, aDescrText.getLength()) );
715 aPropOpt.AddOpt( ESCHER_Prop_wzDescription, aAltTxt );
718 // write DFF property set to stream
719 aPropOpt.Commit( mrEscherEx.GetStream() );
721 // anchor
722 ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
724 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
725 mrEscherEx.UpdateDffFragmentEnd();
727 // control label
728 OUString aString;
729 if( aCtrlProp.GetProperty( aString, "Label" ) )
731 /* Be sure to construct the MSODRAWING record containing the
732 ClientTextbox atom after the base OBJ's MSODRAWING record data is
733 completed. */
734 pClientTextbox.reset( new XclExpMsoDrawing( mrEscherEx ) );
735 mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record
736 mrEscherEx.UpdateDffFragmentEnd();
738 sal_uInt16 nXclFont = EXC_FONT_APP;
739 if( !aString.isEmpty() )
741 XclFontData aFontData;
742 GetFontPropSetHelper().ReadFontProperties( aFontData, aCtrlProp, EXC_FONTPROPSET_CONTROL );
743 if( (!aFontData.maName.isEmpty() ) && (aFontData.mnHeight > 0) )
744 nXclFont = GetFontBuffer().Insert( aFontData, EXC_COLOR_CTRLTEXT );
747 pTxo.reset( new XclTxo( aString, nXclFont ) );
748 pTxo->SetHorAlign( (mnObjType == EXC_OBJTYPE_BUTTON) ? EXC_OBJ_HOR_CENTER : EXC_OBJ_HOR_LEFT );
749 pTxo->SetVerAlign( EXC_OBJ_VER_CENTER );
752 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
754 // other properties
755 aCtrlProp.GetProperty( mnLineCount, "LineCount" );
757 // border style
758 sal_Int16 nApiButton = AwtVisualEffect::LOOK3D;
759 sal_Int16 nApiBorder = AwtVisualEffect::LOOK3D;
760 switch( nClassId )
762 case FormCompType::LISTBOX:
763 case FormCompType::COMBOBOX:
764 aCtrlProp.GetProperty( nApiBorder, "Border" );
765 break;
766 case FormCompType::CHECKBOX:
767 case FormCompType::RADIOBUTTON:
768 aCtrlProp.GetProperty( nApiButton, "VisualEffect" );
769 nApiBorder = AwtVisualEffect::NONE;
770 break;
771 // Push button cannot be set to flat in Excel
772 case FormCompType::COMMANDBUTTON:
773 nApiBorder = AwtVisualEffect::LOOK3D;
774 break;
775 // Label does not support a border in Excel
776 case FormCompType::FIXEDTEXT:
777 nApiBorder = AwtVisualEffect::NONE;
778 break;
779 /* Scroll bar and spin button have a "Border" property, but it is
780 really used for a border, and not for own 3D/flat look (#i34712#). */
781 case FormCompType::SCROLLBAR:
782 case FormCompType::SPINBUTTON:
783 nApiButton = AwtVisualEffect::LOOK3D;
784 nApiBorder = AwtVisualEffect::NONE;
785 break;
786 // Group box does not support flat style (#i34712#)
787 case FormCompType::GROUPBOX:
788 nApiBorder = AwtVisualEffect::LOOK3D;
789 break;
791 mbFlatButton = nApiButton != AwtVisualEffect::LOOK3D;
792 mbFlatBorder = nApiBorder != AwtVisualEffect::LOOK3D;
794 // control state
795 sal_Int16 nApiState = 0;
796 if( aCtrlProp.GetProperty( nApiState, "State" ) )
798 switch( nApiState )
800 case 0: mnState = EXC_OBJ_CHECKBOX_UNCHECKED; break;
801 case 1: mnState = EXC_OBJ_CHECKBOX_CHECKED; break;
802 case 2: mnState = EXC_OBJ_CHECKBOX_TRISTATE; break;
806 // special control contents
807 switch( nClassId )
809 case FormCompType::LISTBOX:
811 mbMultiSel = aCtrlProp.GetBoolProperty( "MultiSelection" );
812 Sequence< sal_Int16 > aSelection;
813 if( aCtrlProp.GetProperty( aSelection, "SelectedItems" ) )
815 if( aSelection.hasElements() )
817 mnSelEntry = aSelection[ 0 ] + 1;
818 comphelper::sequenceToContainer(maMultiSel, aSelection);
822 // convert listbox with dropdown button to Excel dropdown
823 if( aCtrlProp.GetBoolProperty( "Dropdown" ) )
824 mnObjType = EXC_OBJTYPE_DROPDOWN;
826 break;
828 case FormCompType::COMBOBOX:
830 Sequence< OUString > aStringList;
831 OUString aDefText;
832 if( aCtrlProp.GetProperty( aStringList, "StringItemList" ) &&
833 aCtrlProp.GetProperty( aDefText, "Text" ) &&
834 aStringList.hasElements() && !aDefText.isEmpty() )
836 auto nIndex = comphelper::findValue(aStringList, aDefText);
837 if( nIndex != -1 )
838 mnSelEntry = static_cast< sal_Int16 >( nIndex + 1 ); // 1-based
839 if( mnSelEntry > 0 )
840 maMultiSel.resize( 1, mnSelEntry - 1 );
843 // convert combobox without dropdown button to Excel listbox
844 if( !aCtrlProp.GetBoolProperty( "Dropdown" ) )
845 mnObjType = EXC_OBJTYPE_LISTBOX;
847 break;
849 case FormCompType::SCROLLBAR:
851 sal_Int32 nApiValue = 0;
852 if( aCtrlProp.GetProperty( nApiValue, "ScrollValueMin" ) )
853 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
854 if( aCtrlProp.GetProperty( nApiValue, "ScrollValueMax" ) )
855 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MIN );
856 if( aCtrlProp.GetProperty( nApiValue, "ScrollValue" ) )
857 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
858 if( aCtrlProp.GetProperty( nApiValue, "LineIncrement" ) )
859 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
860 if( aCtrlProp.GetProperty( nApiValue, "BlockIncrement" ) )
861 mnScrollPage = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
862 if( aCtrlProp.GetProperty( nApiValue, "Orientation" ) )
863 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
865 break;
867 case FormCompType::SPINBUTTON:
869 sal_Int32 nApiValue = 0;
870 if( aCtrlProp.GetProperty( nApiValue, "SpinValueMin" ) )
871 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
872 if( aCtrlProp.GetProperty( nApiValue, "SpinValueMax" ) )
873 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
874 if( aCtrlProp.GetProperty( nApiValue, "SpinValue" ) )
875 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
876 if( aCtrlProp.GetProperty( nApiValue, "SpinIncrement" ) )
877 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
878 if( aCtrlProp.GetProperty( nApiValue, "Orientation" ) )
879 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
881 break;
884 // spreadsheet links
885 ConvertSheetLinks( xShape );
888 bool XclExpTbxControlObj::SetMacroLink( const ScriptEventDescriptor& rEvent )
890 return XclMacroHelper::SetMacroLink( rEvent, meEventType );
893 void XclExpTbxControlObj::WriteSubRecs( XclExpStream& rStrm )
895 switch( mnObjType )
897 // *** Push buttons, labels ***
899 case EXC_OBJTYPE_BUTTON:
900 case EXC_OBJTYPE_LABEL:
901 // ftMacro - macro link
902 WriteMacroSubRec( rStrm );
903 break;
905 // *** Check boxes, option buttons ***
907 case EXC_OBJTYPE_CHECKBOX:
908 case EXC_OBJTYPE_OPTIONBUTTON:
910 // ftCbls - box properties
911 sal_uInt16 nStyle = 0;
912 ::set_flag( nStyle, EXC_OBJ_CHECKBOX_FLAT, mbFlatButton );
914 rStrm.StartRecord( EXC_ID_OBJCBLS, 12 );
915 rStrm << mnState;
916 rStrm.WriteZeroBytes( 8 );
917 rStrm << nStyle;
918 rStrm.EndRecord();
920 // ftMacro - macro link
921 WriteMacroSubRec( rStrm );
922 // ftCblsFmla subrecord - cell link
923 WriteCellLinkSubRec( rStrm, EXC_ID_OBJCBLSFMLA );
925 // ftCblsData subrecord - box properties, again
926 rStrm.StartRecord( EXC_ID_OBJCBLS, 8 );
927 rStrm << mnState;
928 rStrm.WriteZeroBytes( 4 );
929 rStrm << nStyle;
930 rStrm.EndRecord();
932 break;
934 // *** List boxes, combo boxes ***
936 case EXC_OBJTYPE_LISTBOX:
937 case EXC_OBJTYPE_DROPDOWN:
939 sal_uInt16 nEntryCount = GetSourceEntryCount();
941 // ftSbs subrecord - Scroll bars
942 sal_Int32 nLineHeight = XclTools::GetHmmFromTwips( 200 ); // always 10pt
943 if( mnObjType == EXC_OBJTYPE_LISTBOX )
944 mnLineCount = static_cast< sal_uInt16 >( mnHeight / nLineHeight );
945 mnScrollValue = 0;
946 mnScrollMin = 0;
947 sal_uInt16 nInvisLines = (nEntryCount >= mnLineCount) ? (nEntryCount - mnLineCount) : 0;
948 mnScrollMax = limit_cast< sal_uInt16 >( nInvisLines, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
949 mnScrollStep = 1;
950 mnScrollPage = limit_cast< sal_uInt16 >( mnLineCount, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
951 mbScrollHor = false;
952 WriteSbs( rStrm );
954 // ftMacro - macro link
955 WriteMacroSubRec( rStrm );
956 // ftSbsFmla subrecord - cell link
957 WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
959 // ftLbsData - source data range and box properties
960 sal_uInt16 nStyle = 0;
961 ::insert_value( nStyle, mbMultiSel ? EXC_OBJ_LISTBOX_MULTI : EXC_OBJ_LISTBOX_SINGLE, 4, 2 );
962 ::set_flag( nStyle, EXC_OBJ_LISTBOX_FLAT, mbFlatBorder );
964 rStrm.StartRecord( EXC_ID_OBJLBSDATA, 0 );
966 if( const XclTokenArray* pSrcRange = GetSourceRangeTokArr() )
968 rStrm << static_cast< sal_uInt16 >( (pSrcRange->GetSize() + 7) & 0xFFFE );
969 WriteFormula( rStrm, *pSrcRange );
971 else
972 rStrm << sal_uInt16( 0 );
974 rStrm << nEntryCount << mnSelEntry << nStyle << sal_uInt16( 0 );
975 if( mnObjType == EXC_OBJTYPE_LISTBOX )
977 if( nEntryCount )
979 ScfUInt8Vec aSelEx( nEntryCount, 0 );
980 for( const auto& rItem : maMultiSel )
981 if( rItem < nEntryCount )
982 aSelEx[ rItem ] = 1;
983 rStrm.Write( aSelEx.data(), aSelEx.size() );
986 else if( mnObjType == EXC_OBJTYPE_DROPDOWN )
988 rStrm << sal_uInt16( 0 ) << mnLineCount << sal_uInt16( 0 ) << sal_uInt16( 0 );
991 rStrm.EndRecord();
993 break;
995 // *** Spin buttons, scrollbars ***
997 case EXC_OBJTYPE_SPIN:
998 case EXC_OBJTYPE_SCROLLBAR:
1000 // ftSbs subrecord - scroll bars
1001 WriteSbs( rStrm );
1002 // ftMacro - macro link
1003 WriteMacroSubRec( rStrm );
1004 // ftSbsFmla subrecord - cell link
1005 WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
1007 break;
1009 // *** Group boxes ***
1011 case EXC_OBJTYPE_GROUPBOX:
1013 // ftMacro - macro link
1014 WriteMacroSubRec( rStrm );
1016 // ftGboData subrecord - group box properties
1017 sal_uInt16 nStyle = 0;
1018 ::set_flag( nStyle, EXC_OBJ_GROUPBOX_FLAT, mbFlatBorder );
1020 rStrm.StartRecord( EXC_ID_OBJGBODATA, 6 );
1021 rStrm << sal_uInt32( 0 )
1022 << nStyle;
1023 rStrm.EndRecord();
1025 break;
1029 void XclExpTbxControlObj::WriteCellLinkSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId )
1031 if( const XclTokenArray* pCellLink = GetCellLinkTokArr() )
1032 WriteFormulaSubRec( rStrm, nSubRecId, *pCellLink );
1035 void XclExpTbxControlObj::WriteSbs( XclExpStream& rStrm )
1037 sal_uInt16 nOrient = 0;
1038 ::set_flag( nOrient, EXC_OBJ_SCROLLBAR_HOR, mbScrollHor );
1039 sal_uInt16 nStyle = EXC_OBJ_SCROLLBAR_DEFFLAGS;
1040 ::set_flag( nStyle, EXC_OBJ_SCROLLBAR_FLAT, mbFlatButton );
1042 rStrm.StartRecord( EXC_ID_OBJSBS, 20 );
1043 rStrm << sal_uInt32( 0 ) // reserved
1044 << mnScrollValue // thumb position
1045 << mnScrollMin // thumb min pos
1046 << mnScrollMax // thumb max pos
1047 << mnScrollStep // line increment
1048 << mnScrollPage // page increment
1049 << nOrient // 0 = vertical, 1 = horizontal
1050 << sal_uInt16( 15 ) // thumb width
1051 << nStyle; // flags/style
1052 rStrm.EndRecord();
1055 //#endif
1057 XclExpChartObj::XclExpChartObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor, ScDocument* pDoc ) :
1058 XclObj( rObjMgr, EXC_OBJTYPE_CHART ),
1059 XclExpRoot( rObjMgr.GetRoot() ), mxShape( xShape ),
1060 mpDoc(pDoc)
1062 // create the MSODRAWING record contents for the chart object
1063 mrEscherEx.OpenContainer( ESCHER_SpContainer );
1064 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
1065 EscherPropertyContainer aPropOpt;
1066 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 );
1067 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 );
1068 aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x0800004E );
1069 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x0800004D );
1070 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 );
1071 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x0800004D );
1072 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080008 );
1073 aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00020000 );
1074 aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 );
1075 aPropOpt.Commit( mrEscherEx.GetStream() );
1077 // anchor
1078 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
1079 ImplWriteAnchor( pSdrObj, pChildAnchor );
1081 // client data (the following OBJ record)
1082 mrEscherEx.AddAtom( 0, ESCHER_ClientData );
1083 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
1084 mrEscherEx.UpdateDffFragmentEnd();
1086 // load the chart OLE object
1087 if( SdrOle2Obj* pSdrOleObj = dynamic_cast< SdrOle2Obj* >( pSdrObj ) )
1088 svt::EmbeddedObjectRef::TryRunningState( pSdrOleObj->GetObjRef() );
1090 // create the chart substream object
1091 ScfPropertySet aShapeProp( xShape );
1092 Reference< XModel > xModel;
1093 aShapeProp.GetProperty( xModel, "Model" );
1094 mxChartDoc.set( xModel,UNO_QUERY );
1095 css::awt::Rectangle aBoundRect;
1096 aShapeProp.GetProperty( aBoundRect, "BoundRect" );
1097 tools::Rectangle aChartRect( Point( aBoundRect.X, aBoundRect.Y ), Size( aBoundRect.Width, aBoundRect.Height ) );
1098 mxChart.reset( new XclExpChart( GetRoot(), xModel, aChartRect ) );
1101 XclExpChartObj::~XclExpChartObj()
1105 void XclExpChartObj::Save( XclExpStream& rStrm )
1107 // content of OBJ record
1108 XclObj::Save( rStrm );
1109 // chart substream
1110 mxChart->Save( rStrm );
1113 void XclExpChartObj::SaveXml( XclExpXmlStream& rStrm )
1115 sax_fastparser::FSHelperPtr pDrawing = rStrm.GetCurrentStream();
1117 // FIXME: two cell? it seems the two cell anchor is incorrect.
1118 pDrawing->startElement( FSNS( XML_xdr, XML_twoCellAnchor ), // OOXTODO: oneCellAnchor, absoluteAnchor
1119 XML_editAs, "oneCell" );
1120 Reference< XPropertySet > xPropSet( mxShape, UNO_QUERY );
1121 if (xPropSet.is())
1123 XclObjAny::WriteFromTo( rStrm, mxShape, GetTab() );
1124 ChartExport aChartExport(XML_xdr, pDrawing, mxChartDoc, &rStrm, drawingml::DOCUMENT_XLSX);
1125 std::shared_ptr<oox::drawingml::URLTransformer> pURLTransformer(new ScURLTransformer(*mpDoc));
1126 aChartExport.SetURLTranslator(pURLTransformer);
1127 static sal_Int32 nChartCount = 0;
1128 nChartCount++;
1129 sal_Int32 nID = rStrm.GetUniqueId();
1130 aChartExport.WriteChartObj( mxShape, nID, nChartCount );
1131 // TODO: get the correcto chart number
1134 pDrawing->singleElement( FSNS( XML_xdr, XML_clientData)
1135 // OOXTODO: XML_fLocksWithSheet
1136 // OOXTODO: XML_fPrintsWithSheet
1138 pDrawing->endElement( FSNS( XML_xdr, XML_twoCellAnchor ) );
1141 const css::uno::Reference<css::chart::XChartDocument>& XclExpChartObj::GetChartDoc() const
1143 return mxChartDoc;
1146 XclExpNote::XclExpNote(const XclExpRoot& rRoot, const ScAddress& rScPos,
1147 const ScPostIt* pScNote, const OUString& rAddText)
1148 : XclExpRecord(EXC_ID_NOTE)
1149 , mrRoot(rRoot)
1150 , maScPos(rScPos)
1151 , mnObjId(EXC_OBJ_INVALID_ID)
1152 , mbVisible(pScNote && pScNote->IsCaptionShown())
1153 , meTHA(SDRTEXTHORZADJUST_LEFT)
1154 , meTVA(SDRTEXTVERTADJUST_TOP)
1155 , mbAutoScale(false)
1156 , mbLocked(false)
1157 , mbAutoFill(false)
1158 , mbColHidden(false)
1159 , mbRowHidden(false)
1161 // get the main note text
1162 OUString aNoteText;
1163 if( pScNote )
1165 aNoteText = pScNote->GetText();
1166 const EditTextObject *pEditObj = pScNote->GetEditTextObject();
1167 if( pEditObj )
1168 mpNoteContents = XclExpStringHelper::CreateString( rRoot, *pEditObj );
1170 // append additional text
1171 aNoteText = ScGlobal::addToken( aNoteText, rAddText, '\n', 2 );
1173 // initialize record dependent on BIFF type
1174 switch( rRoot.GetBiff() )
1176 case EXC_BIFF5:
1177 maNoteText = OUStringToOString(aNoteText, rRoot.GetTextEncoding());
1178 break;
1180 case EXC_BIFF8:
1182 // TODO: additional text
1183 if( pScNote )
1185 if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ) )
1187 lcl_GetFromTo( rRoot, pCaption->GetLogicRect(), maScPos.Tab(), maCommentFrom, maCommentTo );
1188 if( const OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
1189 mnObjId = rRoot.GetObjectManager().AddObj( std::make_unique<XclObjComment>( rRoot.GetObjectManager(), pCaption->GetLogicRect(), pOPO->GetTextObject(), pCaption, mbVisible, maScPos, maCommentFrom, maCommentTo ) );
1191 SfxItemSet aItemSet = pCaption->GetMergedItemSet();
1192 meTVA = pCaption->GetTextVerticalAdjust();
1193 meTHA = pCaption->GetTextHorizontalAdjust();
1194 mbAutoScale = pCaption->GetFitToSize() != drawing::TextFitToSizeType_NONE;
1195 mbLocked = pCaption->IsMoveProtect() || pCaption->IsResizeProtect();
1197 // AutoFill style would change if Postit.cxx object creation values are changed
1198 OUString aCol(aItemSet.Get(XATTR_FILLCOLOR).GetValue());
1199 mbAutoFill = aCol.isEmpty() && (aItemSet.Get(XATTR_FILLSTYLE).GetValue() == drawing::FillStyle_SOLID);
1200 mbRowHidden = (rRoot.GetDoc().RowHidden(maScPos.Row(),maScPos.Tab()));
1201 mbColHidden = (rRoot.GetDoc().ColHidden(maScPos.Col(),maScPos.Tab()));
1203 // stAuthor (variable): An XLUnicodeString that specifies the name of the comment
1204 // author. String length MUST be greater than or equal to 1 and less than or equal
1205 // to 54.
1206 if( pScNote->GetAuthor().isEmpty() )
1207 maAuthor = XclExpString( " " );
1208 else
1209 maAuthor = XclExpString( pScNote->GetAuthor(), XclStrFlags::NONE, 54 );
1212 SetRecSize( 9 + maAuthor.GetSize() );
1214 break;
1216 default: DBG_ERROR_BIFF();
1220 void XclExpNote::Save( XclExpStream& rStrm )
1222 switch( rStrm.GetRoot().GetBiff() )
1224 case EXC_BIFF5:
1226 // write the NOTE record directly, there may be the need to create more than one
1227 const sal_Char* pcBuffer = maNoteText.getStr();
1228 sal_uInt16 nCharsLeft = static_cast< sal_uInt16 >( maNoteText.getLength() );
1230 while( nCharsLeft )
1232 sal_uInt16 nWriteChars = ::std::min( nCharsLeft, EXC_NOTE5_MAXLEN );
1234 rStrm.StartRecord( EXC_ID_NOTE, 6 + nWriteChars );
1235 if( pcBuffer == maNoteText.getStr() )
1237 // first record: row, col, length of complete text
1238 rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
1239 << static_cast< sal_uInt16 >( maScPos.Col() )
1240 << nCharsLeft; // still contains full length
1242 else
1244 // next records: -1, 0, length of current text segment
1245 rStrm << sal_uInt16( 0xFFFF )
1246 << sal_uInt16( 0 )
1247 << nWriteChars;
1249 rStrm.Write( pcBuffer, nWriteChars );
1250 rStrm.EndRecord();
1252 pcBuffer += nWriteChars;
1253 nCharsLeft = nCharsLeft - nWriteChars;
1256 break;
1258 case EXC_BIFF8:
1259 if( mnObjId != EXC_OBJ_INVALID_ID )
1260 XclExpRecord::Save( rStrm );
1261 break;
1263 default: DBG_ERROR_BIFF();
1267 void XclExpNote::WriteBody( XclExpStream& rStrm )
1269 // BIFF5/BIFF7 is written separately
1270 OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
1272 sal_uInt16 nFlags = 0;
1273 ::set_flag( nFlags, EXC_NOTE_VISIBLE, mbVisible );
1275 rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
1276 << static_cast< sal_uInt16 >( maScPos.Col() )
1277 << nFlags
1278 << mnObjId
1279 << maAuthor
1280 << sal_uInt8( 0 );
1283 void XclExpNote::WriteXml( sal_Int32 nAuthorId, XclExpXmlStream& rStrm )
1285 sax_fastparser::FSHelperPtr rComments = rStrm.GetCurrentStream();
1287 rComments->startElement( XML_comment,
1288 XML_ref, XclXmlUtils::ToOString(&mrRoot.GetDoc(), maScPos),
1289 XML_authorId, OString::number(nAuthorId)
1290 // OOXTODO: XML_guid
1292 rComments->startElement(XML_text);
1293 // OOXTODO: phoneticPr, rPh, r
1294 if( mpNoteContents )
1295 mpNoteContents->WriteXml( rStrm );
1296 rComments->endElement( XML_text );
1299 Export of commentPr is disabled, since the current (Oct 2010)
1300 version of MSO 2010 doesn't yet support commentPr
1302 #if 1//def XLSX_OOXML_FUTURE
1303 if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1305 rComments->startElement(FSNS(XML_mc, XML_AlternateContent));
1306 rComments->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "v2");
1307 rComments->startElement( XML_commentPr,
1308 XML_autoFill, ToPsz( mbAutoFill ),
1309 XML_autoScale, ToPsz( mbAutoScale ),
1310 XML_colHidden, ToPsz( mbColHidden ),
1311 XML_locked, ToPsz( mbLocked ),
1312 XML_rowHidden, ToPsz( mbRowHidden ),
1313 XML_textHAlign, ToHorizAlign( meTHA ),
1314 XML_textVAlign, ToVertAlign( meTVA ) );
1315 rComments->startElement(XML_anchor, XML_moveWithCells, "false", XML_sizeWithCells, "false");
1316 rComments->startElement(FSNS(XML_xdr, XML_from));
1317 lcl_WriteAnchorVertex( rComments, maCommentFrom );
1318 rComments->endElement( FSNS( XML_xdr, XML_from ) );
1319 rComments->startElement(FSNS(XML_xdr, XML_to));
1320 lcl_WriteAnchorVertex( rComments, maCommentTo );
1321 rComments->endElement( FSNS( XML_xdr, XML_to ) );
1322 rComments->endElement( XML_anchor );
1323 rComments->endElement( XML_commentPr );
1325 rComments->endElement( FSNS( XML_mc, XML_Choice ) );
1326 rComments->startElement(FSNS(XML_mc, XML_Fallback));
1327 // Any fallback code ?
1328 rComments->endElement( FSNS( XML_mc, XML_Fallback ) );
1329 rComments->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1331 #endif
1332 rComments->endElement( XML_comment );
1335 XclMacroHelper::XclMacroHelper( const XclExpRoot& rRoot ) :
1336 XclExpControlHelper( rRoot )
1340 XclMacroHelper::~XclMacroHelper()
1344 void XclMacroHelper::WriteMacroSubRec( XclExpStream& rStrm )
1346 if( mxMacroLink )
1347 WriteFormulaSubRec( rStrm, EXC_ID_OBJMACRO, *mxMacroLink );
1350 bool
1351 XclMacroHelper::SetMacroLink( const ScriptEventDescriptor& rEvent, const XclTbxEventType& nEventType )
1353 OUString aMacroName = XclControlHelper::ExtractFromMacroDescriptor( rEvent, nEventType );
1354 if( !aMacroName.isEmpty() )
1356 return SetMacroLink( aMacroName );
1358 return false;
1361 bool
1362 XclMacroHelper::SetMacroLink( const OUString& rMacroName )
1364 if( !rMacroName.isEmpty() )
1366 sal_uInt16 nExtSheet = GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC );
1367 sal_uInt16 nNameIdx = GetNameManager().InsertMacroCall( rMacroName, true, false );
1368 mxMacroLink = GetFormulaCompiler().CreateNameXFormula( nExtSheet, nNameIdx );
1369 return true;
1371 return false;
1374 XclExpShapeObj::XclExpShapeObj( XclExpObjectManager& rRoot, css::uno::Reference< css::drawing::XShape > const & xShape, ScDocument* pDoc ) :
1375 XclObjAny( rRoot, xShape, pDoc ),
1376 XclMacroHelper( rRoot )
1378 if( SdrObject* pSdrObj = ::GetSdrObjectFromXShape( xShape ) )
1380 ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pSdrObj );
1381 if ( pInfo && !pInfo->GetMacro().isEmpty() )
1382 // 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
1383 // SetMacroLink( XclControlHelper::GetXclMacroName( pInfo->GetMacro(), rRoot.GetDocShell() ) );
1384 SetMacroLink( XclTools::GetXclMacroName( pInfo->GetMacro() ) );
1388 XclExpShapeObj::~XclExpShapeObj()
1392 void XclExpShapeObj::WriteSubRecs( XclExpStream& rStrm )
1394 XclObjAny::WriteSubRecs( rStrm );
1395 WriteMacroSubRec( rStrm );
1398 XclExpComments::XclExpComments( SCTAB nTab, XclExpRecordList< XclExpNote >& rNotes )
1399 : mnTab( nTab ), mrNotes( rNotes )
1403 void XclExpComments::SaveXml( XclExpXmlStream& rStrm )
1405 if( mrNotes.IsEmpty() )
1406 return;
1408 sax_fastparser::FSHelperPtr rComments = rStrm.CreateOutputStream(
1409 XclXmlUtils::GetStreamName( "xl/", "comments", mnTab + 1 ),
1410 XclXmlUtils::GetStreamName( "../", "comments", mnTab + 1 ),
1411 rStrm.GetCurrentStream()->getOutputStream(),
1412 "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
1413 OUStringToOString(oox::getRelationship(Relationship::COMMENTS), RTL_TEXTENCODING_UTF8).getStr());
1414 rStrm.PushStream( rComments );
1416 if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1417 rComments->startElement( XML_comments,
1418 XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(),
1419 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8(),
1420 FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)).toUtf8(),
1421 FSNS(XML_xmlns, XML_v2), rStrm.getNamespaceURL(OOX_NS(mceTest)).toUtf8(),
1422 FSNS( XML_mc, XML_Ignorable ), "v2" );
1423 else
1424 rComments->startElement( XML_comments,
1425 XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(),
1426 FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)).toUtf8() );
1428 rComments->startElement(XML_authors);
1430 typedef std::set<OUString> Authors;
1431 Authors aAuthors;
1433 size_t nNotes = mrNotes.GetSize();
1434 for( size_t i = 0; i < nNotes; ++i )
1436 aAuthors.insert( XclXmlUtils::ToOUString( mrNotes.GetRecord( i )->GetAuthor() ) );
1439 for( const auto& rAuthor : aAuthors )
1441 rComments->startElement(XML_author);
1442 rComments->writeEscaped( rAuthor );
1443 rComments->endElement( XML_author );
1446 rComments->endElement( XML_authors );
1447 rComments->startElement(XML_commentList);
1449 Authors::const_iterator aAuthorsBegin = aAuthors.begin();
1450 for( size_t i = 0; i < nNotes; ++i )
1452 XclExpRecordList< XclExpNote >::RecordRefType xNote = mrNotes.GetRecord( i );
1453 Authors::const_iterator aAuthor = aAuthors.find(
1454 XclXmlUtils::ToOUString( xNote->GetAuthor() ) );
1455 sal_Int32 nAuthorId = distance( aAuthorsBegin, aAuthor );
1456 xNote->WriteXml( nAuthorId, rStrm );
1459 rComments->endElement( XML_commentList );
1460 rComments->endElement( XML_comments );
1462 rStrm.PopStream();
1465 // object manager =============================================================
1467 XclExpObjectManager::XclExpObjectManager( const XclExpRoot& rRoot ) :
1468 XclExpRoot( rRoot )
1470 InitStream( true );
1471 mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm ) );
1474 XclExpObjectManager::XclExpObjectManager( const XclExpObjectManager& rParent ) :
1475 XclExpRoot( rParent.GetRoot() )
1477 InitStream( false );
1478 mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm, rParent.mxEscherEx.get() ) );
1481 XclExpObjectManager::~XclExpObjectManager()
1485 XclExpDffAnchorBase* XclExpObjectManager::CreateDffAnchor() const
1487 return new XclExpDffSheetAnchor( GetRoot() );
1490 std::shared_ptr< XclExpRecordBase > XclExpObjectManager::CreateDrawingGroup()
1492 return std::shared_ptr< XclExpRecordBase >( new XclExpMsoDrawingGroup( *mxEscherEx ) );
1495 void XclExpObjectManager::StartSheet()
1497 mxObjList.reset( new XclExpObjList( GetRoot(), *mxEscherEx ) );
1500 std::shared_ptr< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const SdrPage* pSdrPage )
1502 if( pSdrPage )
1503 mxEscherEx->AddSdrPage( *pSdrPage );
1504 // the first dummy object may still be open
1505 OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1506 while( mxEscherEx->GetGroupLevel() )
1507 mxEscherEx->LeaveGroup();
1508 mxObjList->EndSheet();
1509 return mxObjList;
1512 std::shared_ptr< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const Reference< XShapes >& rxShapes )
1514 if( rxShapes.is() )
1515 mxEscherEx->AddUnoShapes( rxShapes );
1516 // the first dummy object may still be open
1517 OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1518 while( mxEscherEx->GetGroupLevel() )
1519 mxEscherEx->LeaveGroup();
1520 mxObjList->EndSheet();
1521 return mxObjList;
1524 void XclExpObjectManager::EndDocument()
1526 mxEscherEx->EndDocument();
1529 XclExpMsoDrawing* XclExpObjectManager::GetMsodrawingPerSheet()
1531 return mxObjList->GetMsodrawingPerSheet();
1534 bool XclExpObjectManager::HasObj() const
1536 return !mxObjList->empty();
1539 sal_uInt16 XclExpObjectManager::AddObj( std::unique_ptr<XclObj> pObjRec )
1541 return mxObjList->Add( std::move(pObjRec) );
1544 std::unique_ptr<XclObj> XclExpObjectManager::RemoveLastObj()
1546 return mxObjList->pop_back();
1549 void XclExpObjectManager::InitStream( bool bTempFile )
1551 if( bTempFile )
1553 mxTempFile.reset( new ::utl::TempFile );
1554 if( mxTempFile->IsValid() )
1556 mxTempFile->EnableKillingFile();
1557 mxDffStrm = ::utl::UcbStreamHelper::CreateStream( mxTempFile->GetURL(), StreamMode::STD_READWRITE );
1561 if( !mxDffStrm.get() )
1562 mxDffStrm.reset( new SvMemoryStream );
1564 mxDffStrm->SetEndian( SvStreamEndian::LITTLE );
1567 XclExpEmbeddedObjectManager::XclExpEmbeddedObjectManager(
1568 const XclExpObjectManager& rParent, const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
1569 XclExpObjectManager( rParent ),
1570 maPageSize( rPageSize ),
1571 mnScaleX( nScaleX ),
1572 mnScaleY( nScaleY )
1576 XclExpDffAnchorBase* XclExpEmbeddedObjectManager::CreateDffAnchor() const
1578 return new XclExpDffEmbeddedAnchor( GetRoot(), maPageSize, mnScaleX, mnScaleY );
1581 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */