xref: /aoo4110/main/sc/source/filter/excel/xeescher.cxx (revision b1cdbd2c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 #include "xeescher.hxx"
28 
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/frame/XModel.hpp>
31 #include <com/sun/star/form/FormComponentType.hpp>
32 #include <com/sun/star/awt/VisualEffect.hpp>
33 #include <com/sun/star/awt/ScrollBarOrientation.hpp>
34 #include <com/sun/star/drawing/XShape.hpp>
35 #include <com/sun/star/form/binding/XBindableValue.hpp>
36 #include <com/sun/star/form/binding/XValueBinding.hpp>
37 #include <com/sun/star/form/binding/XListEntrySink.hpp>
38 #include <com/sun/star/form/binding/XListEntrySource.hpp>
39 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
40 
41 #include <set>
42 #include <rtl/ustrbuf.h>
43 #include <vcl/bmpacc.hxx>
44 #include <svx/svdoole2.hxx>
45 #include <svx/svdocapt.hxx>
46 #include <editeng/outlobj.hxx>
47 #include <editeng/editobj.hxx>
48 #include <unotools/tempfile.hxx>
49 #include <unotools/ucbstreamhelper.hxx>
50 
51 #include "editutil.hxx"
52 #include "unonames.hxx"
53 #include "convuno.hxx"
54 #include "postit.hxx"
55 
56 #include "fapihelper.hxx"
57 #include "xechart.hxx"
58 #include "xeformula.hxx"
59 #include "xelink.hxx"
60 #include "xename.hxx"
61 #include "xestyle.hxx"
62 
63 using namespace ::oox;
64 
65 using ::rtl::OString;
66 using ::rtl::OUString;
67 using ::rtl::OUStringBuffer;
68 using ::com::sun::star::uno::UNO_QUERY;
69 using ::com::sun::star::uno::Reference;
70 using ::com::sun::star::uno::Sequence;
71 using ::com::sun::star::lang::XServiceInfo;
72 using ::com::sun::star::beans::XPropertySet;
73 using ::com::sun::star::drawing::XShape;
74 using ::com::sun::star::drawing::XShapes;
75 using ::com::sun::star::frame::XModel;
76 using ::com::sun::star::embed::XEmbeddedObject;
77 using ::com::sun::star::awt::XControlModel;
78 using ::com::sun::star::form::binding::XBindableValue;
79 using ::com::sun::star::form::binding::XValueBinding;
80 using ::com::sun::star::form::binding::XListEntrySink;
81 using ::com::sun::star::form::binding::XListEntrySource;
82 using ::com::sun::star::script::ScriptEventDescriptor;
83 using ::com::sun::star::table::CellAddress;
84 using ::com::sun::star::table::CellRangeAddress;
85 
86 // Escher client anchor =======================================================
87 
XclExpDffAnchorBase(const XclExpRoot & rRoot,sal_uInt16 nFlags)88 XclExpDffAnchorBase::XclExpDffAnchorBase( const XclExpRoot& rRoot, sal_uInt16 nFlags ) :
89     XclExpRoot( rRoot ),
90     mnFlags( nFlags )
91 {
92 }
93 
SetFlags(const SdrObject & rSdrObj)94 void XclExpDffAnchorBase::SetFlags( const SdrObject& rSdrObj )
95 {
96     ImplSetFlags( rSdrObj );
97 }
98 
SetSdrObject(const SdrObject & rSdrObj)99 void XclExpDffAnchorBase::SetSdrObject( const SdrObject& rSdrObj )
100 {
101     ImplSetFlags( rSdrObj );
102     ImplCalcAnchorRect( rSdrObj.GetCurrentBoundRect(), MAP_100TH_MM );
103 }
104 
WriteDffData(EscherEx & rEscherEx) const105 void XclExpDffAnchorBase::WriteDffData( EscherEx& rEscherEx ) const
106 {
107     rEscherEx.AddAtom( 18, ESCHER_ClientAnchor );
108     rEscherEx.GetStream() << mnFlags << maAnchor;
109 }
110 
WriteData(EscherEx & rEscherEx,const Rectangle & rRect)111 void XclExpDffAnchorBase::WriteData( EscherEx& rEscherEx, const Rectangle& rRect )
112 {
113     // the passed rectangle is in twips
114     ImplCalcAnchorRect( rRect, MAP_TWIP );
115     WriteDffData( rEscherEx );
116 }
117 
ImplSetFlags(const SdrObject &)118 void XclExpDffAnchorBase::ImplSetFlags( const SdrObject& )
119 {
120     OSL_ENSURE( false, "XclExpDffAnchorBase::ImplSetFlags - not implemented" );
121 }
122 
ImplCalcAnchorRect(const Rectangle &,MapUnit)123 void XclExpDffAnchorBase::ImplCalcAnchorRect( const Rectangle&, MapUnit )
124 {
125     OSL_ENSURE( false, "XclExpDffAnchorBase::ImplCalcAnchorRect - not implemented" );
126 }
127 
128 // ----------------------------------------------------------------------------
129 
XclExpDffSheetAnchor(const XclExpRoot & rRoot)130 XclExpDffSheetAnchor::XclExpDffSheetAnchor( const XclExpRoot& rRoot ) :
131     XclExpDffAnchorBase( rRoot ),
132     mnScTab( rRoot.GetCurrScTab() )
133 {
134 }
135 
ImplSetFlags(const SdrObject & rSdrObj)136 void XclExpDffSheetAnchor::ImplSetFlags( const SdrObject& rSdrObj )
137 {
138     // Special case "page anchor" (X==0,Y==1) -> lock pos and size.
139     const Point& rPos = rSdrObj.GetAnchorPos();
140     mnFlags = ((rPos.X() == 0) && (rPos.Y() == 1)) ? EXC_ESC_ANCHOR_LOCKED : 0;
141 }
142 
ImplCalcAnchorRect(const Rectangle & rRect,MapUnit eMapUnit)143 void XclExpDffSheetAnchor::ImplCalcAnchorRect( const Rectangle& rRect, MapUnit eMapUnit )
144 {
145     maAnchor.SetRect( GetRoot(), mnScTab, rRect, eMapUnit );
146 }
147 
148 // ----------------------------------------------------------------------------
149 
XclExpDffEmbeddedAnchor(const XclExpRoot & rRoot,const Size & rPageSize,sal_Int32 nScaleX,sal_Int32 nScaleY)150 XclExpDffEmbeddedAnchor::XclExpDffEmbeddedAnchor( const XclExpRoot& rRoot,
151         const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
152     XclExpDffAnchorBase( rRoot ),
153     maPageSize( rPageSize ),
154     mnScaleX( nScaleX ),
155     mnScaleY( nScaleY )
156 {
157 }
158 
ImplSetFlags(const SdrObject &)159 void XclExpDffEmbeddedAnchor::ImplSetFlags( const SdrObject& /*rSdrObj*/ )
160 {
161     // TODO (unsupported feature): fixed size
162 }
163 
ImplCalcAnchorRect(const Rectangle & rRect,MapUnit eMapUnit)164 void XclExpDffEmbeddedAnchor::ImplCalcAnchorRect( const Rectangle& rRect, MapUnit eMapUnit )
165 {
166     maAnchor.SetRect( maPageSize, mnScaleX, mnScaleY, rRect, eMapUnit, true );
167 }
168 
169 // ----------------------------------------------------------------------------
170 
XclExpDffNoteAnchor(const XclExpRoot & rRoot,const Rectangle & rRect)171 XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot& rRoot, const Rectangle& rRect ) :
172     XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_SIZELOCKED )
173 {
174     maAnchor.SetRect( rRoot, rRoot.GetCurrScTab(), rRect, MAP_100TH_MM );
175 }
176 
177 // ----------------------------------------------------------------------------
178 
XclExpDffDropDownAnchor(const XclExpRoot & rRoot,const ScAddress & rScPos)179 XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
180     XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_POSLOCKED )
181 {
182     GetAddressConverter().ConvertAddress( maAnchor.maFirst, rScPos, true );
183     maAnchor.maLast.mnCol = maAnchor.maFirst.mnCol + 1;
184     maAnchor.maLast.mnRow = maAnchor.maFirst.mnRow + 1;
185     maAnchor.mnLX = maAnchor.mnTY = maAnchor.mnRX = maAnchor.mnBY = 0;
186 }
187 
188 // MSODRAWING* records ========================================================
189 
XclExpMsoDrawingBase(XclEscherEx & rEscherEx,sal_uInt16 nRecId)190 XclExpMsoDrawingBase::XclExpMsoDrawingBase( XclEscherEx& rEscherEx, sal_uInt16 nRecId ) :
191     XclExpRecord( nRecId ),
192     mrEscherEx( rEscherEx ),
193     mnFragmentKey( rEscherEx.InitNextDffFragment() )
194 {
195 }
196 
WriteBody(XclExpStream & rStrm)197 void XclExpMsoDrawingBase::WriteBody( XclExpStream& rStrm )
198 {
199     OSL_ENSURE( mrEscherEx.GetStreamPos() == mrEscherEx.GetDffFragmentPos( mnFragmentKey ),
200         "XclExpMsoDrawingBase::WriteBody - DFF stream position mismatch" );
201     rStrm.CopyFromStream( mrEscherEx.GetStream(), mrEscherEx.GetDffFragmentSize( mnFragmentKey ) );
202 }
203 
204 // ----------------------------------------------------------------------------
205 
XclExpMsoDrawingGroup(XclEscherEx & rEscherEx)206 XclExpMsoDrawingGroup::XclExpMsoDrawingGroup( XclEscherEx& rEscherEx ) :
207     XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWINGGROUP )
208 {
209     SvStream& rDffStrm = mrEscherEx.GetStream();
210 
211     // write the DGGCONTAINER with some default settings
212     mrEscherEx.OpenContainer( ESCHER_DggContainer );
213 
214     // TODO: stuff the OPT atom with our own document defaults?
215     static const sal_uInt8 spnDffOpt[] = {
216         0xBF, 0x00, 0x08, 0x00, 0x08, 0x00, 0x81, 0x01,
217         0x09, 0x00, 0x00, 0x08, 0xC0, 0x01, 0x40, 0x00,
218         0x00, 0x08
219     };
220     mrEscherEx.AddAtom( sizeof( spnDffOpt ), ESCHER_OPT, 3, 3 );
221     rDffStrm.Write( spnDffOpt, sizeof( spnDffOpt ) );
222 
223     // SPLITMENUCOLORS contains colors in toolbar
224     static const sal_uInt8 spnDffSplitMenuColors[] = {
225         0x0D, 0x00, 0x00, 0x08, 0x0C, 0x00, 0x00, 0x08,
226         0x17, 0x00, 0x00, 0x08, 0xF7, 0x00, 0x00, 0x10
227     };
228     mrEscherEx.AddAtom( sizeof( spnDffSplitMenuColors ), ESCHER_SplitMenuColors, 0, 4 );
229     rDffStrm.Write( spnDffSplitMenuColors, sizeof( spnDffSplitMenuColors ) );
230 
231     // close the DGGCONTAINER
232     mrEscherEx.CloseContainer();
233     mrEscherEx.UpdateDffFragmentEnd();
234 }
235 
236 // ----------------------------------------------------------------------------
237 
XclExpMsoDrawing(XclEscherEx & rEscherEx)238 XclExpMsoDrawing::XclExpMsoDrawing( XclEscherEx& rEscherEx ) :
239     XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWING )
240 {
241 }
242 
243 // ============================================================================
244 
XclExpImgData(const Graphic & rGraphic,sal_uInt16 nRecId)245 XclExpImgData::XclExpImgData( const Graphic& rGraphic, sal_uInt16 nRecId ) :
246     maGraphic( rGraphic ),
247     mnRecId( nRecId )
248 {
249 }
250 
Save(XclExpStream & rStrm)251 void XclExpImgData::Save( XclExpStream& rStrm )
252 {
253     Bitmap aBmp = maGraphic.GetBitmap();
254     if( aBmp.GetBitCount() != 24 )
255         aBmp.Convert( BMP_CONVERSION_24BIT );
256 
257     if( BitmapReadAccess* pAccess = aBmp.AcquireReadAccess() )
258     {
259         sal_Int32 nWidth = ::std::min< sal_Int32 >( pAccess->Width(), 0xFFFF );
260         sal_Int32 nHeight = ::std::min< sal_Int32 >( pAccess->Height(), 0xFFFF );
261         if( (nWidth > 0) && (nHeight > 0) )
262         {
263             sal_uInt8 nPadding = static_cast< sal_uInt8 >( nWidth & 0x03 );
264             sal_uInt32 nTmpSize = static_cast< sal_uInt32 >( (nWidth * 3 + nPadding) * nHeight + 12 );
265 
266             rStrm.StartRecord( mnRecId, nTmpSize + 4 );
267 
268             rStrm   << EXC_IMGDATA_BMP                      // BMP format
269                     << EXC_IMGDATA_WIN                      // Windows
270                     << nTmpSize                             // size after _this_ field
271                     << sal_uInt32( 12 )                     // BITMAPCOREHEADER size
272                     << static_cast< sal_uInt16 >( nWidth )  // width
273                     << static_cast< sal_uInt16 >( nHeight ) // height
274                     << sal_uInt16( 1 )                      // planes
275                     << sal_uInt16( 24 );                    // bits per pixel
276 
277             for( sal_Int32 nY = nHeight - 1; nY >= 0; --nY )
278             {
279                 for( sal_Int32 nX = 0; nX < nWidth; ++nX )
280                 {
281                     const BitmapColor& rBmpColor = pAccess->GetPixel( nY, nX );
282                     rStrm << rBmpColor.GetBlue() << rBmpColor.GetGreen() << rBmpColor.GetRed();
283                 }
284                 rStrm.WriteZeroBytes( nPadding );
285             }
286 
287             rStrm.EndRecord();
288         }
289         aBmp.ReleaseAccess( pAccess );
290     }
291 }
292 
293 // ============================================================================
294 
XclExpControlHelper(const XclExpRoot & rRoot)295 XclExpControlHelper::XclExpControlHelper( const XclExpRoot& rRoot ) :
296     XclExpRoot( rRoot ),
297     mnEntryCount( 0 )
298 {
299 }
300 
~XclExpControlHelper()301 XclExpControlHelper::~XclExpControlHelper()
302 {
303 }
304 
ConvertSheetLinks(Reference<XShape> xShape)305 void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > xShape )
306 {
307     mxCellLink.reset();
308     mxSrcRange.reset();
309     mnEntryCount = 0;
310 
311     // get control model
312     Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
313     if( !xCtrlModel.is() )
314         return;
315 
316     // *** cell link *** ------------------------------------------------------
317 
318     Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
319     if( xBindable.is() )
320     {
321         Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
322         if( xServInfo.is() && xServInfo->supportsService( CREATE_OUSTRING( SC_SERVICENAME_VALBIND ) ) )
323         {
324             ScfPropertySet aBindProp( xServInfo );
325             CellAddress aApiAddress;
326             if( aBindProp.GetProperty( aApiAddress, CREATE_OUSTRING( SC_UNONAME_BOUNDCELL ) ) )
327             {
328                 ScAddress aCellLink;
329                 ScUnoConversion::FillScAddress( aCellLink, aApiAddress );
330                 if( GetTabInfo().IsExportTab( aCellLink.Tab() ) )
331                     mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aCellLink );
332             }
333         }
334     }
335 
336     // *** source range *** ---------------------------------------------------
337 
338     Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY );
339     if( xEntrySink.is() )
340     {
341         Reference< XServiceInfo > xServInfo( xEntrySink->getListEntrySource(), UNO_QUERY );
342         if( xServInfo.is() && xServInfo->supportsService( CREATE_OUSTRING( SC_SERVICENAME_LISTSOURCE ) ) )
343         {
344             ScfPropertySet aSinkProp( xServInfo );
345             CellRangeAddress aApiRange;
346             if( aSinkProp.GetProperty( aApiRange, CREATE_OUSTRING( SC_UNONAME_CELLRANGE ) ) )
347             {
348                 ScRange aSrcRange;
349                 ScUnoConversion::FillScRange( aSrcRange, aApiRange );
350                 if( (aSrcRange.aStart.Tab() == aSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( aSrcRange.aStart.Tab() ) )
351                     mxSrcRange = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aSrcRange );
352                 mnEntryCount = static_cast< sal_uInt16 >( aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1 );
353             }
354         }
355     }
356 }
357 
WriteFormula(XclExpStream & rStrm,const XclTokenArray & rTokArr) const358 void XclExpControlHelper::WriteFormula( XclExpStream& rStrm, const XclTokenArray& rTokArr ) const
359 {
360     sal_uInt16 nFmlaSize = rTokArr.GetSize();
361     rStrm << nFmlaSize << sal_uInt32( 0 );
362     rTokArr.WriteArray( rStrm );
363     if( nFmlaSize & 1 )             // pad to 16-bit
364         rStrm << sal_uInt8( 0 );
365 }
366 
WriteFormulaSubRec(XclExpStream & rStrm,sal_uInt16 nSubRecId,const XclTokenArray & rTokArr) const367 void XclExpControlHelper::WriteFormulaSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId, const XclTokenArray& rTokArr ) const
368 {
369     rStrm.StartRecord( nSubRecId, (rTokArr.GetSize() + 5) & ~1 );
370     WriteFormula( rStrm, rTokArr );
371     rStrm.EndRecord();
372 }
373 
374 // ----------------------------------------------------------------------------
375 
376 //delete for exporting OCX
377 //#if EXC_EXP_OCX_CTRL
378 
XclExpOcxControlObj(XclExpObjectManager & rObjMgr,Reference<XShape> xShape,const Rectangle * pChildAnchor,const String & rClassName,sal_uInt32 nStrmStart,sal_uInt32 nStrmSize)379 XclExpOcxControlObj::XclExpOcxControlObj( XclExpObjectManager& rObjMgr, Reference< XShape > xShape,
380         const Rectangle* pChildAnchor, const String& rClassName, sal_uInt32 nStrmStart, sal_uInt32 nStrmSize ) :
381     XclObj( rObjMgr, EXC_OBJTYPE_PICTURE, true ),
382     XclExpControlHelper( rObjMgr.GetRoot() ),
383     maClassName( rClassName ),
384     mnStrmStart( nStrmStart ),
385     mnStrmSize( nStrmSize )
386 {
387     ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
388 
389     // OBJ record flags
390     SetLocked( sal_True );
391     SetPrintable( aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Printable" ) ) );
392     SetAutoFill( sal_False );
393     SetAutoLine( sal_False );
394 
395     // fill DFF property set
396     mrEscherEx.OpenContainer( ESCHER_SpContainer );
397     mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVESPT | SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_OLESHAPE );
398     Rectangle aDummyRect;
399     EscherPropertyContainer aPropOpt( mrEscherEx.GetGraphicProvider(), mrEscherEx.QueryPictureStream(), aDummyRect );
400     aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape,    0x00080008 );   // bool field
401     aPropOpt.AddOpt( ESCHER_Prop_lineColor,         0x08000040 );
402     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash,   0x00080000 );   // bool field
403 
404     // #i51348# name of the control, may overwrite shape name
405     OUString aCtrlName;
406     if( aCtrlProp.GetProperty( aCtrlName, CREATE_OUSTRING( "Name" ) ) && (aCtrlName.getLength() > 0) )
407         aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
408 
409     // meta file
410     //! TODO - needs check
411     Reference< XPropertySet > xShapePS( xShape, UNO_QUERY );
412     if( xShapePS.is() && aPropOpt.CreateGraphicProperties( xShapePS, CREATE_STRING( "MetaFile" ), sal_False ) )
413     {
414         sal_uInt32 nBlipId;
415         if( aPropOpt.GetOpt( ESCHER_Prop_pib, nBlipId ) )
416             aPropOpt.AddOpt( ESCHER_Prop_pictureId, nBlipId );
417     }
418 
419     // write DFF property set to stream
420     aPropOpt.Commit( mrEscherEx.GetStream() );
421 
422     // anchor
423     ImplWriteAnchor( GetRoot(), SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
424 
425     mrEscherEx.AddAtom( 0, ESCHER_ClientData );                       // OBJ record
426     mrEscherEx.CloseContainer();  // ESCHER_SpContainer
427     mrEscherEx.UpdateDffFragmentEnd();
428 
429     // spreadsheet links
430     ConvertSheetLinks( xShape );
431 }
432 
WriteSubRecs(XclExpStream & rStrm)433 void XclExpOcxControlObj::WriteSubRecs( XclExpStream& rStrm )
434 {
435     // OBJCF - clipboard format
436     rStrm.StartRecord( EXC_ID_OBJCF, 2 );
437     rStrm << sal_uInt16( 2 );
438     rStrm.EndRecord();
439 
440     // OBJFLAGS
441     rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 );
442     rStrm << sal_uInt16( 0x0031 );
443     rStrm.EndRecord();
444 
445     // OBJPICTFMLA
446     XclExpString aClass( maClassName );
447     sal_uInt16 nClassNameSize = static_cast< sal_uInt16 >( aClass.GetSize() );
448     sal_uInt16 nClassNamePad = nClassNameSize & 1;
449     sal_uInt16 nFirstPartSize = 12 + nClassNameSize + nClassNamePad;
450 
451     const XclTokenArray* pCellLink = GetCellLinkTokArr();
452     sal_uInt16 nCellLinkSize = pCellLink ? ((pCellLink->GetSize() + 7) & 0xFFFE) : 0;
453 
454     const XclTokenArray* pSrcRange = GetSourceRangeTokArr();
455     sal_uInt16 nSrcRangeSize = pSrcRange ? ((pSrcRange->GetSize() + 7) & 0xFFFE) : 0;
456 
457     sal_uInt16 nPictFmlaSize = nFirstPartSize + nCellLinkSize + nSrcRangeSize + 18;
458     rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nPictFmlaSize );
459 
460     rStrm   << sal_uInt16( nFirstPartSize )             // size of first part
461             << sal_uInt16( 5 )                          // formula size
462             << sal_uInt32( 0 )                          // unknown ID
463             << sal_uInt8( 0x02 ) << sal_uInt32( 0 )     // tTbl token with unknown ID
464             << sal_uInt8( 3 )                           // pad to word
465             << aClass;                                  // "Forms.***.1"
466     rStrm.WriteZeroBytes( nClassNamePad );              // pad to word
467     rStrm   << mnStrmStart                              // start in 'Ctls' stream
468             << mnStrmSize                               // size in 'Ctls' stream
469             << sal_uInt32( 0 );                         // class ID size
470     // cell link
471     rStrm << nCellLinkSize;
472     if( pCellLink )
473         WriteFormula( rStrm, *pCellLink );
474     // list source range
475     rStrm << nSrcRangeSize;
476     if( pSrcRange )
477         WriteFormula( rStrm, *pSrcRange );
478 
479     rStrm.EndRecord();
480 }
481 
482 //#else
483 
XclExpTbxControlObj(XclExpObjectManager & rObjMgr,Reference<XShape> xShape,const Rectangle * pChildAnchor)484 XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rObjMgr, Reference< XShape > xShape, const Rectangle* pChildAnchor ) :
485     XclObj( rObjMgr, EXC_OBJTYPE_UNKNOWN, true ),
486     XclExpControlHelper( rObjMgr.GetRoot() ),
487     mnHeight( 0 ),
488     mnState( 0 ),
489     mnLineCount( 0 ),
490     mnSelEntry( 0 ),
491     mnScrollValue( 0 ),
492     mnScrollMin( 0 ),
493     mnScrollMax( 100 ),
494     mnScrollStep( 1 ),
495     mnScrollPage( 10 ),
496     mbFlatButton( false ),
497     mbFlatBorder( false ),
498     mbMultiSel( false ),
499     mbScrollHor( false )
500 {
501     namespace FormCompType = ::com::sun::star::form::FormComponentType;
502     namespace AwtVisualEffect = ::com::sun::star::awt::VisualEffect;
503     namespace AwtScrollOrient = ::com::sun::star::awt::ScrollBarOrientation;
504 
505     ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
506     if( !xShape.is() || !aCtrlProp.Is() )
507         return;
508 
509     mnHeight = xShape->getSize().Height;
510     if( mnHeight <= 0 )
511         return;
512 
513     // control type
514     sal_Int16 nClassId = 0;
515     if( aCtrlProp.GetProperty( nClassId, CREATE_OUSTRING( "ClassId" ) ) )
516     {
517         switch( nClassId )
518         {
519             case FormCompType::COMMANDBUTTON:   mnObjType = EXC_OBJTYPE_BUTTON;       meEventType = EXC_TBX_EVENT_ACTION; break;
520             case FormCompType::RADIOBUTTON:     mnObjType = EXC_OBJTYPE_OPTIONBUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
521             case FormCompType::CHECKBOX:        mnObjType = EXC_OBJTYPE_CHECKBOX;     meEventType = EXC_TBX_EVENT_ACTION; break;
522             case FormCompType::LISTBOX:         mnObjType = EXC_OBJTYPE_LISTBOX;      meEventType = EXC_TBX_EVENT_CHANGE; break;
523             case FormCompType::COMBOBOX:        mnObjType = EXC_OBJTYPE_DROPDOWN;     meEventType = EXC_TBX_EVENT_CHANGE; break;
524             case FormCompType::GROUPBOX:        mnObjType = EXC_OBJTYPE_GROUPBOX;     meEventType = EXC_TBX_EVENT_MOUSE;  break;
525             case FormCompType::FIXEDTEXT:       mnObjType = EXC_OBJTYPE_LABEL;        meEventType = EXC_TBX_EVENT_MOUSE;  break;
526             case FormCompType::SCROLLBAR:       mnObjType = EXC_OBJTYPE_SCROLLBAR;    meEventType = EXC_TBX_EVENT_VALUE;  break;
527             case FormCompType::SPINBUTTON:      mnObjType = EXC_OBJTYPE_SPIN;         meEventType = EXC_TBX_EVENT_VALUE;  break;
528         }
529     }
530     if( mnObjType == EXC_OBJTYPE_UNKNOWN )
531         return;
532 
533     // OBJ record flags
534     SetLocked( sal_True );
535     SetPrintable( aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Printable" ) ) );
536     SetAutoFill( sal_False );
537     SetAutoLine( sal_False );
538 
539     // fill DFF property set
540     mrEscherEx.OpenContainer( ESCHER_SpContainer );
541     mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_HAVESPT );
542     EscherPropertyContainer aPropOpt;
543     bool bVisible = aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "EnableVisible" ) );
544     aPropOpt.AddOpt( ESCHER_Prop_fPrint, bVisible ? 0x00080000 : 0x00080002 ); // visible flag
545 
546     aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01000100 ); // bool field
547     aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 );                        // Text ID
548     aPropOpt.AddOpt( ESCHER_Prop_WrapText, 0x00000001 );
549     aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x001A0008 );      // bool field
550     aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00100000 );      // bool field
551     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 );     // bool field
552 
553     // #i51348# name of the control, may overwrite shape name
554     OUString aCtrlName;
555     if( aCtrlProp.GetProperty( aCtrlName, CREATE_OUSTRING( "Name" ) ) && (aCtrlName.getLength() > 0) )
556         aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
557 
558     //Export description as alt text
559 	if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
560 	{
561 		String  aAltTxt( pSdrObj->GetDescription(), 0, MSPROP_DESCRIPTION_MAX_LEN );
562 		aPropOpt.AddOpt( ESCHER_Prop_wzDescription, aAltTxt );
563 	}
564 
565     // write DFF property set to stream
566     aPropOpt.Commit( mrEscherEx.GetStream() );
567 
568     // anchor
569     ImplWriteAnchor( GetRoot(), SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
570 
571     mrEscherEx.AddAtom( 0, ESCHER_ClientData );                       // OBJ record
572     mrEscherEx.UpdateDffFragmentEnd();
573 
574     // control label
575     OUString aString;
576     if( aCtrlProp.GetProperty( aString, CREATE_OUSTRING( "Label" ) ) )
577     {
578         /*  Be sure to construct the MSODRAWING record containing the
579             ClientTextbox atom after the base OBJ's MSODRAWING record data is
580             completed. */
581         pClientTextbox = new XclExpMsoDrawing( mrEscherEx );
582         mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox );  // TXO record
583         mrEscherEx.UpdateDffFragmentEnd();
584 
585         sal_uInt16 nXclFont = EXC_FONT_APP;
586         if( aString.getLength() > 0 )
587         {
588             XclFontData aFontData;
589             GetFontPropSetHelper().ReadFontProperties( aFontData, aCtrlProp, EXC_FONTPROPSET_CONTROL );
590             if( (aFontData.maName.Len() > 0) && (aFontData.mnHeight > 0) )
591                 nXclFont = GetFontBuffer().Insert( aFontData, EXC_COLOR_CTRLTEXT );
592         }
593 
594         pTxo = new XclTxo( aString, nXclFont );
595         pTxo->SetHorAlign( (mnObjType == EXC_OBJTYPE_BUTTON) ? EXC_OBJ_HOR_CENTER : EXC_OBJ_HOR_LEFT );
596         pTxo->SetVerAlign( EXC_OBJ_VER_CENTER );
597     }
598 
599     mrEscherEx.CloseContainer();  // ESCHER_SpContainer
600 
601     // other properties
602     aCtrlProp.GetProperty( mnLineCount, CREATE_OUSTRING( "LineCount" ) );
603 
604     // border style
605     sal_Int16 nApiButton = AwtVisualEffect::LOOK3D;
606     sal_Int16 nApiBorder = AwtVisualEffect::LOOK3D;
607     switch( nClassId )
608     {
609         case FormCompType::LISTBOX:
610         case FormCompType::COMBOBOX:
611             aCtrlProp.GetProperty( nApiBorder, CREATE_OUSTRING( "Border" ) );
612         break;
613         case FormCompType::CHECKBOX:
614         case FormCompType::RADIOBUTTON:
615             aCtrlProp.GetProperty( nApiButton, CREATE_OUSTRING( "VisualEffect" ) );
616             nApiBorder = AwtVisualEffect::NONE;
617         break;
618         // Push button cannot be set to flat in Excel
619         case FormCompType::COMMANDBUTTON:
620             nApiBorder = AwtVisualEffect::LOOK3D;
621         break;
622         // Label does not support a border in Excel
623         case FormCompType::FIXEDTEXT:
624             nApiBorder = AwtVisualEffect::NONE;
625         break;
626         /*  Scroll bar and spin button have a "Border" property, but it is
627             really used for a border, and not for own 3D/flat look (#i34712#). */
628         case FormCompType::SCROLLBAR:
629         case FormCompType::SPINBUTTON:
630             nApiButton = AwtVisualEffect::LOOK3D;
631             nApiBorder = AwtVisualEffect::NONE;
632         break;
633         // Group box does not support flat style (#i34712#)
634         case FormCompType::GROUPBOX:
635             nApiBorder = AwtVisualEffect::LOOK3D;
636         break;
637     }
638     mbFlatButton = nApiButton != AwtVisualEffect::LOOK3D;
639     mbFlatBorder = nApiBorder != AwtVisualEffect::LOOK3D;
640 
641     // control state
642     sal_Int16 nApiState = 0;
643     if( aCtrlProp.GetProperty( nApiState, CREATE_OUSTRING( "State" ) ) )
644     {
645         switch( nApiState )
646         {
647             case 0: mnState = EXC_OBJ_CHECKBOX_UNCHECKED;  break;
648             case 1: mnState = EXC_OBJ_CHECKBOX_CHECKED;    break;
649             case 2: mnState = EXC_OBJ_CHECKBOX_TRISTATE;   break;
650         }
651     }
652 
653     // special control contents
654     switch( nClassId )
655     {
656         case FormCompType::LISTBOX:
657         {
658             mbMultiSel = aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "MultiSelection" ) );
659             Sequence< sal_Int16 > aSelection;
660             if( aCtrlProp.GetProperty( aSelection, CREATE_OUSTRING( "SelectedItems" ) ) )
661             {
662                 sal_Int32 nLen = aSelection.getLength();
663                 if( nLen > 0 )
664                 {
665                     mnSelEntry = aSelection[ 0 ] + 1;
666                     maMultiSel.resize( nLen );
667                     const sal_Int16* pnBegin = aSelection.getConstArray();
668                     ::std::copy( pnBegin, pnBegin + nLen, maMultiSel.begin() );
669                 }
670             }
671 
672             // convert listbox with dropdown button to Excel dropdown
673             if( aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Dropdown" ) ) )
674                 mnObjType = EXC_OBJTYPE_DROPDOWN;
675         }
676         break;
677 
678         case FormCompType::COMBOBOX:
679         {
680             Sequence< OUString > aStringList;
681             OUString aDefText;
682             if( aCtrlProp.GetProperty( aStringList, CREATE_OUSTRING( "StringItemList" ) ) &&
683                 aCtrlProp.GetProperty( aDefText, CREATE_OUSTRING( "Text" ) ) &&
684                 aStringList.getLength() && aDefText.getLength() )
685             {
686                 const OUString* pBegin = aStringList.getConstArray();
687                 const OUString* pEnd = pBegin + aStringList.getLength();
688                 const OUString* pString = ::std::find( pBegin, pEnd, aDefText );
689                 if( pString != pEnd )
690                     mnSelEntry = static_cast< sal_Int16 >( pString - pBegin + 1 );  // 1-based
691                 if( mnSelEntry > 0 )
692                     maMultiSel.resize( 1, mnSelEntry - 1 );
693             }
694 
695             // convert combobox without dropdown button to Excel listbox
696             if( !aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Dropdown" ) ) )
697                 mnObjType = EXC_OBJTYPE_LISTBOX;
698         }
699         break;
700 
701         case FormCompType::SCROLLBAR:
702         {
703             sal_Int32 nApiValue = 0;
704             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "ScrollValueMin" ) ) )
705                 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
706             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "ScrollValueMax" ) ) )
707                 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MIN );
708             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "ScrollValue" ) ) )
709                 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
710             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "LineIncrement" ) ) )
711                 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
712             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "BlockIncrement" ) ) )
713                 mnScrollPage = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
714             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "Orientation" ) ) )
715                 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
716         }
717         break;
718 
719         case FormCompType::SPINBUTTON:
720         {
721             sal_Int32 nApiValue = 0;
722             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinValueMin" ) ) )
723                 mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
724             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinValueMax" ) ) )
725                 mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
726             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinValue" ) ) )
727                 mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
728             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinIncrement" ) ) )
729                 mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
730             if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "Orientation" ) ) )
731                 mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
732         }
733         break;
734     }
735 
736     // spreadsheet links
737     ConvertSheetLinks( xShape );
738 }
739 
SetMacroLink(const ScriptEventDescriptor & rEvent)740 bool XclExpTbxControlObj::SetMacroLink( const ScriptEventDescriptor& rEvent )
741 {
742     String aMacroName = XclControlHelper::ExtractFromMacroDescriptor( rEvent, meEventType );
743     if( aMacroName.Len() )
744     {
745         sal_uInt16 nExtSheet = GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC );
746         sal_uInt16 nNameIdx = GetNameManager().InsertMacroCall( aMacroName, true, false );
747         mxMacroLink = GetFormulaCompiler().CreateNameXFormula( nExtSheet, nNameIdx );
748         return true;
749     }
750     return false;
751 }
752 
WriteSubRecs(XclExpStream & rStrm)753 void XclExpTbxControlObj::WriteSubRecs( XclExpStream& rStrm )
754 {
755     switch( mnObjType )
756     {
757         // *** Push buttons, labels ***
758 
759         case EXC_OBJTYPE_BUTTON:
760         case EXC_OBJTYPE_LABEL:
761             // ftMacro - macro link
762             WriteMacroSubRec( rStrm );
763         break;
764 
765         // *** Check boxes, option buttons ***
766 
767         case EXC_OBJTYPE_CHECKBOX:
768         case EXC_OBJTYPE_OPTIONBUTTON:
769         {
770             // ftCbls - box properties
771             sal_uInt16 nStyle = 0;
772             ::set_flag( nStyle, EXC_OBJ_CHECKBOX_FLAT, mbFlatButton );
773 
774             rStrm.StartRecord( EXC_ID_OBJCBLS, 12 );
775             rStrm << mnState;
776             rStrm.WriteZeroBytes( 8 );
777             rStrm << nStyle;
778             rStrm.EndRecord();
779 
780             // ftMacro - macro link
781             WriteMacroSubRec( rStrm );
782             // ftCblsFmla subrecord - cell link
783             WriteCellLinkSubRec( rStrm, EXC_ID_OBJCBLSFMLA );
784 
785             // ftCblsData subrecord - box properties, again
786             rStrm.StartRecord( EXC_ID_OBJCBLS, 8 );
787             rStrm << mnState;
788             rStrm.WriteZeroBytes( 4 );
789             rStrm << nStyle;
790             rStrm.EndRecord();
791         }
792         break;
793 
794         // *** List boxes, combo boxes ***
795 
796         case EXC_OBJTYPE_LISTBOX:
797         case EXC_OBJTYPE_DROPDOWN:
798         {
799             sal_uInt16 nEntryCount = GetSourceEntryCount();
800 
801             // ftSbs subrecord - Scroll bars
802             sal_Int32 nLineHeight = XclTools::GetHmmFromTwips( 200 );   // always 10pt
803             if( mnObjType == EXC_OBJTYPE_LISTBOX )
804                 mnLineCount = static_cast< sal_uInt16 >( mnHeight / nLineHeight );
805             mnScrollValue = 0;
806             mnScrollMin = 0;
807             sal_uInt16 nInvisLines = (nEntryCount >= mnLineCount) ? (nEntryCount - mnLineCount) : 0;
808             mnScrollMax = limit_cast< sal_uInt16 >( nInvisLines, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
809             mnScrollStep = 1;
810             mnScrollPage = limit_cast< sal_uInt16 >( mnLineCount, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
811             mbScrollHor = false;
812             WriteSbs( rStrm );
813 
814             // ftMacro - macro link
815             WriteMacroSubRec( rStrm );
816             // ftSbsFmla subrecord - cell link
817             WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
818 
819             // ftLbsData - source data range and box properties
820             sal_uInt16 nStyle = 0;
821             ::insert_value( nStyle, mbMultiSel ? EXC_OBJ_LISTBOX_MULTI : EXC_OBJ_LISTBOX_SINGLE, 4, 2 );
822             ::set_flag( nStyle, EXC_OBJ_LISTBOX_FLAT, mbFlatBorder );
823 
824             rStrm.StartRecord( EXC_ID_OBJLBSDATA, 0 );
825 
826             if( const XclTokenArray* pSrcRange = GetSourceRangeTokArr() )
827             {
828                 rStrm << static_cast< sal_uInt16 >( (pSrcRange->GetSize() + 7) & 0xFFFE );
829                 WriteFormula( rStrm, *pSrcRange );
830             }
831             else
832                 rStrm << sal_uInt16( 0 );
833 
834             rStrm << nEntryCount << mnSelEntry << nStyle << sal_uInt16( 0 );
835             if( mnObjType == EXC_OBJTYPE_LISTBOX )
836             {
837                 if( nEntryCount )
838                 {
839                     ScfUInt8Vec aSelEx( nEntryCount, 0 );
840                     for( ScfInt16Vec::const_iterator aIt = maMultiSel.begin(), aEnd = maMultiSel.end(); aIt != aEnd; ++aIt )
841                         if( *aIt < nEntryCount )
842                             aSelEx[ *aIt ] = 1;
843                     rStrm.Write( &aSelEx[ 0 ], aSelEx.size() );
844                 }
845             }
846             else if( mnObjType == EXC_OBJTYPE_DROPDOWN )
847             {
848                 rStrm << sal_uInt16( 0 ) << mnLineCount << sal_uInt16( 0 ) << sal_uInt16( 0 );
849             }
850 
851             rStrm.EndRecord();
852         }
853         break;
854 
855         // *** Spin buttons, scrollbars ***
856 
857         case EXC_OBJTYPE_SPIN:
858         case EXC_OBJTYPE_SCROLLBAR:
859         {
860             // ftSbs subrecord - scroll bars
861             WriteSbs( rStrm );
862             // ftMacro - macro link
863             WriteMacroSubRec( rStrm );
864             // ftSbsFmla subrecord - cell link
865             WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
866         }
867         break;
868 
869         // *** Group boxes ***
870 
871         case EXC_OBJTYPE_GROUPBOX:
872         {
873             // ftMacro - macro link
874             WriteMacroSubRec( rStrm );
875 
876             // ftGboData subrecord - group box properties
877             sal_uInt16 nStyle = 0;
878             ::set_flag( nStyle, EXC_OBJ_GROUPBOX_FLAT, mbFlatBorder );
879 
880             rStrm.StartRecord( EXC_ID_OBJGBODATA, 6 );
881             rStrm   << sal_uInt32( 0 )
882                     << nStyle;
883             rStrm.EndRecord();
884         }
885         break;
886     }
887 }
888 
WriteMacroSubRec(XclExpStream & rStrm)889 void XclExpTbxControlObj::WriteMacroSubRec( XclExpStream& rStrm )
890 {
891     if( mxMacroLink.is() )
892         WriteFormulaSubRec( rStrm, EXC_ID_OBJMACRO, *mxMacroLink );
893 }
894 
WriteCellLinkSubRec(XclExpStream & rStrm,sal_uInt16 nSubRecId)895 void XclExpTbxControlObj::WriteCellLinkSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId )
896 {
897     if( const XclTokenArray* pCellLink = GetCellLinkTokArr() )
898         WriteFormulaSubRec( rStrm, nSubRecId, *pCellLink );
899 }
900 
WriteSbs(XclExpStream & rStrm)901 void XclExpTbxControlObj::WriteSbs( XclExpStream& rStrm )
902 {
903     sal_uInt16 nOrient = 0;
904     ::set_flag( nOrient, EXC_OBJ_SCROLLBAR_HOR, mbScrollHor );
905     sal_uInt16 nStyle = EXC_OBJ_SCROLLBAR_DEFFLAGS;
906     ::set_flag( nStyle, EXC_OBJ_SCROLLBAR_FLAT, mbFlatButton );
907 
908     rStrm.StartRecord( EXC_ID_OBJSBS, 20 );
909     rStrm   << sal_uInt32( 0 )              // reserved
910             << mnScrollValue                // thumb position
911             << mnScrollMin                  // thumb min pos
912             << mnScrollMax                  // thumb max pos
913             << mnScrollStep                 // line increment
914             << mnScrollPage                 // page increment
915             << nOrient                      // 0 = vertical, 1 = horizontal
916             << sal_uInt16( 15 )             // thumb width
917             << nStyle;                      // flags/style
918     rStrm.EndRecord();
919 }
920 
921 //#endif
922 
923 // ----------------------------------------------------------------------------
924 
XclExpChartObj(XclExpObjectManager & rObjMgr,Reference<XShape> xShape,const Rectangle * pChildAnchor)925 XclExpChartObj::XclExpChartObj( XclExpObjectManager& rObjMgr, Reference< XShape > xShape, const Rectangle* pChildAnchor ) :
926     XclObj( rObjMgr, EXC_OBJTYPE_CHART ),
927     XclExpRoot( rObjMgr.GetRoot() )
928 {
929     // create the MSODRAWING record contents for the chart object
930     mrEscherEx.OpenContainer( ESCHER_SpContainer );
931     mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_HAVESPT );
932     EscherPropertyContainer aPropOpt;
933     aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 );
934     aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 );
935     aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x0800004E );
936     aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x0800004D );
937     aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 );
938     aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x0800004D );
939     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080008 );
940     aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00020000 );
941     aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 );
942     aPropOpt.Commit( mrEscherEx.GetStream() );
943 
944     // anchor
945     SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
946     ImplWriteAnchor( GetRoot(), pSdrObj, pChildAnchor );
947 
948     // client data (the following OBJ record)
949     mrEscherEx.AddAtom( 0, ESCHER_ClientData );
950     mrEscherEx.CloseContainer();  // ESCHER_SpContainer
951     mrEscherEx.UpdateDffFragmentEnd();
952 
953     // load the chart OLE object
954     if( SdrOle2Obj* pSdrOleObj = dynamic_cast< SdrOle2Obj* >( pSdrObj ) )
955         svt::EmbeddedObjectRef::TryRunningState( pSdrOleObj->GetObjRef() );
956 
957     // create the chart substream object
958     ScfPropertySet aShapeProp( xShape );
959     Reference< XModel > xModel;
960     aShapeProp.GetProperty( xModel, CREATE_OUSTRING( "Model" ) );
961     ::com::sun::star::awt::Rectangle aBoundRect;
962     aShapeProp.GetProperty( aBoundRect, CREATE_OUSTRING( "BoundRect" ) );
963     Rectangle aChartRect( Point( aBoundRect.X, aBoundRect.Y ), Size( aBoundRect.Width, aBoundRect.Height ) );
964     mxChart.reset( new XclExpChart( GetRoot(), xModel, aChartRect ) );
965 }
966 
~XclExpChartObj()967 XclExpChartObj::~XclExpChartObj()
968 {
969 }
970 
Save(XclExpStream & rStrm)971 void XclExpChartObj::Save( XclExpStream& rStrm )
972 {
973     // content of OBJ record
974     XclObj::Save( rStrm );
975     // chart substream
976     mxChart->Save( rStrm );
977 }
978 
979 // ============================================================================
980 
XclExpNote(const XclExpRoot & rRoot,const ScAddress & rScPos,const ScPostIt * pScNote,const String & rAddText)981 XclExpNote::XclExpNote( const XclExpRoot& rRoot, const ScAddress& rScPos,
982         const ScPostIt* pScNote, const String& rAddText ) :
983     XclExpRecord( EXC_ID_NOTE ),
984     maScPos( rScPos ),
985     mnObjId( EXC_OBJ_INVALID_ID ),
986     mbVisible( pScNote && pScNote->IsCaptionShown() )
987 {
988     // get the main note text
989     String aNoteText;
990     if( pScNote )
991         aNoteText = pScNote->GetText();
992     // append additional text
993     ScGlobal::AddToken( aNoteText, rAddText, '\n', 2 );
994     maOrigNoteText = aNoteText;
995 
996     // initialize record dependent on BIFF type
997     switch( rRoot.GetBiff() )
998     {
999         case EXC_BIFF5:
1000             maNoteText = ByteString( aNoteText, rRoot.GetTextEncoding() );
1001         break;
1002 
1003         case EXC_BIFF8:
1004         {
1005             // TODO: additional text
1006             if( pScNote )
1007                 if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ) )
1008                     if( const OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
1009                         mnObjId = rRoot.GetObjectManager().AddObj( new XclObjComment( rRoot.GetObjectManager(), pCaption->GetLogicRect(), pOPO->GetTextObject(), pCaption, mbVisible ) );
1010 
1011             SetRecSize( 9 + maAuthor.GetSize() );
1012         }
1013         break;
1014 
1015         default:    DBG_ERROR_BIFF();
1016     }
1017 }
1018 
Save(XclExpStream & rStrm)1019 void XclExpNote::Save( XclExpStream& rStrm )
1020 {
1021     switch( rStrm.GetRoot().GetBiff() )
1022     {
1023         case EXC_BIFF5:
1024         {
1025             // write the NOTE record directly, there may be the need to create more than one
1026             const sal_Char* pcBuffer = maNoteText.GetBuffer();
1027             sal_uInt16 nCharsLeft = static_cast< sal_uInt16 >( maNoteText.Len() );
1028 
1029             while( nCharsLeft )
1030             {
1031                 sal_uInt16 nWriteChars = ::std::min( nCharsLeft, EXC_NOTE5_MAXLEN );
1032 
1033                 rStrm.StartRecord( EXC_ID_NOTE, 6 + nWriteChars );
1034                 if( pcBuffer == maNoteText.GetBuffer() )
1035                 {
1036                     // first record: row, col, length of complete text
1037                     rStrm   << static_cast< sal_uInt16 >( maScPos.Row() )
1038                             << static_cast< sal_uInt16 >( maScPos.Col() )
1039                             << nCharsLeft;  // still contains full length
1040                 }
1041                 else
1042                 {
1043                     // next records: -1, 0, length of current text segment
1044                     rStrm   << sal_uInt16( 0xFFFF )
1045                             << sal_uInt16( 0 )
1046                             << nWriteChars;
1047                 }
1048                 rStrm.Write( pcBuffer, nWriteChars );
1049                 rStrm.EndRecord();
1050 
1051                 pcBuffer += nWriteChars;
1052                 nCharsLeft = nCharsLeft - nWriteChars;
1053             }
1054         }
1055         break;
1056 
1057         case EXC_BIFF8:
1058             if( mnObjId != EXC_OBJ_INVALID_ID )
1059                 XclExpRecord::Save( rStrm );
1060         break;
1061 
1062         default:    DBG_ERROR_BIFF();
1063     }
1064 }
1065 
WriteBody(XclExpStream & rStrm)1066 void XclExpNote::WriteBody( XclExpStream& rStrm )
1067 {
1068     // BIFF5/BIFF7 is written separately
1069     DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
1070 
1071     sal_uInt16 nFlags = 0;
1072     ::set_flag( nFlags, EXC_NOTE_VISIBLE, mbVisible );
1073 
1074     rStrm   << static_cast< sal_uInt16 >( maScPos.Row() )
1075             << static_cast< sal_uInt16 >( maScPos.Col() )
1076             << nFlags
1077             << mnObjId
1078             << maAuthor
1079             << sal_uInt8( 0 );
1080 }
1081 
WriteXml(sal_Int32 nAuthorId,XclExpXmlStream & rStrm)1082 void XclExpNote::WriteXml( sal_Int32 nAuthorId, XclExpXmlStream& rStrm )
1083 {
1084     sax_fastparser::FSHelperPtr rComments = rStrm.GetCurrentStream();
1085 
1086     rComments->startElement( XML_comment,
1087             XML_ref,        XclXmlUtils::ToOString( maScPos ).getStr(),
1088             XML_authorId,   OString::valueOf( nAuthorId ).getStr(),
1089             // OOXTODO: XML_guid,
1090             FSEND );
1091     rComments->startElement( XML_text, FSEND );
1092     // OOXTODO: phoneticPr, rPh, r
1093     rComments->startElement( XML_t, FSEND );
1094     rComments->writeEscaped( XclXmlUtils::ToOUString( maOrigNoteText ) );
1095     rComments->endElement ( XML_t );
1096     rComments->endElement( XML_text );
1097     rComments->endElement( XML_comment );
1098 }
1099 
1100 // ============================================================================
1101 
XclExpComments(SCTAB nTab,XclExpRecordList<XclExpNote> & rNotes)1102 XclExpComments::XclExpComments( SCTAB nTab, XclExpRecordList< XclExpNote >& rNotes )
1103     : mnTab( nTab ), mrNotes( rNotes )
1104 {
1105 }
1106 
1107 struct OUStringLess : public std::binary_function<OUString, OUString, bool>
1108 {
operator ()OUStringLess1109     bool operator()(const OUString& x, const OUString& y) const
1110     {
1111         return x.compareTo( y ) <= 0;
1112     }
1113 };
1114 
SaveXml(XclExpXmlStream & rStrm)1115 void XclExpComments::SaveXml( XclExpXmlStream& rStrm )
1116 {
1117     if( mrNotes.IsEmpty() )
1118         return;
1119 
1120     sax_fastparser::FSHelperPtr rComments = rStrm.CreateOutputStream(
1121             XclXmlUtils::GetStreamName( "xl/", "comments", mnTab + 1 ),
1122             XclXmlUtils::GetStreamName( "../", "comments", mnTab + 1 ),
1123             rStrm.GetCurrentStream()->getOutputStream(),
1124             "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
1125             "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" );
1126     rStrm.PushStream( rComments );
1127 
1128     rComments->startElement( XML_comments,
1129             XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
1130             FSEND );
1131     rComments->startElement( XML_authors, FSEND );
1132 
1133     typedef std::set< OUString, OUStringLess > Authors;
1134     Authors aAuthors;
1135 
1136     size_t nNotes = mrNotes.GetSize();
1137     for( size_t i = 0; i < nNotes; ++i )
1138     {
1139         aAuthors.insert( XclXmlUtils::ToOUString( mrNotes.GetRecord( i )->GetAuthor() ) );
1140     }
1141 
1142     for( Authors::const_iterator b = aAuthors.begin(), e = aAuthors.end(); b != e; ++b )
1143     {
1144         rComments->startElement( XML_author, FSEND );
1145         rComments->writeEscaped( *b );
1146         rComments->endElement( XML_author );
1147     }
1148 
1149     rComments->endElement( XML_authors );
1150     rComments->startElement( XML_commentList, FSEND );
1151 
1152     Authors::const_iterator aAuthorsBegin = aAuthors.begin();
1153     for( size_t i = 0; i < nNotes; ++i )
1154     {
1155         XclExpNoteList::RecordRefType xNote = mrNotes.GetRecord( i );
1156         Authors::const_iterator aAuthor = aAuthors.find(
1157                 XclXmlUtils::ToOUString( xNote->GetAuthor() ) );
1158         sal_Int32 nAuthorId = distance( aAuthorsBegin, aAuthor );
1159         xNote->WriteXml( nAuthorId, rStrm );
1160     }
1161 
1162     rComments->endElement( XML_commentList );
1163     rComments->endElement( XML_comments );
1164 
1165     rStrm.PopStream();
1166 }
1167 
1168 // object manager =============================================================
1169 
XclExpObjectManager(const XclExpRoot & rRoot)1170 XclExpObjectManager::XclExpObjectManager( const XclExpRoot& rRoot ) :
1171     XclExpRoot( rRoot )
1172 {
1173     InitStream( true );
1174     mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm ) );
1175 }
1176 
XclExpObjectManager(const XclExpObjectManager & rParent)1177 XclExpObjectManager::XclExpObjectManager( const XclExpObjectManager& rParent ) :
1178     XclExpRoot( rParent.GetRoot() )
1179 {
1180     InitStream( false );
1181     mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm, rParent.mxEscherEx.get() ) );
1182 }
1183 
~XclExpObjectManager()1184 XclExpObjectManager::~XclExpObjectManager()
1185 {
1186 }
1187 
CreateDffAnchor() const1188 XclExpDffAnchorBase* XclExpObjectManager::CreateDffAnchor() const
1189 {
1190     return new XclExpDffSheetAnchor( GetRoot() );
1191 }
1192 
CreateDrawingGroup()1193 ScfRef< XclExpRecordBase > XclExpObjectManager::CreateDrawingGroup()
1194 {
1195     return ScfRef< XclExpRecordBase >( new XclExpMsoDrawingGroup( *mxEscherEx ) );
1196 }
1197 
StartSheet()1198 void XclExpObjectManager::StartSheet()
1199 {
1200     mxObjList.reset( new XclExpObjList( GetRoot(), *mxEscherEx ) );
1201 }
1202 
ProcessDrawing(SdrPage * pSdrPage)1203 ScfRef< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( SdrPage* pSdrPage )
1204 {
1205     if( pSdrPage )
1206         mxEscherEx->AddSdrPage( *pSdrPage );
1207     // #106213# the first dummy object may still be open
1208     DBG_ASSERT( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1209     while( mxEscherEx->GetGroupLevel() )
1210         mxEscherEx->LeaveGroup();
1211     mxObjList->EndSheet();
1212     return mxObjList;
1213 }
1214 
ProcessDrawing(const Reference<XShapes> & rxShapes)1215 ScfRef< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const Reference< XShapes >& rxShapes )
1216 {
1217     if( rxShapes.is() )
1218         mxEscherEx->AddUnoShapes( rxShapes );
1219     // #106213# the first dummy object may still be open
1220     DBG_ASSERT( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1221     while( mxEscherEx->GetGroupLevel() )
1222         mxEscherEx->LeaveGroup();
1223     mxObjList->EndSheet();
1224     return mxObjList;
1225 }
1226 
EndDocument()1227 void XclExpObjectManager::EndDocument()
1228 {
1229     mxEscherEx->EndDocument();
1230 }
1231 
GetMsodrawingPerSheet()1232 XclExpMsoDrawing* XclExpObjectManager::GetMsodrawingPerSheet()
1233 {
1234     return mxObjList->GetMsodrawingPerSheet();
1235 }
1236 
HasObj() const1237 bool XclExpObjectManager::HasObj() const
1238 {
1239     return mxObjList->Count() > 0;
1240 }
1241 
AddObj(XclObj * pObjRec)1242 sal_uInt16 XclExpObjectManager::AddObj( XclObj* pObjRec )
1243 {
1244     return mxObjList->Add( pObjRec );
1245 }
1246 
RemoveLastObj()1247 XclObj* XclExpObjectManager::RemoveLastObj()
1248 {
1249     XclObj* pLastObj = static_cast< XclObj* >( mxObjList->Last() );
1250     mxObjList->Remove();    // remove current, which is the Last()
1251     return pLastObj;
1252 }
1253 
InitStream(bool bTempFile)1254 void XclExpObjectManager::InitStream( bool bTempFile )
1255 {
1256     if( bTempFile )
1257     {
1258         mxTempFile.reset( new ::utl::TempFile );
1259         if( mxTempFile->IsValid() )
1260         {
1261             mxTempFile->EnableKillingFile();
1262             mxDffStrm.reset( ::utl::UcbStreamHelper::CreateStream( mxTempFile->GetURL(), STREAM_STD_READWRITE ) );
1263         }
1264     }
1265 
1266     if( !mxDffStrm.get() )
1267         mxDffStrm.reset( new SvMemoryStream );
1268 
1269     mxDffStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
1270 }
1271 
1272 // ----------------------------------------------------------------------------
1273 
XclExpEmbeddedObjectManager(const XclExpObjectManager & rParent,const Size & rPageSize,sal_Int32 nScaleX,sal_Int32 nScaleY)1274 XclExpEmbeddedObjectManager::XclExpEmbeddedObjectManager(
1275         const XclExpObjectManager& rParent, const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
1276     XclExpObjectManager( rParent ),
1277     maPageSize( rPageSize ),
1278     mnScaleX( nScaleX ),
1279     mnScaleY( nScaleY )
1280 {
1281 }
1282 
CreateDffAnchor() const1283 XclExpDffAnchorBase* XclExpEmbeddedObjectManager::CreateDffAnchor() const
1284 {
1285     return new XclExpDffEmbeddedAnchor( GetRoot(), maPageSize, mnScaleX, mnScaleY );
1286 }
1287 
1288 // ============================================================================
1289 
1290