1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <xeescher.hxx>
21 
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>
32 
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>
41 
42 #include <unonames.hxx>
43 #include <convuno.hxx>
44 #include <postit.hxx>
45 
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>
64 
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>
73 
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;
92 
93 namespace
94 {
95 
lcl_hmm2px(long nPixel)96 long lcl_hmm2px(long nPixel)
97 {
98     return static_cast<long>(nPixel*PIXEL_PER_INCH/1000.0/CM_PER_INCH + 0.5);
99 }
100 
ToHorizAlign(SdrTextHorzAdjust eAdjust)101 const char *ToHorizAlign( SdrTextHorzAdjust eAdjust )
102 {
103     switch( eAdjust )
104     {
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";
114     }
115 }
116 
ToVertAlign(SdrTextVertAdjust eAdjust)117 const char *ToVertAlign( SdrTextVertAdjust eAdjust )
118 {
119     switch( eAdjust )
120     {
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";
130     }
131 }
132 
lcl_WriteAnchorVertex(sax_fastparser::FSHelperPtr const & rComments,const tools::Rectangle & aRect)133 void lcl_WriteAnchorVertex( sax_fastparser::FSHelperPtr const & rComments, const tools::Rectangle &aRect )
134 {
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 ) );
147 }
148 
lcl_hmm2output(long value,bool bInEMU)149 long lcl_hmm2output(long value, bool bInEMU)
150 {
151     if (bInEMU)
152         return oox::drawingml::convertHmmToEmu(value);
153     else
154         return lcl_hmm2px(value);
155 }
156 
lcl_GetFromTo(const XclExpRoot & rRoot,const tools::Rectangle & aRect,sal_Int32 nTab,tools::Rectangle & aFrom,tools::Rectangle & aTo,bool bInEMU=false)157 void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_Int32 nTab, tools::Rectangle &aFrom, tools::Rectangle &aTo, bool bInEMU = false )
158 {
159     sal_Int32 nCol = 0, nRow = 0;
160     sal_Int32 nColOff = 0, nRowOff= 0;
161 
162     const bool bRTL = rRoot.GetDoc().IsNegativePage( nTab );
163     if (!bRTL)
164     {
165         while(true)
166         {
167             tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
168             if( r.Left() <= aRect.Left() )
169             {
170                 nCol++;
171                 nColOff = aRect.Left() - r.Left();
172             }
173             if( r.Top() <= aRect.Top() )
174             {
175                 nRow++;
176                 nRowOff = aRect.Top() - r.Top();
177             }
178             if( r.Left() > aRect.Left() && r.Top() > aRect.Top() )
179             {
180                 aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
181                                    nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
182                 break;
183             }
184         }
185     }
186     else
187     {
188         while(true)
189         {
190             tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
191             if( r.Left() >= aRect.Left() )
192             {
193                 nCol++;
194                 nColOff = r.Left() - aRect.Left();
195             }
196             if( r.Top() <= aRect.Top() )
197             {
198                 nRow++;
199                 nRowOff = aRect.Top() - r.Top();
200             }
201             if( r.Left() < aRect.Left() && r.Top() > aRect.Top() )
202             {
203                 aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
204                                    nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
205                 break;
206             }
207         }
208     }
209     if (!bRTL)
210     {
211         while(true)
212         {
213             tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
214             if( r.Right() < aRect.Right() )
215                 nCol++;
216             if( r.Bottom() < aRect.Bottom() )
217                 nRow++;
218             if( r.Right() >= aRect.Right() && r.Bottom() >= aRect.Bottom() )
219             {
220                 aTo = tools::Rectangle( nCol, lcl_hmm2output( aRect.Right() - r.Left(), bInEMU ),
221                                  nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
222                 break;
223             }
224         }
225     }
226     else
227     {
228         while(true)
229         {
230             tools::Rectangle r = rRoot.GetDoc().GetMMRect( nCol,nRow,nCol,nRow,nTab );
231             if( r.Right() >= aRect.Right() )
232                 nCol++;
233             if( r.Bottom() < aRect.Bottom() )
234                 nRow++;
235             if( r.Right() < aRect.Right() && r.Bottom() >= aRect.Bottom() )
236             {
237                 aTo = tools::Rectangle( nCol, lcl_hmm2output( r.Left() - aRect.Right(), bInEMU ),
238                                  nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
239                 break;
240             }
241         }
242     }
243 }
244 
245 } // namespace
246 
247 // Escher client anchor =======================================================
248 
XclExpDffAnchorBase(const XclExpRoot & rRoot,sal_uInt16 nFlags)249 XclExpDffAnchorBase::XclExpDffAnchorBase( const XclExpRoot& rRoot, sal_uInt16 nFlags ) :
250     XclExpRoot( rRoot ),
251     mnFlags( nFlags )
252 {
253 }
254 
SetFlags(const SdrObject & rSdrObj)255 void XclExpDffAnchorBase::SetFlags( const SdrObject& rSdrObj )
256 {
257     ImplSetFlags( rSdrObj );
258 }
259 
SetSdrObject(const SdrObject & rSdrObj)260 void XclExpDffAnchorBase::SetSdrObject( const SdrObject& rSdrObj )
261 {
262     ImplSetFlags( rSdrObj );
263     ImplCalcAnchorRect( rSdrObj.GetCurrentBoundRect(), MapUnit::Map100thMM );
264 }
265 
WriteDffData(EscherEx & rEscherEx) const266 void XclExpDffAnchorBase::WriteDffData( EscherEx& rEscherEx ) const
267 {
268     rEscherEx.AddAtom( 18, ESCHER_ClientAnchor );
269     rEscherEx.GetStream().WriteUInt16( mnFlags );
270     WriteXclObjAnchor( rEscherEx.GetStream(), maAnchor );
271 }
272 
WriteData(EscherEx & rEscherEx,const tools::Rectangle & rRect)273 void XclExpDffAnchorBase::WriteData( EscherEx& rEscherEx, const tools::Rectangle& rRect )
274 {
275     // the passed rectangle is in twips
276     ImplCalcAnchorRect( rRect, MapUnit::MapTwip );
277     WriteDffData( rEscherEx );
278 }
279 
ImplSetFlags(const SdrObject &)280 void XclExpDffAnchorBase::ImplSetFlags( const SdrObject& )
281 {
282     OSL_FAIL( "XclExpDffAnchorBase::ImplSetFlags - not implemented" );
283 }
284 
ImplCalcAnchorRect(const tools::Rectangle &,MapUnit)285 void XclExpDffAnchorBase::ImplCalcAnchorRect( const tools::Rectangle&, MapUnit )
286 {
287     OSL_FAIL( "XclExpDffAnchorBase::ImplCalcAnchorRect - not implemented" );
288 }
289 
XclExpDffSheetAnchor(const XclExpRoot & rRoot)290 XclExpDffSheetAnchor::XclExpDffSheetAnchor( const XclExpRoot& rRoot ) :
291     XclExpDffAnchorBase( rRoot ),
292     mnScTab( rRoot.GetCurrScTab() )
293 {
294 }
295 
ImplSetFlags(const SdrObject & rSdrObj)296 void XclExpDffSheetAnchor::ImplSetFlags( const SdrObject& rSdrObj )
297 {
298     // set flags for cell/page anchoring
299     if ( ScDrawLayer::GetAnchorType( rSdrObj ) == SCA_CELL )
300         mnFlags = 0;
301     else
302         mnFlags = EXC_ESC_ANCHOR_LOCKED;
303 }
304 
ImplCalcAnchorRect(const tools::Rectangle & rRect,MapUnit eMapUnit)305 void XclExpDffSheetAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
306 {
307     maAnchor.SetRect( GetRoot(), mnScTab, rRect, eMapUnit );
308 }
309 
XclExpDffEmbeddedAnchor(const XclExpRoot & rRoot,const Size & rPageSize,sal_Int32 nScaleX,sal_Int32 nScaleY)310 XclExpDffEmbeddedAnchor::XclExpDffEmbeddedAnchor( const XclExpRoot& rRoot,
311         const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
312     XclExpDffAnchorBase( rRoot ),
313     maPageSize( rPageSize ),
314     mnScaleX( nScaleX ),
315     mnScaleY( nScaleY )
316 {
317 }
318 
ImplSetFlags(const SdrObject &)319 void XclExpDffEmbeddedAnchor::ImplSetFlags( const SdrObject& /*rSdrObj*/ )
320 {
321     // TODO (unsupported feature): fixed size
322 }
323 
ImplCalcAnchorRect(const tools::Rectangle & rRect,MapUnit eMapUnit)324 void XclExpDffEmbeddedAnchor::ImplCalcAnchorRect( const tools::Rectangle& rRect, MapUnit eMapUnit )
325 {
326     maAnchor.SetRect( maPageSize, mnScaleX, mnScaleY, rRect, eMapUnit );
327 }
328 
XclExpDffNoteAnchor(const XclExpRoot & rRoot,const tools::Rectangle & rRect)329 XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot& rRoot, const tools::Rectangle& rRect ) :
330     XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_SIZELOCKED )
331 {
332     maAnchor.SetRect( rRoot, rRoot.GetCurrScTab(), rRect, MapUnit::Map100thMM );
333 }
334 
XclExpDffDropDownAnchor(const XclExpRoot & rRoot,const ScAddress & rScPos)335 XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
336     XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_POSLOCKED )
337 {
338     GetAddressConverter().ConvertAddress( maAnchor.maFirst, rScPos, true );
339     maAnchor.maLast.mnCol = maAnchor.maFirst.mnCol + 1;
340     maAnchor.maLast.mnRow = maAnchor.maFirst.mnRow + 1;
341     maAnchor.mnLX = maAnchor.mnTY = maAnchor.mnRX = maAnchor.mnBY = 0;
342 }
343 
344 // MSODRAWING* records ========================================================
345 
XclExpMsoDrawingBase(XclEscherEx & rEscherEx,sal_uInt16 nRecId)346 XclExpMsoDrawingBase::XclExpMsoDrawingBase( XclEscherEx& rEscherEx, sal_uInt16 nRecId ) :
347     XclExpRecord( nRecId ),
348     mrEscherEx( rEscherEx ),
349     mnFragmentKey( rEscherEx.InitNextDffFragment() )
350 {
351 }
352 
WriteBody(XclExpStream & rStrm)353 void XclExpMsoDrawingBase::WriteBody( XclExpStream& rStrm )
354 {
355     OSL_ENSURE( mrEscherEx.GetStreamPos() == mrEscherEx.GetDffFragmentPos( mnFragmentKey ),
356         "XclExpMsoDrawingBase::WriteBody - DFF stream position mismatch" );
357     rStrm.CopyFromStream( mrEscherEx.GetStream(), mrEscherEx.GetDffFragmentSize( mnFragmentKey ) );
358 }
359 
XclExpMsoDrawingGroup(XclEscherEx & rEscherEx)360 XclExpMsoDrawingGroup::XclExpMsoDrawingGroup( XclEscherEx& rEscherEx ) :
361     XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWINGGROUP )
362 {
363     SvStream& rDffStrm = mrEscherEx.GetStream();
364 
365     // write the DGGCONTAINER with some default settings
366     mrEscherEx.OpenContainer( ESCHER_DggContainer );
367 
368     // TODO: stuff the OPT atom with our own document defaults?
369     static const sal_uInt8 spnDffOpt[] = {
370         0xBF, 0x00, 0x08, 0x00, 0x08, 0x00, 0x81, 0x01,
371         0x09, 0x00, 0x00, 0x08, 0xC0, 0x01, 0x40, 0x00,
372         0x00, 0x08
373     };
374     mrEscherEx.AddAtom( sizeof( spnDffOpt ), ESCHER_OPT, 3, 3 );
375     rDffStrm.WriteBytes(spnDffOpt, sizeof(spnDffOpt));
376 
377     // SPLITMENUCOLORS contains colors in toolbar
378     static const sal_uInt8 spnDffSplitMenuColors[] = {
379         0x0D, 0x00, 0x00, 0x08, 0x0C, 0x00, 0x00, 0x08,
380         0x17, 0x00, 0x00, 0x08, 0xF7, 0x00, 0x00, 0x10
381     };
382     mrEscherEx.AddAtom( sizeof( spnDffSplitMenuColors ), ESCHER_SplitMenuColors, 0, 4 );
383     rDffStrm.WriteBytes(spnDffSplitMenuColors, sizeof(spnDffSplitMenuColors));
384 
385     // close the DGGCONTAINER
386     mrEscherEx.CloseContainer();
387     mrEscherEx.UpdateDffFragmentEnd();
388 }
389 
XclExpMsoDrawing(XclEscherEx & rEscherEx)390 XclExpMsoDrawing::XclExpMsoDrawing( XclEscherEx& rEscherEx ) :
391     XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWING )
392 {
393 }
394 
XclExpImgData(const Graphic & rGraphic,sal_uInt16 nRecId)395 XclExpImgData::XclExpImgData( const Graphic& rGraphic, sal_uInt16 nRecId ) :
396     maGraphic( rGraphic ),
397     mnRecId( nRecId )
398 {
399 }
400 
Save(XclExpStream & rStrm)401 void XclExpImgData::Save( XclExpStream& rStrm )
402 {
403     Bitmap aBmp = maGraphic.GetBitmapEx().GetBitmap();
404     if( aBmp.GetBitCount() != 24 )
405         aBmp.Convert( BmpConversion::N24Bit );
406 
407     Bitmap::ScopedReadAccess pAccess(aBmp);
408     if( pAccess )
409     {
410         sal_Int32 nWidth = ::std::min< sal_Int32 >( pAccess->Width(), 0xFFFF );
411         sal_Int32 nHeight = ::std::min< sal_Int32 >( pAccess->Height(), 0xFFFF );
412         if( (nWidth > 0) && (nHeight > 0) )
413         {
414             sal_uInt8 nPadding = static_cast< sal_uInt8 >( nWidth & 0x03 );
415             sal_uInt32 nTmpSize = static_cast< sal_uInt32 >( (nWidth * 3 + nPadding) * nHeight + 12 );
416 
417             rStrm.StartRecord( mnRecId, nTmpSize + 4 );
418 
419             rStrm   << EXC_IMGDATA_BMP                      // BMP format
420                     << EXC_IMGDATA_WIN                      // Windows
421                     << nTmpSize                             // size after _this_ field
422                     << sal_uInt32( 12 )                     // BITMAPCOREHEADER size
423                     << static_cast< sal_uInt16 >( nWidth )  // width
424                     << static_cast< sal_uInt16 >( nHeight ) // height
425                     << sal_uInt16( 1 )                      // planes
426                     << sal_uInt16( 24 );                    // bits per pixel
427 
428             for( sal_Int32 nY = nHeight - 1; nY >= 0; --nY )
429             {
430                 Scanline pScanline = pAccess->GetScanline( nY );
431                 for( sal_Int32 nX = 0; nX < nWidth; ++nX )
432                 {
433                     const BitmapColor& rBmpColor = pAccess->GetPixelFromData( pScanline, nX );
434                     rStrm << rBmpColor.GetBlue() << rBmpColor.GetGreen() << rBmpColor.GetRed();
435                 }
436                 rStrm.WriteZeroBytes( nPadding );
437             }
438 
439             rStrm.EndRecord();
440         }
441     }
442 }
443 
SaveXml(XclExpXmlStream & rStrm)444 void XclExpImgData::SaveXml( XclExpXmlStream& rStrm )
445 {
446     sax_fastparser::FSHelperPtr pWorksheet = rStrm.GetCurrentStream();
447 
448     DrawingML aDML(pWorksheet, &rStrm, drawingml::DOCUMENT_XLSX);
449     OUString rId = aDML.WriteImage( maGraphic );
450     pWorksheet->singleElement(XML_picture, FSNS(XML_r, XML_id), rId.toUtf8());
451 }
452 
XclExpControlHelper(const XclExpRoot & rRoot)453 XclExpControlHelper::XclExpControlHelper( const XclExpRoot& rRoot ) :
454     XclExpRoot( rRoot ),
455     mnEntryCount( 0 )
456 {
457 }
458 
~XclExpControlHelper()459 XclExpControlHelper::~XclExpControlHelper()
460 {
461 }
462 
ConvertSheetLinks(Reference<XShape> const & xShape)463 void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > const & xShape )
464 {
465     mxCellLink.reset();
466     mxCellLinkAddress.SetInvalid();
467     mxSrcRange.reset();
468     mnEntryCount = 0;
469 
470     // get control model
471     Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
472     if( !xCtrlModel.is() )
473         return;
474 
475     // *** cell link *** ------------------------------------------------------
476 
477     Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
478     if( xBindable.is() )
479     {
480         Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
481         if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
482         {
483             ScfPropertySet aBindProp( xServInfo );
484             CellAddress aApiAddress;
485             if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
486             {
487                 ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
488                 if( GetTabInfo().IsExportTab( mxCellLinkAddress.Tab() ) )
489                     mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, mxCellLinkAddress );
490             }
491         }
492     }
493 
494     // *** source range *** ---------------------------------------------------
495 
496     Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY );
497     if( xEntrySink.is() )
498     {
499         Reference< XServiceInfo > xServInfo( xEntrySink->getListEntrySource(), UNO_QUERY );
500         if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_LISTSOURCE ) )
501         {
502             ScfPropertySet aSinkProp( xServInfo );
503             CellRangeAddress aApiRange;
504             if( aSinkProp.GetProperty( aApiRange, SC_UNONAME_CELLRANGE ) )
505             {
506                 ScRange aSrcRange;
507                 ScUnoConversion::FillScRange( aSrcRange, aApiRange );
508                 if( (aSrcRange.aStart.Tab() == aSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( aSrcRange.aStart.Tab() ) )
509                     mxSrcRange = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aSrcRange );
510                 mnEntryCount = static_cast< sal_uInt16 >( aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1 );
511             }
512         }
513     }
514 }
515 
WriteFormula(XclExpStream & rStrm,const XclTokenArray & rTokArr)516 void XclExpControlHelper::WriteFormula( XclExpStream& rStrm, const XclTokenArray& rTokArr )
517 {
518     sal_uInt16 nFmlaSize = rTokArr.GetSize();
519     rStrm << nFmlaSize << sal_uInt32( 0 );
520     rTokArr.WriteArray( rStrm );
521     if( nFmlaSize & 1 )             // pad to 16-bit
522         rStrm << sal_uInt8( 0 );
523 }
524 
WriteFormulaSubRec(XclExpStream & rStrm,sal_uInt16 nSubRecId,const XclTokenArray & rTokArr)525 void XclExpControlHelper::WriteFormulaSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId, const XclTokenArray& rTokArr )
526 {
527     rStrm.StartRecord( nSubRecId, (rTokArr.GetSize() + 5) & ~1 );
528     WriteFormula( rStrm, rTokArr );
529     rStrm.EndRecord();
530 }
531 
532 //delete for exporting OCX
533 //#if EXC_EXP_OCX_CTRL
534 
XclExpOcxControlObj(XclExpObjectManager & rObjMgr,Reference<XShape> const & xShape,const tools::Rectangle * pChildAnchor,const OUString & rClassName,sal_uInt32 nStrmStart,sal_uInt32 nStrmSize)535 XclExpOcxControlObj::XclExpOcxControlObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape,
536         const tools::Rectangle* pChildAnchor, const OUString& rClassName, sal_uInt32 nStrmStart, sal_uInt32 nStrmSize ) :
537     XclObj( rObjMgr, EXC_OBJTYPE_PICTURE, true ),
538     XclExpControlHelper( rObjMgr.GetRoot() ),
539     maClassName( rClassName ),
540     mnStrmStart( nStrmStart ),
541     mnStrmSize( nStrmSize )
542 {
543     ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
544 
545     // OBJ record flags
546     SetLocked( true );
547     SetPrintable( aCtrlProp.GetBoolProperty( "Printable" ) );
548     SetAutoFill( false );
549     SetAutoLine( false );
550 
551     // fill DFF property set
552     mrEscherEx.OpenContainer( ESCHER_SpContainer );
553     mrEscherEx.AddShape( ESCHER_ShpInst_HostControl,
554                          ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape );
555     tools::Rectangle aDummyRect;
556     EscherPropertyContainer aPropOpt( mrEscherEx.GetGraphicProvider(), mrEscherEx.QueryPictureStream(), aDummyRect );
557     aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape,    0x00080008 );   // bool field
558     aPropOpt.AddOpt( ESCHER_Prop_lineColor,         0x08000040 );
559     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash,   0x00080000 );   // bool field
560 
561     // #i51348# name of the control, may overwrite shape name
562     OUString aCtrlName;
563     if( aCtrlProp.GetProperty( aCtrlName, "Name" ) && !aCtrlName.isEmpty() )
564         aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
565 
566     // meta file
567     //TODO - needs check
568     Reference< XPropertySet > xShapePS( xShape, UNO_QUERY );
569     if( xShapePS.is() && aPropOpt.CreateGraphicProperties( xShapePS, "MetaFile", false ) )
570     {
571         sal_uInt32 nBlipId;
572         if( aPropOpt.GetOpt( ESCHER_Prop_pib, nBlipId ) )
573             aPropOpt.AddOpt( ESCHER_Prop_pictureId, nBlipId );
574     }
575 
576     // write DFF property set to stream
577     aPropOpt.Commit( mrEscherEx.GetStream() );
578 
579     // anchor
580     ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
581 
582     mrEscherEx.AddAtom( 0, ESCHER_ClientData );                       // OBJ record
583     mrEscherEx.CloseContainer();  // ESCHER_SpContainer
584     mrEscherEx.UpdateDffFragmentEnd();
585 
586     // spreadsheet links
587     ConvertSheetLinks( xShape );
588 }
589 
WriteSubRecs(XclExpStream & rStrm)590 void XclExpOcxControlObj::WriteSubRecs( XclExpStream& rStrm )
591 {
592     // OBJCF - clipboard format
593     rStrm.StartRecord( EXC_ID_OBJCF, 2 );
594     rStrm << sal_uInt16( 2 );
595     rStrm.EndRecord();
596 
597     // OBJFLAGS
598     rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 );
599     rStrm << sal_uInt16( 0x0031 );
600     rStrm.EndRecord();
601 
602     // OBJPICTFMLA
603     XclExpString aClass( maClassName );
604     sal_uInt16 nClassNameSize = static_cast< sal_uInt16 >( aClass.GetSize() );
605     sal_uInt16 nClassNamePad = nClassNameSize & 1;
606     sal_uInt16 nFirstPartSize = 12 + nClassNameSize + nClassNamePad;
607 
608     const XclTokenArray* pCellLink = GetCellLinkTokArr();
609     sal_uInt16 nCellLinkSize = pCellLink ? ((pCellLink->GetSize() + 7) & 0xFFFE) : 0;
610 
611     const XclTokenArray* pSrcRange = GetSourceRangeTokArr();
612     sal_uInt16 nSrcRangeSize = pSrcRange ? ((pSrcRange->GetSize() + 7) & 0xFFFE) : 0;
613 
614     sal_uInt16 nPictFmlaSize = nFirstPartSize + nCellLinkSize + nSrcRangeSize + 18;
615     rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nPictFmlaSize );
616 
617     rStrm   << nFirstPartSize                           // size of first part
618             << sal_uInt16( 5 )                          // formula size
619             << sal_uInt32( 0 )                          // unknown ID
620             << sal_uInt8( 0x02 ) << sal_uInt32( 0 )     // tTbl token with unknown ID
621             << sal_uInt8( 3 )                           // pad to word
622             << aClass;                                  // "Forms.***.1"
623     rStrm.WriteZeroBytes( nClassNamePad );              // pad to word
624     rStrm   << mnStrmStart                              // start in 'Ctls' stream
625             << mnStrmSize                               // size in 'Ctls' stream
626             << sal_uInt32( 0 );                         // class ID size
627     // cell link
628     rStrm << nCellLinkSize;
629     if( pCellLink )
630         WriteFormula( rStrm, *pCellLink );
631     // list source range
632     rStrm << nSrcRangeSize;
633     if( pSrcRange )
634         WriteFormula( rStrm, *pSrcRange );
635 
636     rStrm.EndRecord();
637 }
638 
639 //#else
640 
XclExpTbxControlObj(XclExpObjectManager & rRoot,Reference<XShape> const & xShape,const tools::Rectangle * pChildAnchor)641 XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference< XShape > const & xShape , const tools::Rectangle* pChildAnchor ) :
642     XclObj( rRoot, EXC_OBJTYPE_UNKNOWN, true ),
643     XclMacroHelper( rRoot ),
644     mxShape( xShape ),
645     meEventType( EXC_TBX_EVENT_ACTION ),
646     mnHeight( 0 ),
647     mnState( 0 ),
648     mnLineCount( 0 ),
649     mnSelEntry( 0 ),
650     mnScrollValue( 0 ),
651     mnScrollMin( 0 ),
652     mnScrollMax( 100 ),
653     mnScrollStep( 1 ),
654     mnScrollPage( 10 ),
655     mbFlatButton( false ),
656     mbFlatBorder( false ),
657     mbMultiSel( false ),
658     mbScrollHor( false ),
659     mbPrint( false ),
660     mbVisible( false ),
661     mnShapeId( 0 )
662 {
663     namespace FormCompType = css::form::FormComponentType;
664     namespace AwtVisualEffect = css::awt::VisualEffect;
665     namespace AwtScrollOrient = css::awt::ScrollBarOrientation;
666 
667     ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
668     if( !xShape.is() || !aCtrlProp.Is() )
669         return;
670 
671     mnHeight = xShape->getSize().Height;
672     if( mnHeight <= 0 )
673         return;
674 
675     // control type
676     sal_Int16 nClassId = 0;
677     if( aCtrlProp.GetProperty( nClassId, "ClassId" ) )
678     {
679         switch( nClassId )
680         {
681             case FormCompType::COMMANDBUTTON:   mnObjType = EXC_OBJTYPE_BUTTON;       meEventType = EXC_TBX_EVENT_ACTION; break;
682             case FormCompType::RADIOBUTTON:     mnObjType = EXC_OBJTYPE_OPTIONBUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
683             case FormCompType::CHECKBOX:        mnObjType = EXC_OBJTYPE_CHECKBOX;     meEventType = EXC_TBX_EVENT_ACTION; break;
684             case FormCompType::LISTBOX:         mnObjType = EXC_OBJTYPE_LISTBOX;      meEventType = EXC_TBX_EVENT_CHANGE; break;
685             case FormCompType::COMBOBOX:        mnObjType = EXC_OBJTYPE_DROPDOWN;     meEventType = EXC_TBX_EVENT_CHANGE; break;
686             case FormCompType::GROUPBOX:        mnObjType = EXC_OBJTYPE_GROUPBOX;     meEventType = EXC_TBX_EVENT_MOUSE;  break;
687             case FormCompType::FIXEDTEXT:       mnObjType = EXC_OBJTYPE_LABEL;        meEventType = EXC_TBX_EVENT_MOUSE;  break;
688             case FormCompType::SCROLLBAR:       mnObjType = EXC_OBJTYPE_SCROLLBAR;    meEventType = EXC_TBX_EVENT_VALUE;  break;
689             case FormCompType::SPINBUTTON:      mnObjType = EXC_OBJTYPE_SPIN;         meEventType = EXC_TBX_EVENT_VALUE;  break;
690         }
691     }
692     if( mnObjType == EXC_OBJTYPE_UNKNOWN )
693         return;
694 
695     // OBJ record flags
696     SetLocked( true );
697     mbPrint = aCtrlProp.GetBoolProperty( "Printable" );
698     SetPrintable( mbPrint );
699     SetAutoFill( false );
700     SetAutoLine( false );
701 
702     // fill DFF property set
703     mrEscherEx.OpenContainer( ESCHER_SpContainer );
704     mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
705     EscherPropertyContainer aPropOpt;
706     mbVisible = aCtrlProp.GetBoolProperty( "EnableVisible" );
707     aPropOpt.AddOpt( ESCHER_Prop_fPrint, mbVisible ? 0x00080000 : 0x00080002 ); // visible flag
708 
709     aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01000100 ); // bool field
710     aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 );                        // Text ID
711     aPropOpt.AddOpt( ESCHER_Prop_WrapText, 0x00000001 );
712     aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x001A0008 );      // bool field
713     aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00100000 );      // bool field
714     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 );     // bool field
715 
716     // #i51348# name of the control, may overwrite shape name
717     if( aCtrlProp.GetProperty( msCtrlName, "Name" ) && !msCtrlName.isEmpty() )
718         aPropOpt.AddOpt( ESCHER_Prop_wzName, msCtrlName );
719 
720     //Export description as alt text
721     if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
722     {
723         OUString aAltTxt;
724         OUString aDescrText = pSdrObj->GetDescription();
725         if(!aDescrText.isEmpty())
726             aAltTxt = aDescrText.copy( 0, std::min<sal_Int32>(MSPROP_DESCRIPTION_MAX_LEN, aDescrText.getLength()) );
727         aPropOpt.AddOpt( ESCHER_Prop_wzDescription, aAltTxt );
728     }
729 
730     // write DFF property set to stream
731     aPropOpt.Commit( mrEscherEx.GetStream() );
732 
733     // anchor
734     ImplWriteAnchor( SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
735 
736     mrEscherEx.AddAtom( 0, ESCHER_ClientData );                       // OBJ record
737     mrEscherEx.UpdateDffFragmentEnd();
738 
739     // control label
740     if( aCtrlProp.GetProperty( msLabel, "Label" ) )
741     {
742         /*  Be sure to construct the MSODRAWING record containing the
743             ClientTextbox atom after the base OBJ's MSODRAWING record data is
744             completed. */
745         pClientTextbox.reset( new XclExpMsoDrawing( mrEscherEx ) );
746         mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox );  // TXO record
747         mrEscherEx.UpdateDffFragmentEnd();
748 
749         sal_uInt16 nXclFont = EXC_FONT_APP;
750         if( !msLabel.isEmpty() )
751         {
752             XclFontData aFontData;
753             GetFontPropSetHelper().ReadFontProperties( aFontData, aCtrlProp, EXC_FONTPROPSET_CONTROL );
754             if( (!aFontData.maName.isEmpty() ) && (aFontData.mnHeight > 0) )
755                 nXclFont = GetFontBuffer().Insert( aFontData, EXC_COLOR_CTRLTEXT );
756         }
757 
758         pTxo.reset( new XclTxo( msLabel, nXclFont ) );
759         pTxo->SetHorAlign( (mnObjType == EXC_OBJTYPE_BUTTON) ? EXC_OBJ_HOR_CENTER : EXC_OBJ_HOR_LEFT );
760         pTxo->SetVerAlign( EXC_OBJ_VER_CENTER );
761     }
762 
763     mrEscherEx.CloseContainer();  // ESCHER_SpContainer
764 
765     // other properties
766     aCtrlProp.GetProperty( mnLineCount, "LineCount" );
767 
768     // border style
769     sal_Int16 nApiButton = AwtVisualEffect::LOOK3D;
770     sal_Int16 nApiBorder = AwtVisualEffect::LOOK3D;
771     switch( nClassId )
772     {
773         case FormCompType::LISTBOX:
774         case FormCompType::COMBOBOX:
775             aCtrlProp.GetProperty( nApiBorder, "Border" );
776         break;
777         case FormCompType::CHECKBOX:
778         case FormCompType::RADIOBUTTON:
779             aCtrlProp.GetProperty( nApiButton, "VisualEffect" );
780             nApiBorder = AwtVisualEffect::NONE;
781         break;
782         // Push button cannot be set to flat in Excel
783         case FormCompType::COMMANDBUTTON:
784             nApiBorder = AwtVisualEffect::LOOK3D;
785         break;
786         // Label does not support a border in Excel
787         case FormCompType::FIXEDTEXT:
788             nApiBorder = AwtVisualEffect::NONE;
789         break;
790         /*  Scroll bar and spin button have a "Border" property, but it is
791             really used for a border, and not for own 3D/flat look (#i34712#). */
792         case FormCompType::SCROLLBAR:
793         case FormCompType::SPINBUTTON:
794             nApiButton = AwtVisualEffect::LOOK3D;
795             nApiBorder = AwtVisualEffect::NONE;
796         break;
797         // Group box does not support flat style (#i34712#)
798         case FormCompType::GROUPBOX:
799             nApiBorder = AwtVisualEffect::LOOK3D;
800         break;
801     }
802     mbFlatButton = nApiButton != AwtVisualEffect::LOOK3D;
803     mbFlatBorder = nApiBorder != AwtVisualEffect::LOOK3D;
804 
805     // control state
806     sal_Int16 nApiState = 0;
807     if( aCtrlProp.GetProperty( nApiState, "State" ) )
808     {
809         switch( nApiState )
810         {
811             case 0: mnState = EXC_OBJ_CHECKBOX_UNCHECKED;  break;
812             case 1: mnState = EXC_OBJ_CHECKBOX_CHECKED;    break;
813             case 2: mnState = EXC_OBJ_CHECKBOX_TRISTATE;   break;
814         }
815     }
816 
817     // special control contents
818     switch( nClassId )
819     {
820         case FormCompType::LISTBOX:
821         {
822             mbMultiSel = aCtrlProp.GetBoolProperty( "MultiSelection" );
823             Sequence< sal_Int16 > aSelection;
824             if( aCtrlProp.GetProperty( aSelection, "SelectedItems" ) )
825             {
826                 if( aSelection.hasElements() )
827                 {
828                     mnSelEntry = aSelection[ 0 ] + 1;
829                     comphelper::sequenceToContainer(maMultiSel, aSelection);
830                 }
831             }
832 
833             // convert listbox with dropdown button to Excel dropdown
834             if( aCtrlProp.GetBoolProperty( "Dropdown" ) )
835                 mnObjType = EXC_OBJTYPE_DROPDOWN;
836         }
837         break;
838 
839         case FormCompType::COMBOBOX:
840         {
841             Sequence< OUString > aStringList;
842             OUString aDefText;
843             if( aCtrlProp.GetProperty( aStringList, "StringItemList" ) &&
844                 aCtrlProp.GetProperty( aDefText, "Text" ) &&
845                 aStringList.hasElements() && !aDefText.isEmpty() )
846             {
847                 auto nIndex = comphelper::findValue(aStringList, aDefText);
848                 if( nIndex != -1 )
849                     mnSelEntry = static_cast< sal_Int16 >( nIndex + 1 );  // 1-based
850                 if( mnSelEntry > 0 )
851                     maMultiSel.resize( 1, mnSelEntry - 1 );
852             }
853 
854             // convert combobox without dropdown button to Excel listbox
855             if( !aCtrlProp.GetBoolProperty( "Dropdown" ) )
856                 mnObjType = EXC_OBJTYPE_LISTBOX;
857         }
858         break;
859 
860         case FormCompType::SCROLLBAR:
861         {
862             sal_Int32 nApiValue = 0;
863             if( aCtrlProp.GetProperty( nApiValue, "ScrollValueMin" ) )
864                 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
865             if( aCtrlProp.GetProperty( nApiValue, "ScrollValueMax" ) )
866                 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MIN );
867             if( aCtrlProp.GetProperty( nApiValue, "ScrollValue" ) )
868                 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
869             if( aCtrlProp.GetProperty( nApiValue, "LineIncrement" ) )
870                 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
871             if( aCtrlProp.GetProperty( nApiValue, "BlockIncrement" ) )
872                 mnScrollPage = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
873             if( aCtrlProp.GetProperty( nApiValue, "Orientation" ) )
874                 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
875         }
876         break;
877 
878         case FormCompType::SPINBUTTON:
879         {
880             sal_Int32 nApiValue = 0;
881             if( aCtrlProp.GetProperty( nApiValue, "SpinValueMin" ) )
882                 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
883             if( aCtrlProp.GetProperty( nApiValue, "SpinValueMax" ) )
884                 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
885             if( aCtrlProp.GetProperty( nApiValue, "SpinValue" ) )
886                 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
887             if( aCtrlProp.GetProperty( nApiValue, "SpinIncrement" ) )
888                 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
889             if( aCtrlProp.GetProperty( nApiValue, "Orientation" ) )
890                 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
891         }
892         break;
893     }
894 
895     {
896         Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
897         if( xCtrlModel.is() )
898         {
899             Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
900             if( xBindable.is() )
901             {
902                 Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
903                 if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
904                 {
905                     ScfPropertySet aBindProp( xServInfo );
906                     CellAddress aApiAddress;
907                     if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
908                     {
909                         ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
910                         if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
911                             lcl_GetFromTo( rRoot, pSdrObj->GetLogicRect(), mxCellLinkAddress.Tab(), maAreaFrom, maAreaTo, true );
912                     }
913                 }
914             }
915         }
916     }
917 
918     // spreadsheet links
919     ConvertSheetLinks( xShape );
920 }
921 
SetMacroLink(const ScriptEventDescriptor & rEvent)922 bool XclExpTbxControlObj::SetMacroLink( const ScriptEventDescriptor& rEvent )
923 {
924     return XclMacroHelper::SetMacroLink( rEvent, meEventType );
925 }
926 
WriteSubRecs(XclExpStream & rStrm)927 void XclExpTbxControlObj::WriteSubRecs( XclExpStream& rStrm )
928 {
929     switch( mnObjType )
930     {
931         // *** Push buttons, labels ***
932 
933         case EXC_OBJTYPE_BUTTON:
934         case EXC_OBJTYPE_LABEL:
935             // ftMacro - macro link
936             WriteMacroSubRec( rStrm );
937         break;
938 
939         // *** Check boxes, option buttons ***
940 
941         case EXC_OBJTYPE_CHECKBOX:
942         case EXC_OBJTYPE_OPTIONBUTTON:
943         {
944             // ftCbls - box properties
945             sal_uInt16 nStyle = 0;
946             ::set_flag( nStyle, EXC_OBJ_CHECKBOX_FLAT, mbFlatButton );
947 
948             rStrm.StartRecord( EXC_ID_OBJCBLS, 12 );
949             rStrm << mnState;
950             rStrm.WriteZeroBytes( 8 );
951             rStrm << nStyle;
952             rStrm.EndRecord();
953 
954             // ftMacro - macro link
955             WriteMacroSubRec( rStrm );
956             // ftCblsFmla subrecord - cell link
957             WriteCellLinkSubRec( rStrm, EXC_ID_OBJCBLSFMLA );
958 
959             // ftCblsData subrecord - box properties, again
960             rStrm.StartRecord( EXC_ID_OBJCBLS, 8 );
961             rStrm << mnState;
962             rStrm.WriteZeroBytes( 4 );
963             rStrm << nStyle;
964             rStrm.EndRecord();
965         }
966         break;
967 
968         // *** List boxes, combo boxes ***
969 
970         case EXC_OBJTYPE_LISTBOX:
971         case EXC_OBJTYPE_DROPDOWN:
972         {
973             sal_uInt16 nEntryCount = GetSourceEntryCount();
974 
975             // ftSbs subrecord - Scroll bars
976             sal_Int32 nLineHeight = XclTools::GetHmmFromTwips( 200 );   // always 10pt
977             if( mnObjType == EXC_OBJTYPE_LISTBOX )
978                 mnLineCount = static_cast< sal_uInt16 >( mnHeight / nLineHeight );
979             mnScrollValue = 0;
980             mnScrollMin = 0;
981             sal_uInt16 nInvisLines = (nEntryCount >= mnLineCount) ? (nEntryCount - mnLineCount) : 0;
982             mnScrollMax = limit_cast< sal_uInt16 >( nInvisLines, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
983             mnScrollStep = 1;
984             mnScrollPage = limit_cast< sal_uInt16 >( mnLineCount, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
985             mbScrollHor = false;
986             WriteSbs( rStrm );
987 
988             // ftMacro - macro link
989             WriteMacroSubRec( rStrm );
990             // ftSbsFmla subrecord - cell link
991             WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
992 
993             // ftLbsData - source data range and box properties
994             sal_uInt16 nStyle = 0;
995             ::insert_value( nStyle, mbMultiSel ? EXC_OBJ_LISTBOX_MULTI : EXC_OBJ_LISTBOX_SINGLE, 4, 2 );
996             ::set_flag( nStyle, EXC_OBJ_LISTBOX_FLAT, mbFlatBorder );
997 
998             rStrm.StartRecord( EXC_ID_OBJLBSDATA, 0 );
999 
1000             if( const XclTokenArray* pSrcRange = GetSourceRangeTokArr() )
1001             {
1002                 rStrm << static_cast< sal_uInt16 >( (pSrcRange->GetSize() + 7) & 0xFFFE );
1003                 WriteFormula( rStrm, *pSrcRange );
1004             }
1005             else
1006                 rStrm << sal_uInt16( 0 );
1007 
1008             rStrm << nEntryCount << mnSelEntry << nStyle << sal_uInt16( 0 );
1009             if( mnObjType == EXC_OBJTYPE_LISTBOX )
1010             {
1011                 if( nEntryCount )
1012                 {
1013                     ScfUInt8Vec aSelEx( nEntryCount, 0 );
1014                     for( const auto& rItem : maMultiSel )
1015                         if( rItem < nEntryCount )
1016                             aSelEx[ rItem ] = 1;
1017                     rStrm.Write( aSelEx.data(), aSelEx.size() );
1018                 }
1019             }
1020             else if( mnObjType == EXC_OBJTYPE_DROPDOWN )
1021             {
1022                 rStrm << sal_uInt16( 0 ) << mnLineCount << sal_uInt16( 0 ) << sal_uInt16( 0 );
1023             }
1024 
1025             rStrm.EndRecord();
1026         }
1027         break;
1028 
1029         // *** Spin buttons, scrollbars ***
1030 
1031         case EXC_OBJTYPE_SPIN:
1032         case EXC_OBJTYPE_SCROLLBAR:
1033         {
1034             // ftSbs subrecord - scroll bars
1035             WriteSbs( rStrm );
1036             // ftMacro - macro link
1037             WriteMacroSubRec( rStrm );
1038             // ftSbsFmla subrecord - cell link
1039             WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
1040         }
1041         break;
1042 
1043         // *** Group boxes ***
1044 
1045         case EXC_OBJTYPE_GROUPBOX:
1046         {
1047             // ftMacro - macro link
1048             WriteMacroSubRec( rStrm );
1049 
1050             // ftGboData subrecord - group box properties
1051             sal_uInt16 nStyle = 0;
1052             ::set_flag( nStyle, EXC_OBJ_GROUPBOX_FLAT, mbFlatBorder );
1053 
1054             rStrm.StartRecord( EXC_ID_OBJGBODATA, 6 );
1055             rStrm   << sal_uInt32( 0 )
1056                     << nStyle;
1057             rStrm.EndRecord();
1058         }
1059         break;
1060     }
1061 }
1062 
WriteCellLinkSubRec(XclExpStream & rStrm,sal_uInt16 nSubRecId)1063 void XclExpTbxControlObj::WriteCellLinkSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId )
1064 {
1065     if( const XclTokenArray* pCellLink = GetCellLinkTokArr() )
1066         WriteFormulaSubRec( rStrm, nSubRecId, *pCellLink );
1067 }
1068 
WriteSbs(XclExpStream & rStrm)1069 void XclExpTbxControlObj::WriteSbs( XclExpStream& rStrm )
1070 {
1071     sal_uInt16 nOrient = 0;
1072     ::set_flag( nOrient, EXC_OBJ_SCROLLBAR_HOR, mbScrollHor );
1073     sal_uInt16 nStyle = EXC_OBJ_SCROLLBAR_DEFFLAGS;
1074     ::set_flag( nStyle, EXC_OBJ_SCROLLBAR_FLAT, mbFlatButton );
1075 
1076     rStrm.StartRecord( EXC_ID_OBJSBS, 20 );
1077     rStrm   << sal_uInt32( 0 )              // reserved
1078             << mnScrollValue                // thumb position
1079             << mnScrollMin                  // thumb min pos
1080             << mnScrollMax                  // thumb max pos
1081             << mnScrollStep                 // line increment
1082             << mnScrollPage                 // page increment
1083             << nOrient                      // 0 = vertical, 1 = horizontal
1084             << sal_uInt16( 15 )             // thumb width
1085             << nStyle;                      // flags/style
1086     rStrm.EndRecord();
1087 }
1088 
setShapeId(sal_Int32 aShapeId)1089 void XclExpTbxControlObj::setShapeId(sal_Int32 aShapeId)
1090 {
1091     mnShapeId = aShapeId;
1092 }
1093 
1094 // save into xl\drawings\drawing1.xml
SaveXml(XclExpXmlStream & rStrm)1095 void XclExpTbxControlObj::SaveXml( XclExpXmlStream& rStrm )
1096 {
1097     sax_fastparser::FSHelperPtr& pDrawing = rStrm.GetCurrentStream();
1098 
1099     pDrawing->startElement(FSNS(XML_mc, XML_AlternateContent),
1100         FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8());
1101     pDrawing->startElement(FSNS(XML_mc, XML_Choice),
1102         FSNS(XML_xmlns, XML_a14), rStrm.getNamespaceURL(OOX_NS(a14)).toUtf8(),
1103         XML_Requires, "a14");
1104 
1105     pDrawing->startElement(FSNS(XML_xdr, XML_twoCellAnchor), XML_editAs, "oneCell");
1106     {
1107         pDrawing->startElement(FSNS(XML_xdr, XML_from));
1108         lcl_WriteAnchorVertex(pDrawing, maAreaFrom);
1109         pDrawing->endElement(FSNS(XML_xdr, XML_from));
1110         pDrawing->startElement(FSNS(XML_xdr, XML_to));
1111         lcl_WriteAnchorVertex(pDrawing, maAreaTo);
1112         pDrawing->endElement(FSNS(XML_xdr, XML_to));
1113 
1114         pDrawing->startElement(FSNS(XML_xdr, XML_sp));
1115         {
1116             // xdr:nvSpPr
1117             pDrawing->startElement(FSNS(XML_xdr, XML_nvSpPr));
1118             {
1119                 pDrawing->singleElement(FSNS(XML_xdr, XML_cNvPr),
1120                     XML_id, OString::number(mnShapeId).getStr(),
1121                     XML_name, msCtrlName.toUtf8(), // control name
1122                     XML_descr, msLabel.toUtf8(), // description as alt text
1123                     XML_hidden, mbVisible ? "0" : "1");
1124                 pDrawing->singleElement(FSNS(XML_xdr, XML_cNvSpPr));
1125             }
1126             pDrawing->endElement(FSNS(XML_xdr, XML_nvSpPr));
1127 
1128             // xdr:spPr
1129             pDrawing->startElement(FSNS(XML_xdr, XML_spPr));
1130             {
1131                 // a:xfrm
1132                 pDrawing->startElement(FSNS(XML_a, XML_xfrm));
1133                 {
1134                     pDrawing->singleElement(FSNS(XML_a, XML_off),
1135                         XML_x, "0",
1136                         XML_y, "0");
1137                     pDrawing->singleElement(FSNS(XML_a, XML_ext),
1138                         XML_cx, "0",
1139                         XML_cy, "0");
1140                 }
1141                 pDrawing->endElement(FSNS(XML_a, XML_xfrm));
1142 
1143                 // a:prstGeom
1144                 pDrawing->startElement(FSNS(XML_a, XML_prstGeom), XML_prst, "rect");
1145                 {
1146                     pDrawing->singleElement(FSNS(XML_a, XML_avLst));
1147                 }
1148                 pDrawing->endElement(FSNS(XML_a, XML_prstGeom));
1149             }
1150             pDrawing->endElement(FSNS(XML_xdr, XML_spPr));
1151 
1152             // xdr:txBody
1153             {
1154                 pDrawing->startElement(FSNS(XML_xdr, XML_txBody));
1155 
1156 #define DEFLRINS 254
1157 #define DEFTBINS 127
1158                 sal_Int32 nLeft, nRight, nTop, nBottom;
1159                 nLeft = nRight = DEFLRINS;
1160                 nTop = nBottom = DEFTBINS;
1161 
1162                 // top inset looks a bit different compared to ppt export
1163                 // check if something related doesn't work as expected
1164                 Reference< XPropertySet > rXPropSet(mxShape, UNO_QUERY);
1165 
1166                 try
1167                 {
1168                     css::uno::Any mAny;
1169 
1170                     mAny = rXPropSet->getPropertyValue("TextLeftDistance");
1171                     if (mAny.hasValue())
1172                         mAny >>= nLeft;
1173 
1174                     mAny = rXPropSet->getPropertyValue("TextRightDistance");
1175                     if (mAny.hasValue())
1176                         mAny >>= nRight;
1177 
1178                     mAny = rXPropSet->getPropertyValue("TextUpperDistance");
1179                     if (mAny.hasValue())
1180                         mAny >>= nTop;
1181 
1182                     mAny = rXPropSet->getPropertyValue("TextLowerDistance");
1183                     if (mAny.hasValue())
1184                         mAny >>= nBottom;
1185                 }
1186                 catch (...)
1187                 {
1188                 }
1189 
1190                 // Specifies the inset of the bounding rectangle.
1191                 // Insets are used just as internal margins for text boxes within shapes.
1192                 // If this attribute is omitted, then a value of 45720 or 0.05 inches is implied.
1193                 pDrawing->startElementNS(XML_a, XML_bodyPr,
1194                     XML_lIns, (nLeft != DEFLRINS) ? OString::number(oox::drawingml::convertHmmToEmu(nLeft)).getStr() : nullptr,
1195                     XML_rIns, (nRight != DEFLRINS) ? OString::number(oox::drawingml::convertHmmToEmu(nRight)).getStr() : nullptr,
1196                     XML_tIns, (nTop != DEFTBINS) ? OString::number(oox::drawingml::convertHmmToEmu(nTop)).getStr() : nullptr,
1197                     XML_bIns, (nBottom != DEFTBINS) ? OString::number(oox::drawingml::convertHmmToEmu(nBottom)).getStr() : nullptr,
1198                     XML_anchor, "ctr");
1199 
1200                 {
1201                     bool bTextAutoGrowHeight = false;
1202 
1203                     try
1204                     {
1205                         css::uno::Any mAny;
1206 
1207                         mAny = rXPropSet->getPropertyValue("TextAutoGrowHeight");
1208                         if (mAny.hasValue())
1209                             mAny >>= bTextAutoGrowHeight;
1210                     }
1211                     catch (...)
1212                     {
1213                     }
1214 
1215                     pDrawing->singleElementNS(XML_a, (bTextAutoGrowHeight ? XML_spAutoFit : XML_noAutofit));
1216                 }
1217 
1218                 pDrawing->endElementNS(XML_a, XML_bodyPr);
1219 
1220                 {
1221                     pDrawing->startElementNS(XML_a, XML_p);
1222                     pDrawing->startElementNS(XML_a, XML_r);
1223                     pDrawing->startElementNS(XML_a, XML_t);
1224                     pDrawing->write(msLabel.toUtf8());
1225                     pDrawing->endElementNS(XML_a, XML_t);
1226                     pDrawing->endElementNS(XML_a, XML_r);
1227                     pDrawing->endElementNS(XML_a, XML_p);
1228                 }
1229 
1230                 pDrawing->endElement(FSNS(XML_xdr, XML_txBody));
1231             }
1232         }
1233         pDrawing->endElement(FSNS(XML_xdr, XML_sp));
1234         pDrawing->singleElement(FSNS(XML_xdr, XML_clientData));
1235     }
1236     pDrawing->endElement(FSNS(XML_xdr, XML_twoCellAnchor));
1237     pDrawing->endElement( FSNS( XML_mc, XML_Choice ) );
1238     pDrawing->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1239 }
1240 
1241 // output into ctrlProp1.xml
SaveControlPropertiesXml(XclExpXmlStream & rStrm) const1242 OUString XclExpTbxControlObj::SaveControlPropertiesXml(XclExpXmlStream& rStrm) const
1243 {
1244     OUString sIdFormControlPr;
1245 
1246     switch (mnObjType)
1247     {
1248         case EXC_OBJTYPE_CHECKBOX:
1249         {
1250             const sal_Int32 nDrawing = XclExpObjList::getNewDrawingUniqueId();
1251             sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream(
1252                     XclXmlUtils::GetStreamName( "xl/", "ctrlProps/ctrlProps", nDrawing ),
1253                     XclXmlUtils::GetStreamName( "../", "ctrlProps/ctrlProps", nDrawing ),
1254                     rStrm.GetCurrentStream()->getOutputStream(),
1255                     "application/vnd.ms-excel.controlproperties+xml",
1256                     OUStringToOString(oox::getRelationship(Relationship::CTRLPROP), RTL_TEXTENCODING_UTF8).getStr(),
1257                     &sIdFormControlPr );
1258 
1259             rStrm.PushStream( pFormControl );
1260             // checkbox
1261             // <formControlPr
1262             //      xmlns="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
1263             //      objectType="CheckBox" checked="Checked" lockText="1" noThreeD="1"/>
1264             //
1265             pFormControl->write("<formControlPr xmlns=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\" objectType=\"CheckBox\"");
1266             if (mnState == EXC_OBJ_CHECKBOX_CHECKED)
1267                 pFormControl->write(" checked=\"Checked\"");
1268 
1269             pFormControl->write(" autoLine=\"false\"");
1270 
1271             if (mbPrint)
1272                 pFormControl->write(" print=\"true\"");
1273             else
1274                 pFormControl->write(" print=\"false\"");
1275 
1276             if (mxCellLinkAddress.IsValid())
1277             {
1278                 OUString aCellLink = mxCellLinkAddress.Format(ScRefFlags::ADDR_ABS,
1279                     &GetDoc(),
1280                     ScAddress::Details(::formula::FormulaGrammar::CONV_XL_A1));
1281 
1282                 // "Sheet1!$C$5"
1283                 pFormControl->write(" fmlaLink=\"");
1284                 if (aCellLink.indexOf('!') < 0)
1285                 {
1286                     pFormControl->write(GetTabInfo().GetScTabName( mxCellLinkAddress.Tab() ).toUtf8());
1287                     pFormControl->write("!");
1288                 }
1289                 pFormControl->write(aCellLink);
1290                 pFormControl->write("\"");
1291             }
1292 
1293             pFormControl->write(" lockText=\"1\" noThreeD=\"1\"/>");
1294             rStrm.PopStream();
1295 
1296             break;
1297         }
1298     }
1299 
1300     return sIdFormControlPr;
1301 }
1302 
1303 // output into sheet1.xml
SaveSheetXml(XclExpXmlStream & rStrm,const OUString & aIdFormControlPr) const1304 void XclExpTbxControlObj::SaveSheetXml(XclExpXmlStream& rStrm, const OUString& aIdFormControlPr) const
1305 {
1306     switch (mnObjType)
1307     {
1308         case EXC_OBJTYPE_CHECKBOX:
1309         {
1310             sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1311 
1312             rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent),
1313                 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8());
1314             rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
1315 
1316             rWorksheet->startElement(
1317                 XML_control,
1318                 XML_shapeId, OString::number(mnShapeId).getStr(),
1319                 FSNS(XML_r, XML_id), aIdFormControlPr.toUtf8(),
1320                 XML_name, msLabel.toUtf8()); // text to display with checkbox button
1321 
1322             rWorksheet->write("<controlPr defaultSize=\"0\" locked=\"1\" autoFill=\"0\" autoLine=\"0\" autoPict=\"0\"");
1323 
1324             if (mbPrint)
1325                 rWorksheet->write(" print=\"true\"");
1326             else
1327                 rWorksheet->write(" print=\"false\"");
1328 
1329             if (!msCtrlName.isEmpty())
1330             {
1331                 rWorksheet->write(" altText=\"");
1332                 rWorksheet->write(msCtrlName.toUtf8()); // alt text
1333                 rWorksheet->write("\"");
1334             }
1335 
1336             rWorksheet->write(">");
1337 
1338             rWorksheet->startElement(XML_anchor, XML_moveWithCells, "true", XML_sizeWithCells, "false");
1339             rWorksheet->startElement(XML_from);
1340             lcl_WriteAnchorVertex(rWorksheet, maAreaFrom);
1341             rWorksheet->endElement(XML_from);
1342             rWorksheet->startElement(XML_to);
1343             lcl_WriteAnchorVertex(rWorksheet, maAreaTo);
1344             rWorksheet->endElement(XML_to);
1345             rWorksheet->endElement( XML_anchor );
1346 
1347             rWorksheet->write("</controlPr>");
1348 
1349             rWorksheet->endElement(XML_control);
1350             rWorksheet->endElement( FSNS( XML_mc, XML_Choice ) );
1351             rWorksheet->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1352 
1353             break;
1354         }
1355     }
1356 }
1357 
1358 //#endif
1359 
XclExpChartObj(XclExpObjectManager & rObjMgr,Reference<XShape> const & xShape,const tools::Rectangle * pChildAnchor,ScDocument * pDoc)1360 XclExpChartObj::XclExpChartObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor, ScDocument* pDoc ) :
1361     XclObj( rObjMgr, EXC_OBJTYPE_CHART ),
1362     XclExpRoot( rObjMgr.GetRoot() ), mxShape( xShape ),
1363     mpDoc(pDoc)
1364 {
1365     // create the MSODRAWING record contents for the chart object
1366     mrEscherEx.OpenContainer( ESCHER_SpContainer );
1367     mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
1368     EscherPropertyContainer aPropOpt;
1369     aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 );
1370     aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 );
1371     aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x0800004E );
1372     aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x0800004D );
1373     aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 );
1374     aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x0800004D );
1375     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080008 );
1376     aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00020000 );
1377     aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 );
1378     aPropOpt.Commit( mrEscherEx.GetStream() );
1379 
1380     // anchor
1381     SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
1382     ImplWriteAnchor( pSdrObj, pChildAnchor );
1383 
1384     // client data (the following OBJ record)
1385     mrEscherEx.AddAtom( 0, ESCHER_ClientData );
1386     mrEscherEx.CloseContainer();  // ESCHER_SpContainer
1387     mrEscherEx.UpdateDffFragmentEnd();
1388 
1389     // load the chart OLE object
1390     if( SdrOle2Obj* pSdrOleObj = dynamic_cast< SdrOle2Obj* >( pSdrObj ) )
1391         svt::EmbeddedObjectRef::TryRunningState( pSdrOleObj->GetObjRef() );
1392 
1393     // create the chart substream object
1394     ScfPropertySet aShapeProp( xShape );
1395     Reference< XModel > xModel;
1396     aShapeProp.GetProperty( xModel, "Model" );
1397     mxChartDoc.set( xModel,UNO_QUERY );
1398     css::awt::Rectangle aBoundRect;
1399     aShapeProp.GetProperty( aBoundRect, "BoundRect" );
1400     tools::Rectangle aChartRect( Point( aBoundRect.X, aBoundRect.Y ), Size( aBoundRect.Width, aBoundRect.Height ) );
1401     mxChart.reset( new XclExpChart( GetRoot(), xModel, aChartRect ) );
1402 }
1403 
~XclExpChartObj()1404 XclExpChartObj::~XclExpChartObj()
1405 {
1406 }
1407 
Save(XclExpStream & rStrm)1408 void XclExpChartObj::Save( XclExpStream& rStrm )
1409 {
1410     // content of OBJ record
1411     XclObj::Save( rStrm );
1412     // chart substream
1413     mxChart->Save( rStrm );
1414 }
1415 
SaveXml(XclExpXmlStream & rStrm)1416 void XclExpChartObj::SaveXml( XclExpXmlStream& rStrm )
1417 {
1418     sax_fastparser::FSHelperPtr pDrawing = rStrm.GetCurrentStream();
1419 
1420     // FIXME: two cell? it seems the two cell anchor is incorrect.
1421     pDrawing->startElement( FSNS( XML_xdr, XML_twoCellAnchor ), // OOXTODO: oneCellAnchor, absoluteAnchor
1422             XML_editAs, "oneCell" );
1423     Reference< XPropertySet > xPropSet( mxShape, UNO_QUERY );
1424     if (xPropSet.is())
1425     {
1426         XclObjAny::WriteFromTo( rStrm, mxShape, GetTab() );
1427         ChartExport aChartExport(XML_xdr, pDrawing, mxChartDoc, &rStrm, drawingml::DOCUMENT_XLSX);
1428         std::shared_ptr<oox::drawingml::URLTransformer> pURLTransformer(new ScURLTransformer(*mpDoc));
1429         aChartExport.SetURLTranslator(pURLTransformer);
1430         static sal_Int32 nChartCount = 0;
1431         nChartCount++;
1432         sal_Int32 nID = rStrm.GetUniqueId();
1433         aChartExport.WriteChartObj( mxShape, nID, nChartCount );
1434         // TODO: get the correcto chart number
1435     }
1436 
1437     pDrawing->singleElement( FSNS( XML_xdr, XML_clientData)
1438             // OOXTODO: XML_fLocksWithSheet
1439             // OOXTODO: XML_fPrintsWithSheet
1440     );
1441     pDrawing->endElement( FSNS( XML_xdr, XML_twoCellAnchor ) );
1442 }
1443 
GetChartDoc() const1444 const css::uno::Reference<css::chart::XChartDocument>& XclExpChartObj::GetChartDoc() const
1445 {
1446     return mxChartDoc;
1447 }
1448 
XclExpNote(const XclExpRoot & rRoot,const ScAddress & rScPos,const ScPostIt * pScNote,const OUString & rAddText)1449 XclExpNote::XclExpNote(const XclExpRoot& rRoot, const ScAddress& rScPos,
1450         const ScPostIt* pScNote, const OUString& rAddText)
1451     : XclExpRecord(EXC_ID_NOTE)
1452     , mrRoot(rRoot)
1453     , maScPos(rScPos)
1454     , mnObjId(EXC_OBJ_INVALID_ID)
1455     , mbVisible(pScNote && pScNote->IsCaptionShown())
1456     , meTHA(SDRTEXTHORZADJUST_LEFT)
1457     , meTVA(SDRTEXTVERTADJUST_TOP)
1458     , mbAutoScale(false)
1459     , mbLocked(false)
1460     , mbAutoFill(false)
1461     , mbColHidden(false)
1462     , mbRowHidden(false)
1463 {
1464     // get the main note text
1465     OUString aNoteText;
1466     if( pScNote )
1467     {
1468         aNoteText = pScNote->GetText();
1469         const EditTextObject *pEditObj = pScNote->GetEditTextObject();
1470         if( pEditObj )
1471             mpNoteContents = XclExpStringHelper::CreateString( rRoot, *pEditObj );
1472     }
1473     // append additional text
1474     aNoteText = ScGlobal::addToken( aNoteText, rAddText, '\n', 2 );
1475 
1476     // initialize record dependent on BIFF type
1477     switch( rRoot.GetBiff() )
1478     {
1479         case EXC_BIFF5:
1480             maNoteText = OUStringToOString(aNoteText, rRoot.GetTextEncoding());
1481         break;
1482 
1483         case EXC_BIFF8:
1484         {
1485             // TODO: additional text
1486             if( pScNote )
1487             {
1488                 if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ) )
1489                 {
1490                     lcl_GetFromTo( rRoot, pCaption->GetLogicRect(), maScPos.Tab(), maCommentFrom, maCommentTo );
1491                     if( const OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
1492                         mnObjId = rRoot.GetObjectManager().AddObj( std::make_unique<XclObjComment>( rRoot.GetObjectManager(), pCaption->GetLogicRect(), pOPO->GetTextObject(), pCaption, mbVisible, maScPos, maCommentFrom, maCommentTo ) );
1493 
1494                     SfxItemSet aItemSet = pCaption->GetMergedItemSet();
1495                     meTVA       = pCaption->GetTextVerticalAdjust();
1496                     meTHA       = pCaption->GetTextHorizontalAdjust();
1497                     mbAutoScale = pCaption->GetFitToSize() != drawing::TextFitToSizeType_NONE;
1498                     mbLocked    = pCaption->IsMoveProtect() || pCaption->IsResizeProtect();
1499 
1500                     // AutoFill style would change if Postit.cxx object creation values are changed
1501                     OUString aCol(aItemSet.Get(XATTR_FILLCOLOR).GetValue());
1502                     mbAutoFill  = aCol.isEmpty() && (aItemSet.Get(XATTR_FILLSTYLE).GetValue() == drawing::FillStyle_SOLID);
1503                     mbRowHidden = (rRoot.GetDoc().RowHidden(maScPos.Row(),maScPos.Tab()));
1504                     mbColHidden = (rRoot.GetDoc().ColHidden(maScPos.Col(),maScPos.Tab()));
1505                 }
1506                 // stAuthor (variable): An XLUnicodeString that specifies the name of the comment
1507                 // author. String length MUST be greater than or equal to 1 and less than or equal
1508                 // to 54.
1509                 if( pScNote->GetAuthor().isEmpty() )
1510                     maAuthor = XclExpString( " " );
1511                 else
1512                     maAuthor = XclExpString( pScNote->GetAuthor(), XclStrFlags::NONE, 54 );
1513             }
1514 
1515             SetRecSize( 9 + maAuthor.GetSize() );
1516         }
1517         break;
1518 
1519         default:    DBG_ERROR_BIFF();
1520     }
1521 }
1522 
Save(XclExpStream & rStrm)1523 void XclExpNote::Save( XclExpStream& rStrm )
1524 {
1525     switch( rStrm.GetRoot().GetBiff() )
1526     {
1527         case EXC_BIFF5:
1528         {
1529             // write the NOTE record directly, there may be the need to create more than one
1530             const sal_Char* pcBuffer = maNoteText.getStr();
1531             sal_uInt16 nCharsLeft = static_cast< sal_uInt16 >( maNoteText.getLength() );
1532 
1533             while( nCharsLeft )
1534             {
1535                 sal_uInt16 nWriteChars = ::std::min( nCharsLeft, EXC_NOTE5_MAXLEN );
1536 
1537                 rStrm.StartRecord( EXC_ID_NOTE, 6 + nWriteChars );
1538                 if( pcBuffer == maNoteText.getStr() )
1539                 {
1540                     // first record: row, col, length of complete text
1541                     rStrm   << static_cast< sal_uInt16 >( maScPos.Row() )
1542                             << static_cast< sal_uInt16 >( maScPos.Col() )
1543                             << nCharsLeft;  // still contains full length
1544                 }
1545                 else
1546                 {
1547                     // next records: -1, 0, length of current text segment
1548                     rStrm   << sal_uInt16( 0xFFFF )
1549                             << sal_uInt16( 0 )
1550                             << nWriteChars;
1551                 }
1552                 rStrm.Write( pcBuffer, nWriteChars );
1553                 rStrm.EndRecord();
1554 
1555                 pcBuffer += nWriteChars;
1556                 nCharsLeft = nCharsLeft - nWriteChars;
1557             }
1558         }
1559         break;
1560 
1561         case EXC_BIFF8:
1562             if( mnObjId != EXC_OBJ_INVALID_ID )
1563                 XclExpRecord::Save( rStrm );
1564         break;
1565 
1566         default:    DBG_ERROR_BIFF();
1567     }
1568 }
1569 
WriteBody(XclExpStream & rStrm)1570 void XclExpNote::WriteBody( XclExpStream& rStrm )
1571 {
1572     // BIFF5/BIFF7 is written separately
1573     OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
1574 
1575     sal_uInt16 nFlags = 0;
1576     ::set_flag( nFlags, EXC_NOTE_VISIBLE, mbVisible );
1577 
1578     rStrm   << static_cast< sal_uInt16 >( maScPos.Row() )
1579             << static_cast< sal_uInt16 >( maScPos.Col() )
1580             << nFlags
1581             << mnObjId
1582             << maAuthor
1583             << sal_uInt8( 0 );
1584 }
1585 
WriteXml(sal_Int32 nAuthorId,XclExpXmlStream & rStrm)1586 void XclExpNote::WriteXml( sal_Int32 nAuthorId, XclExpXmlStream& rStrm )
1587 {
1588     sax_fastparser::FSHelperPtr rComments = rStrm.GetCurrentStream();
1589 
1590     rComments->startElement( XML_comment,
1591             XML_ref,        XclXmlUtils::ToOString(&mrRoot.GetDoc(), maScPos),
1592             XML_authorId,   OString::number(nAuthorId)
1593             // OOXTODO: XML_guid
1594     );
1595     rComments->startElement(XML_text);
1596     // OOXTODO: phoneticPr, rPh, r
1597     if( mpNoteContents )
1598         mpNoteContents->WriteXml( rStrm );
1599     rComments->endElement( XML_text );
1600 
1601 /*
1602    Export of commentPr is disabled, since the current (Oct 2010)
1603    version of MSO 2010 doesn't yet support commentPr
1604  */
1605 #if 1//def XLSX_OOXML_FUTURE
1606     if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1607     {
1608         rComments->startElement(FSNS(XML_mc, XML_AlternateContent));
1609         rComments->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "v2");
1610         rComments->startElement( XML_commentPr,
1611                 XML_autoFill,       ToPsz( mbAutoFill ),
1612                 XML_autoScale,      ToPsz( mbAutoScale ),
1613                 XML_colHidden,      ToPsz( mbColHidden ),
1614                 XML_locked,         ToPsz( mbLocked ),
1615                 XML_rowHidden,      ToPsz( mbRowHidden ),
1616                 XML_textHAlign,     ToHorizAlign( meTHA ),
1617                 XML_textVAlign,     ToVertAlign( meTVA )  );
1618         rComments->startElement(XML_anchor, XML_moveWithCells, "false", XML_sizeWithCells, "false");
1619         rComments->startElement(FSNS(XML_xdr, XML_from));
1620         lcl_WriteAnchorVertex( rComments, maCommentFrom );
1621         rComments->endElement( FSNS( XML_xdr, XML_from ) );
1622         rComments->startElement(FSNS(XML_xdr, XML_to));
1623         lcl_WriteAnchorVertex( rComments, maCommentTo );
1624         rComments->endElement( FSNS( XML_xdr, XML_to ) );
1625         rComments->endElement( XML_anchor );
1626         rComments->endElement( XML_commentPr );
1627 
1628         rComments->endElement( FSNS( XML_mc, XML_Choice ) );
1629         rComments->startElement(FSNS(XML_mc, XML_Fallback));
1630         // Any fallback code ?
1631         rComments->endElement( FSNS( XML_mc, XML_Fallback ) );
1632         rComments->endElement( FSNS( XML_mc, XML_AlternateContent ) );
1633     }
1634 #endif
1635     rComments->endElement( XML_comment );
1636 }
1637 
XclMacroHelper(const XclExpRoot & rRoot)1638 XclMacroHelper::XclMacroHelper( const XclExpRoot& rRoot ) :
1639     XclExpControlHelper( rRoot )
1640 {
1641 }
1642 
~XclMacroHelper()1643 XclMacroHelper::~XclMacroHelper()
1644 {
1645 }
1646 
WriteMacroSubRec(XclExpStream & rStrm)1647 void XclMacroHelper::WriteMacroSubRec( XclExpStream& rStrm )
1648 {
1649     if( mxMacroLink )
1650         WriteFormulaSubRec( rStrm, EXC_ID_OBJMACRO, *mxMacroLink );
1651 }
1652 
1653 bool
SetMacroLink(const ScriptEventDescriptor & rEvent,const XclTbxEventType & nEventType)1654 XclMacroHelper::SetMacroLink( const ScriptEventDescriptor& rEvent, const XclTbxEventType& nEventType )
1655 {
1656     OUString aMacroName = XclControlHelper::ExtractFromMacroDescriptor( rEvent, nEventType );
1657     if( !aMacroName.isEmpty() )
1658     {
1659         return SetMacroLink( aMacroName );
1660     }
1661     return false;
1662 }
1663 
1664 bool
SetMacroLink(const OUString & rMacroName)1665 XclMacroHelper::SetMacroLink( const OUString& rMacroName )
1666 {
1667     if( !rMacroName.isEmpty() )
1668     {
1669         sal_uInt16 nExtSheet = GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC );
1670         sal_uInt16 nNameIdx = GetNameManager().InsertMacroCall( rMacroName, true, false );
1671         mxMacroLink = GetFormulaCompiler().CreateNameXFormula( nExtSheet, nNameIdx );
1672         return true;
1673     }
1674     return false;
1675 }
1676 
XclExpShapeObj(XclExpObjectManager & rRoot,css::uno::Reference<css::drawing::XShape> const & xShape,ScDocument * pDoc)1677 XclExpShapeObj::XclExpShapeObj( XclExpObjectManager& rRoot, css::uno::Reference< css::drawing::XShape > const & xShape, ScDocument* pDoc ) :
1678     XclObjAny( rRoot, xShape, pDoc ),
1679     XclMacroHelper( rRoot )
1680 {
1681     if( SdrObject* pSdrObj = ::GetSdrObjectFromXShape( xShape ) )
1682     {
1683         ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pSdrObj );
1684         if ( pInfo && !pInfo->GetMacro().isEmpty() )
1685 // 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
1686 //            SetMacroLink( XclControlHelper::GetXclMacroName( pInfo->GetMacro(), rRoot.GetDocShell() ) );
1687             SetMacroLink( XclTools::GetXclMacroName( pInfo->GetMacro() ) );
1688     }
1689 }
1690 
~XclExpShapeObj()1691 XclExpShapeObj::~XclExpShapeObj()
1692 {
1693 }
1694 
WriteSubRecs(XclExpStream & rStrm)1695 void XclExpShapeObj::WriteSubRecs( XclExpStream& rStrm )
1696 {
1697     XclObjAny::WriteSubRecs( rStrm );
1698     WriteMacroSubRec( rStrm );
1699 }
1700 
XclExpComments(SCTAB nTab,XclExpRecordList<XclExpNote> & rNotes)1701 XclExpComments::XclExpComments( SCTAB nTab, XclExpRecordList< XclExpNote >& rNotes )
1702     : mnTab( nTab ), mrNotes( rNotes )
1703 {
1704 }
1705 
SaveXml(XclExpXmlStream & rStrm)1706 void XclExpComments::SaveXml( XclExpXmlStream& rStrm )
1707 {
1708     if( mrNotes.IsEmpty() )
1709         return;
1710 
1711     sax_fastparser::FSHelperPtr rComments = rStrm.CreateOutputStream(
1712             XclXmlUtils::GetStreamName( "xl/", "comments", mnTab + 1 ),
1713             XclXmlUtils::GetStreamName( "../", "comments", mnTab + 1 ),
1714             rStrm.GetCurrentStream()->getOutputStream(),
1715             "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
1716             OUStringToOString(oox::getRelationship(Relationship::COMMENTS), RTL_TEXTENCODING_UTF8).getStr());
1717     rStrm.PushStream( rComments );
1718 
1719     if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
1720         rComments->startElement( XML_comments,
1721             XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(),
1722             FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8(),
1723             FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)).toUtf8(),
1724             FSNS(XML_xmlns, XML_v2), rStrm.getNamespaceURL(OOX_NS(mceTest)).toUtf8(),
1725             FSNS( XML_mc, XML_Ignorable ), "v2" );
1726     else
1727         rComments->startElement( XML_comments,
1728             XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(),
1729             FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)).toUtf8() );
1730 
1731     rComments->startElement(XML_authors);
1732 
1733     typedef std::set<OUString> Authors;
1734     Authors aAuthors;
1735 
1736     size_t nNotes = mrNotes.GetSize();
1737     for( size_t i = 0; i < nNotes; ++i )
1738     {
1739         aAuthors.insert( XclXmlUtils::ToOUString( mrNotes.GetRecord( i )->GetAuthor() ) );
1740     }
1741 
1742     for( const auto& rAuthor : aAuthors )
1743     {
1744         rComments->startElement(XML_author);
1745         rComments->writeEscaped( rAuthor );
1746         rComments->endElement( XML_author );
1747     }
1748 
1749     rComments->endElement( XML_authors );
1750     rComments->startElement(XML_commentList);
1751 
1752     Authors::const_iterator aAuthorsBegin = aAuthors.begin();
1753     for( size_t i = 0; i < nNotes; ++i )
1754     {
1755         XclExpRecordList< XclExpNote >::RecordRefType xNote = mrNotes.GetRecord( i );
1756         Authors::const_iterator aAuthor = aAuthors.find(
1757                 XclXmlUtils::ToOUString( xNote->GetAuthor() ) );
1758         sal_Int32 nAuthorId = distance( aAuthorsBegin, aAuthor );
1759         xNote->WriteXml( nAuthorId, rStrm );
1760     }
1761 
1762     rComments->endElement( XML_commentList );
1763     rComments->endElement( XML_comments );
1764 
1765     rStrm.PopStream();
1766 }
1767 
1768 // object manager =============================================================
1769 
XclExpObjectManager(const XclExpRoot & rRoot)1770 XclExpObjectManager::XclExpObjectManager( const XclExpRoot& rRoot ) :
1771     XclExpRoot( rRoot )
1772 {
1773     InitStream( true );
1774     mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm ) );
1775 }
1776 
XclExpObjectManager(const XclExpObjectManager & rParent)1777 XclExpObjectManager::XclExpObjectManager( const XclExpObjectManager& rParent ) :
1778     XclExpRoot( rParent.GetRoot() )
1779 {
1780     InitStream( false );
1781     mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm, rParent.mxEscherEx.get() ) );
1782 }
1783 
~XclExpObjectManager()1784 XclExpObjectManager::~XclExpObjectManager()
1785 {
1786 }
1787 
CreateDffAnchor() const1788 XclExpDffAnchorBase* XclExpObjectManager::CreateDffAnchor() const
1789 {
1790     return new XclExpDffSheetAnchor( GetRoot() );
1791 }
1792 
CreateDrawingGroup()1793 std::shared_ptr< XclExpRecordBase > XclExpObjectManager::CreateDrawingGroup()
1794 {
1795     return std::shared_ptr< XclExpRecordBase >( new XclExpMsoDrawingGroup( *mxEscherEx ) );
1796 }
1797 
StartSheet()1798 void XclExpObjectManager::StartSheet()
1799 {
1800     mxObjList.reset( new XclExpObjList( GetRoot(), *mxEscherEx ) );
1801 }
1802 
ProcessDrawing(const SdrPage * pSdrPage)1803 std::shared_ptr< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const SdrPage* pSdrPage )
1804 {
1805     if( pSdrPage )
1806         mxEscherEx->AddSdrPage( *pSdrPage );
1807     // the first dummy object may still be open
1808     OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1809     while( mxEscherEx->GetGroupLevel() )
1810         mxEscherEx->LeaveGroup();
1811     mxObjList->EndSheet();
1812     return mxObjList;
1813 }
1814 
ProcessDrawing(const Reference<XShapes> & rxShapes)1815 std::shared_ptr< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const Reference< XShapes >& rxShapes )
1816 {
1817     if( rxShapes.is() )
1818         mxEscherEx->AddUnoShapes( rxShapes );
1819     // the first dummy object may still be open
1820     OSL_ENSURE( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1821     while( mxEscherEx->GetGroupLevel() )
1822         mxEscherEx->LeaveGroup();
1823     mxObjList->EndSheet();
1824     return mxObjList;
1825 }
1826 
EndDocument()1827 void XclExpObjectManager::EndDocument()
1828 {
1829     mxEscherEx->EndDocument();
1830 }
1831 
GetMsodrawingPerSheet()1832 XclExpMsoDrawing* XclExpObjectManager::GetMsodrawingPerSheet()
1833 {
1834     return mxObjList->GetMsodrawingPerSheet();
1835 }
1836 
HasObj() const1837 bool XclExpObjectManager::HasObj() const
1838 {
1839     return !mxObjList->empty();
1840 }
1841 
AddObj(std::unique_ptr<XclObj> pObjRec)1842 sal_uInt16 XclExpObjectManager::AddObj( std::unique_ptr<XclObj> pObjRec )
1843 {
1844     return mxObjList->Add( std::move(pObjRec) );
1845 }
1846 
RemoveLastObj()1847 std::unique_ptr<XclObj> XclExpObjectManager::RemoveLastObj()
1848 {
1849     return mxObjList->pop_back();
1850 }
1851 
InitStream(bool bTempFile)1852 void XclExpObjectManager::InitStream( bool bTempFile )
1853 {
1854     if( bTempFile )
1855     {
1856         mxTempFile.reset( new ::utl::TempFile );
1857         if( mxTempFile->IsValid() )
1858         {
1859             mxTempFile->EnableKillingFile();
1860             mxDffStrm = ::utl::UcbStreamHelper::CreateStream( mxTempFile->GetURL(), StreamMode::STD_READWRITE );
1861         }
1862     }
1863 
1864     if( !mxDffStrm.get() )
1865         mxDffStrm.reset( new SvMemoryStream );
1866 
1867     mxDffStrm->SetEndian( SvStreamEndian::LITTLE );
1868 }
1869 
XclExpEmbeddedObjectManager(const XclExpObjectManager & rParent,const Size & rPageSize,sal_Int32 nScaleX,sal_Int32 nScaleY)1870 XclExpEmbeddedObjectManager::XclExpEmbeddedObjectManager(
1871         const XclExpObjectManager& rParent, const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
1872     XclExpObjectManager( rParent ),
1873     maPageSize( rPageSize ),
1874     mnScaleX( nScaleX ),
1875     mnScaleY( nScaleY )
1876 {
1877 }
1878 
CreateDffAnchor() const1879 XclExpDffAnchorBase* XclExpEmbeddedObjectManager::CreateDffAnchor() const
1880 {
1881     return new XclExpDffEmbeddedAnchor( GetRoot(), maPageSize, mnScaleX, mnScaleY );
1882 }
1883 
1884 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1885