1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "xeescher.hxx"
23 #include <com/sun/star/lang/XServiceInfo.hpp>
24 #include <com/sun/star/frame/XModel.hpp>
25 #include <com/sun/star/form/FormComponentType.hpp>
26 #include <com/sun/star/awt/VisualEffect.hpp>
27 #include <com/sun/star/awt/ScrollBarOrientation.hpp>
28 #include <com/sun/star/drawing/XShape.hpp>
29 #include <com/sun/star/form/binding/XBindableValue.hpp>
30 #include <com/sun/star/form/binding/XValueBinding.hpp>
31 #include <com/sun/star/form/binding/XListEntrySink.hpp>
32 #include <com/sun/star/form/binding/XListEntrySource.hpp>
33 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
34 #include <com/sun/star/chart2/XChartDocument.hpp>
35 #include <com/sun/star/awt/Point.hpp>
36 #include <com/sun/star/awt/Size.hpp>
37 #include <com/sun/star/container/XNamed.hpp>
40 #include <rtl/ustrbuf.h>
41 #include <vcl/bmpacc.hxx>
42 #include <svx/svdoole2.hxx>
43 #include <svx/svdocapt.hxx>
44 #include <editeng/outlobj.hxx>
45 #include <editeng/editobj.hxx>
46 #include <unotools/tempfile.hxx>
47 #include <unotools/ucbstreamhelper.hxx>
49 #include "editutil.hxx"
50 #include "unonames.hxx"
51 #include "convuno.hxx"
54 #include "fapihelper.hxx"
55 #include "xechart.hxx"
56 #include "xeformula.hxx"
59 #include "xestyle.hxx"
60 #include "userdat.hxx"
61 #include "drwlayer.hxx"
62 #include "svx/unoapi.hxx"
63 #include "svx/algitem.hxx"
64 #include "scitems.hxx"
65 #include <editeng/justifyitem.hxx>
66 #include "svx/sdtaitm.hxx"
68 #include "document.hxx"
69 #include <svx/svdattr.hxx>
70 #include "svx/sdr/properties/properties.hxx"
71 #include "detfunc.hxx"
72 #include "svx/xflclit.hxx"
73 #include "svx/xlnstwit.hxx"
74 #include "svx/xlnstit.hxx"
75 #include "svx/sxmspitm.hxx"
77 #include <oox/token/tokens.hxx>
78 #include <oox/export/drawingml.hxx>
79 #include <oox/export/chartexport.hxx>
80 #include <oox/export/utils.hxx>
81 #include <boost/shared_ptr.hpp>
83 using ::com::sun::star::uno::UNO_QUERY
;
84 using ::com::sun::star::uno::Reference
;
85 using ::com::sun::star::uno::Sequence
;
86 using ::com::sun::star::lang::XServiceInfo
;
87 using ::com::sun::star::beans::XPropertySet
;
88 using ::com::sun::star::drawing::XShape
;
89 using ::com::sun::star::drawing::XShapes
;
90 using ::com::sun::star::frame::XModel
;
91 using ::com::sun::star::embed::XEmbeddedObject
;
92 using ::com::sun::star::awt::XControlModel
;
93 using ::com::sun::star::form::binding::XBindableValue
;
94 using ::com::sun::star::form::binding::XValueBinding
;
95 using ::com::sun::star::form::binding::XListEntrySink
;
96 using ::com::sun::star::form::binding::XListEntrySource
;
97 using ::com::sun::star::script::ScriptEventDescriptor
;
98 using ::com::sun::star::table::CellAddress
;
99 using ::com::sun::star::table::CellRangeAddress
;
100 using ::com::sun::star::chart2::XChartDocument
;
101 using ::com::sun::star::container::XNamed
;
102 using ::oox::drawingml::DrawingML
;
103 using ::oox::drawingml::ChartExport
;
106 #define HMM2XL(x) ((x)/26.5)+0.5
108 #if 1//def XLSX_OOXML_FUTURE
109 // these function are only used within that context
110 // Static Function Helpers
111 static const char *ToHorizAlign( SdrTextHorzAdjust eAdjust
)
115 case SDRTEXTHORZADJUST_CENTER
:
117 case SDRTEXTHORZADJUST_RIGHT
:
119 case SDRTEXTHORZADJUST_BLOCK
:
121 case SDRTEXTHORZADJUST_LEFT
:
127 static const char *ToVertAlign( SdrTextVertAdjust eAdjust
)
131 case SDRTEXTVERTADJUST_CENTER
:
133 case SDRTEXTVERTADJUST_BOTTOM
:
135 case SDRTEXTVERTADJUST_BLOCK
:
137 case SDRTEXTVERTADJUST_TOP
:
143 static void lcl_WriteAnchorVertex( sax_fastparser::FSHelperPtr rComments
, Rectangle
&aRect
)
145 rComments
->startElement( FSNS( XML_xdr
, XML_col
), FSEND
);
146 rComments
->writeEscaped( OUString::valueOf( aRect
.Left() ) );
147 rComments
->endElement( FSNS( XML_xdr
, XML_col
) );
148 rComments
->startElement( FSNS( XML_xdr
, XML_colOff
), FSEND
);
149 rComments
->writeEscaped( OUString::valueOf( aRect
.Top() ) );
150 rComments
->endElement( FSNS( XML_xdr
, XML_colOff
) );
151 rComments
->startElement( FSNS( XML_xdr
, XML_row
), FSEND
);
152 rComments
->writeEscaped( OUString::valueOf( aRect
.Right() ) );
153 rComments
->endElement( FSNS( XML_xdr
, XML_row
) );
154 rComments
->startElement( FSNS( XML_xdr
, XML_rowOff
), FSEND
);
155 rComments
->writeEscaped( OUString::valueOf( aRect
.Bottom() ) );
156 rComments
->endElement( FSNS( XML_xdr
, XML_rowOff
) );
160 static void lcl_GetFromTo( const XclExpRoot
& rRoot
, const Rectangle
&aRect
, sal_Int32 nTab
, Rectangle
&aFrom
, Rectangle
&aTo
)
163 sal_Int32 nCol
= 0, nRow
= 0;
164 sal_Int32 nColOff
= 0, nRowOff
= 0;
168 Rectangle r
= rRoot
.GetDocPtr()->GetMMRect( nCol
,nRow
,nCol
,nRow
,nTab
);
171 if( r
.Left() <= aRect
.Left() )
174 nColOff
= aRect
.Left() - r
.Left();
176 if( r
.Top() <= aRect
.Top() )
179 nRowOff
= aRect
.Top() - r
.Top();
181 if( r
.Left() > aRect
.Left() && r
.Top() > aRect
.Top() )
183 aFrom
= Rectangle( nCol
-1, static_cast<long>(HMM2XL( nColOff
)),
184 nRow
-1, static_cast<long>(HMM2XL( nRowOff
)) );
190 if( r
.Right() < aRect
.Right() )
192 if( r
.Bottom() < aRect
.Bottom() )
194 if( r
.Right() >= aRect
.Right() && r
.Bottom() >= aRect
.Bottom() )
196 aTo
= Rectangle( nCol
, static_cast<long>(HMM2XL( aRect
.Right() - r
.Left() )),
197 nRow
, static_cast<long>(HMM2XL( aRect
.Bottom() - r
.Top() )));
205 // Escher client anchor =======================================================
207 XclExpDffAnchorBase::XclExpDffAnchorBase( const XclExpRoot
& rRoot
, sal_uInt16 nFlags
) :
213 void XclExpDffAnchorBase::SetFlags( const SdrObject
& rSdrObj
)
215 ImplSetFlags( rSdrObj
);
218 void XclExpDffAnchorBase::SetSdrObject( const SdrObject
& rSdrObj
)
220 ImplSetFlags( rSdrObj
);
221 ImplCalcAnchorRect( rSdrObj
.GetCurrentBoundRect(), MAP_100TH_MM
);
224 void XclExpDffAnchorBase::WriteDffData( EscherEx
& rEscherEx
) const
226 rEscherEx
.AddAtom( 18, ESCHER_ClientAnchor
);
227 rEscherEx
.GetStream() << mnFlags
<< maAnchor
;
230 void XclExpDffAnchorBase::WriteData( EscherEx
& rEscherEx
, const Rectangle
& rRect
)
232 // the passed rectangle is in twips
233 ImplCalcAnchorRect( rRect
, MAP_TWIP
);
234 WriteDffData( rEscherEx
);
237 void XclExpDffAnchorBase::ImplSetFlags( const SdrObject
& )
239 OSL_FAIL( "XclExpDffAnchorBase::ImplSetFlags - not implemented" );
242 void XclExpDffAnchorBase::ImplCalcAnchorRect( const Rectangle
&, MapUnit
)
244 OSL_FAIL( "XclExpDffAnchorBase::ImplCalcAnchorRect - not implemented" );
247 // ----------------------------------------------------------------------------
249 XclExpDffSheetAnchor::XclExpDffSheetAnchor( const XclExpRoot
& rRoot
) :
250 XclExpDffAnchorBase( rRoot
),
251 mnScTab( rRoot
.GetCurrScTab() )
255 void XclExpDffSheetAnchor::ImplSetFlags( const SdrObject
& rSdrObj
)
257 // set flags for cell/page anchoring
258 if ( ScDrawLayer::GetAnchorType( rSdrObj
) == SCA_CELL
)
261 mnFlags
= EXC_ESC_ANCHOR_LOCKED
;
264 void XclExpDffSheetAnchor::ImplCalcAnchorRect( const Rectangle
& rRect
, MapUnit eMapUnit
)
266 maAnchor
.SetRect( GetRoot(), mnScTab
, rRect
, eMapUnit
);
269 // ----------------------------------------------------------------------------
271 XclExpDffEmbeddedAnchor::XclExpDffEmbeddedAnchor( const XclExpRoot
& rRoot
,
272 const Size
& rPageSize
, sal_Int32 nScaleX
, sal_Int32 nScaleY
) :
273 XclExpDffAnchorBase( rRoot
),
274 maPageSize( rPageSize
),
280 void XclExpDffEmbeddedAnchor::ImplSetFlags( const SdrObject
& /*rSdrObj*/ )
282 // TODO (unsupported feature): fixed size
285 void XclExpDffEmbeddedAnchor::ImplCalcAnchorRect( const Rectangle
& rRect
, MapUnit eMapUnit
)
287 maAnchor
.SetRect( maPageSize
, mnScaleX
, mnScaleY
, rRect
, eMapUnit
, true );
290 // ----------------------------------------------------------------------------
292 XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot
& rRoot
, const Rectangle
& rRect
) :
293 XclExpDffAnchorBase( rRoot
, EXC_ESC_ANCHOR_SIZELOCKED
)
295 maAnchor
.SetRect( rRoot
, rRoot
.GetCurrScTab(), rRect
, MAP_100TH_MM
);
298 // ----------------------------------------------------------------------------
300 XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot
& rRoot
, const ScAddress
& rScPos
) :
301 XclExpDffAnchorBase( rRoot
, EXC_ESC_ANCHOR_POSLOCKED
)
303 GetAddressConverter().ConvertAddress( maAnchor
.maFirst
, rScPos
, true );
304 maAnchor
.maLast
.mnCol
= maAnchor
.maFirst
.mnCol
+ 1;
305 maAnchor
.maLast
.mnRow
= maAnchor
.maFirst
.mnRow
+ 1;
306 maAnchor
.mnLX
= maAnchor
.mnTY
= maAnchor
.mnRX
= maAnchor
.mnBY
= 0;
309 // MSODRAWING* records ========================================================
311 XclExpMsoDrawingBase::XclExpMsoDrawingBase( XclEscherEx
& rEscherEx
, sal_uInt16 nRecId
) :
312 XclExpRecord( nRecId
),
313 mrEscherEx( rEscherEx
),
314 mnFragmentKey( rEscherEx
.InitNextDffFragment() )
318 void XclExpMsoDrawingBase::WriteBody( XclExpStream
& rStrm
)
320 OSL_ENSURE( mrEscherEx
.GetStreamPos() == mrEscherEx
.GetDffFragmentPos( mnFragmentKey
),
321 "XclExpMsoDrawingBase::WriteBody - DFF stream position mismatch" );
322 rStrm
.CopyFromStream( mrEscherEx
.GetStream(), mrEscherEx
.GetDffFragmentSize( mnFragmentKey
) );
325 // ----------------------------------------------------------------------------
327 XclExpMsoDrawingGroup::XclExpMsoDrawingGroup( XclEscherEx
& rEscherEx
) :
328 XclExpMsoDrawingBase( rEscherEx
, EXC_ID_MSODRAWINGGROUP
)
330 SvStream
& rDffStrm
= mrEscherEx
.GetStream();
332 // write the DGGCONTAINER with some default settings
333 mrEscherEx
.OpenContainer( ESCHER_DggContainer
);
335 // TODO: stuff the OPT atom with our own document defaults?
336 static const sal_uInt8 spnDffOpt
[] = {
337 0xBF, 0x00, 0x08, 0x00, 0x08, 0x00, 0x81, 0x01,
338 0x09, 0x00, 0x00, 0x08, 0xC0, 0x01, 0x40, 0x00,
341 mrEscherEx
.AddAtom( sizeof( spnDffOpt
), ESCHER_OPT
, 3, 3 );
342 rDffStrm
.Write( spnDffOpt
, sizeof( spnDffOpt
) );
344 // SPLITMENUCOLORS contains colors in toolbar
345 static const sal_uInt8 spnDffSplitMenuColors
[] = {
346 0x0D, 0x00, 0x00, 0x08, 0x0C, 0x00, 0x00, 0x08,
347 0x17, 0x00, 0x00, 0x08, 0xF7, 0x00, 0x00, 0x10
349 mrEscherEx
.AddAtom( sizeof( spnDffSplitMenuColors
), ESCHER_SplitMenuColors
, 0, 4 );
350 rDffStrm
.Write( spnDffSplitMenuColors
, sizeof( spnDffSplitMenuColors
) );
352 // close the DGGCONTAINER
353 mrEscherEx
.CloseContainer();
354 mrEscherEx
.UpdateDffFragmentEnd();
357 // ----------------------------------------------------------------------------
359 XclExpMsoDrawing::XclExpMsoDrawing( XclEscherEx
& rEscherEx
) :
360 XclExpMsoDrawingBase( rEscherEx
, EXC_ID_MSODRAWING
)
364 // ============================================================================
366 XclExpImgData::XclExpImgData( const Graphic
& rGraphic
, sal_uInt16 nRecId
) :
367 maGraphic( rGraphic
),
372 void XclExpImgData::Save( XclExpStream
& rStrm
)
374 Bitmap aBmp
= maGraphic
.GetBitmap();
375 if( aBmp
.GetBitCount() != 24 )
376 aBmp
.Convert( BMP_CONVERSION_24BIT
);
378 if( BitmapReadAccess
* pAccess
= aBmp
.AcquireReadAccess() )
380 sal_Int32 nWidth
= ::std::min
< sal_Int32
>( pAccess
->Width(), 0xFFFF );
381 sal_Int32 nHeight
= ::std::min
< sal_Int32
>( pAccess
->Height(), 0xFFFF );
382 if( (nWidth
> 0) && (nHeight
> 0) )
384 sal_uInt8 nPadding
= static_cast< sal_uInt8
>( nWidth
& 0x03 );
385 sal_uInt32 nTmpSize
= static_cast< sal_uInt32
>( (nWidth
* 3 + nPadding
) * nHeight
+ 12 );
387 rStrm
.StartRecord( mnRecId
, nTmpSize
+ 4 );
389 rStrm
<< EXC_IMGDATA_BMP
// BMP format
390 << EXC_IMGDATA_WIN
// Windows
391 << nTmpSize
// size after _this_ field
392 << sal_uInt32( 12 ) // BITMAPCOREHEADER size
393 << static_cast< sal_uInt16
>( nWidth
) // width
394 << static_cast< sal_uInt16
>( nHeight
) // height
395 << sal_uInt16( 1 ) // planes
396 << sal_uInt16( 24 ); // bits per pixel
398 for( sal_Int32 nY
= nHeight
- 1; nY
>= 0; --nY
)
400 for( sal_Int32 nX
= 0; nX
< nWidth
; ++nX
)
402 const BitmapColor
& rBmpColor
= pAccess
->GetPixel( nY
, nX
);
403 rStrm
<< rBmpColor
.GetBlue() << rBmpColor
.GetGreen() << rBmpColor
.GetRed();
405 rStrm
.WriteZeroBytes( nPadding
);
410 aBmp
.ReleaseAccess( pAccess
);
414 void XclExpImgData::SaveXml( XclExpXmlStream
& rStrm
)
416 sax_fastparser::FSHelperPtr pWorksheet
= rStrm
.GetCurrentStream();
418 DrawingML
aDML( pWorksheet
, &rStrm
, DrawingML::DOCUMENT_XLSX
);
419 OUString rId
= aDML
.WriteImage( maGraphic
);
420 pWorksheet
->singleElement( XML_picture
,
421 FSNS( XML_r
, XML_id
), XclXmlUtils::ToOString( rId
).getStr(),
425 // ============================================================================
427 XclExpControlHelper::XclExpControlHelper( const XclExpRoot
& rRoot
) :
433 XclExpControlHelper::~XclExpControlHelper()
437 void XclExpControlHelper::ConvertSheetLinks( Reference
< XShape
> xShape
)
444 Reference
< XControlModel
> xCtrlModel
= XclControlHelper::GetControlModel( xShape
);
445 if( !xCtrlModel
.is() )
448 // *** cell link *** ------------------------------------------------------
450 Reference
< XBindableValue
> xBindable( xCtrlModel
, UNO_QUERY
);
453 Reference
< XServiceInfo
> xServInfo( xBindable
->getValueBinding(), UNO_QUERY
);
454 if( xServInfo
.is() && xServInfo
->supportsService( SC_SERVICENAME_VALBIND
) )
456 ScfPropertySet
aBindProp( xServInfo
);
457 CellAddress aApiAddress
;
458 if( aBindProp
.GetProperty( aApiAddress
, SC_UNONAME_BOUNDCELL
) )
461 ScUnoConversion::FillScAddress( aCellLink
, aApiAddress
);
462 if( GetTabInfo().IsExportTab( aCellLink
.Tab() ) )
463 mxCellLink
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL
, aCellLink
);
468 // *** source range *** ---------------------------------------------------
470 Reference
< XListEntrySink
> xEntrySink( xCtrlModel
, UNO_QUERY
);
471 if( xEntrySink
.is() )
473 Reference
< XServiceInfo
> xServInfo( xEntrySink
->getListEntrySource(), UNO_QUERY
);
474 if( xServInfo
.is() && xServInfo
->supportsService( SC_SERVICENAME_LISTSOURCE
) )
476 ScfPropertySet
aSinkProp( xServInfo
);
477 CellRangeAddress aApiRange
;
478 if( aSinkProp
.GetProperty( aApiRange
, SC_UNONAME_CELLRANGE
) )
481 ScUnoConversion::FillScRange( aSrcRange
, aApiRange
);
482 if( (aSrcRange
.aStart
.Tab() == aSrcRange
.aEnd
.Tab()) && GetTabInfo().IsExportTab( aSrcRange
.aStart
.Tab() ) )
483 mxSrcRange
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL
, aSrcRange
);
484 mnEntryCount
= static_cast< sal_uInt16
>( aSrcRange
.aEnd
.Col() - aSrcRange
.aStart
.Col() + 1 );
490 void XclExpControlHelper::WriteFormula( XclExpStream
& rStrm
, const XclTokenArray
& rTokArr
) const
492 sal_uInt16 nFmlaSize
= rTokArr
.GetSize();
493 rStrm
<< nFmlaSize
<< sal_uInt32( 0 );
494 rTokArr
.WriteArray( rStrm
);
495 if( nFmlaSize
& 1 ) // pad to 16-bit
496 rStrm
<< sal_uInt8( 0 );
499 void XclExpControlHelper::WriteFormulaSubRec( XclExpStream
& rStrm
, sal_uInt16 nSubRecId
, const XclTokenArray
& rTokArr
) const
501 rStrm
.StartRecord( nSubRecId
, (rTokArr
.GetSize() + 5) & ~1 );
502 WriteFormula( rStrm
, rTokArr
);
506 // ----------------------------------------------------------------------------
510 XclExpOcxControlObj::XclExpOcxControlObj( XclExpObjectManager
& rObjMgr
, Reference
< XShape
> xShape
,
511 const Rectangle
* pChildAnchor
, const String
& rClassName
, sal_uInt32 nStrmStart
, sal_uInt32 nStrmSize
) :
512 XclObj( rObjMgr
, EXC_OBJTYPE_PICTURE
, true ),
513 XclExpControlHelper( rObjMgr
.GetRoot() ),
514 maClassName( rClassName
),
515 mnStrmStart( nStrmStart
),
516 mnStrmSize( nStrmSize
)
518 ScfPropertySet
aCtrlProp( XclControlHelper::GetControlModel( xShape
) );
521 SetLocked( sal_True
);
522 SetPrintable( aCtrlProp
.GetBoolProperty( "Printable" ) );
523 SetAutoFill( false );
524 SetAutoLine( false );
526 // fill DFF property set
527 mrEscherEx
.OpenContainer( ESCHER_SpContainer
);
528 mrEscherEx
.AddShape( ESCHER_ShpInst_HostControl
, SHAPEFLAG_HAVESPT
| SHAPEFLAG_HAVEANCHOR
| SHAPEFLAG_OLESHAPE
);
529 Rectangle aDummyRect
;
530 EscherPropertyContainer
aPropOpt( mrEscherEx
, mrEscherEx
.QueryPicStream(), aDummyRect
);
531 aPropOpt
.AddOpt( ESCHER_Prop_FitTextToShape
, 0x00080008 ); // bool field
532 aPropOpt
.AddOpt( ESCHER_Prop_lineColor
, 0x08000040 );
533 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x00080000 ); // bool field
535 // #i51348# name of the control, may overwrite shape name
537 if( aCtrlProp
.GetProperty( aCtrlName
, "Name" ) && !aCtrlName
.isEmpty() )
538 aPropOpt
.AddOpt( ESCHER_Prop_wzName
, aCtrlName
);
541 //! TODO - needs check
542 Reference
< XPropertySet
> xShapePS( xShape
, UNO_QUERY
);
543 if( xShapePS
.is() && aPropOpt
.CreateGraphicProperties( xShapePS
, String( "MetaFile" ), false ) )
546 if( aPropOpt
.GetOpt( ESCHER_Prop_pib
, nBlipId
) )
547 aPropOpt
.AddOpt( ESCHER_Prop_pictureId
, nBlipId
);
550 // write DFF property set to stream
551 aPropOpt
.Commit( mrEscherEx
.GetStream() );
554 ImplWriteAnchor( GetRoot(), SdrObject::getSdrObjectFromXShape( xShape
), pChildAnchor
);
556 mrEscherEx
.AddAtom( 0, ESCHER_ClientData
); // OBJ record
557 mrEscherEx
.CloseContainer(); // ESCHER_SpContainer
558 mrEscherEx
.UpdateDffFragmentEnd();
561 ConvertSheetLinks( xShape
);
564 void XclExpOcxControlObj::WriteSubRecs( XclExpStream
& rStrm
)
566 // OBJCF - clipboard format
567 rStrm
.StartRecord( EXC_ID_OBJCF
, 2 );
568 rStrm
<< sal_uInt16( 2 );
572 rStrm
.StartRecord( EXC_ID_OBJFLAGS
, 2 );
573 rStrm
<< sal_uInt16( 0x0031 );
577 XclExpString
aClass( maClassName
);
578 sal_uInt16 nClassNameSize
= static_cast< sal_uInt16
>( aClass
.GetSize() );
579 sal_uInt16 nClassNamePad
= nClassNameSize
& 1;
580 sal_uInt16 nFirstPartSize
= 12 + nClassNameSize
+ nClassNamePad
;
582 const XclTokenArray
* pCellLink
= GetCellLinkTokArr();
583 sal_uInt16 nCellLinkSize
= pCellLink
? ((pCellLink
->GetSize() + 7) & 0xFFFE) : 0;
585 const XclTokenArray
* pSrcRange
= GetSourceRangeTokArr();
586 sal_uInt16 nSrcRangeSize
= pSrcRange
? ((pSrcRange
->GetSize() + 7) & 0xFFFE) : 0;
588 sal_uInt16 nPictFmlaSize
= nFirstPartSize
+ nCellLinkSize
+ nSrcRangeSize
+ 18;
589 rStrm
.StartRecord( EXC_ID_OBJPICTFMLA
, nPictFmlaSize
);
591 rStrm
<< sal_uInt16( nFirstPartSize
) // size of first part
592 << sal_uInt16( 5 ) // formula size
593 << sal_uInt32( 0 ) // unknown ID
594 << sal_uInt8( 0x02 ) << sal_uInt32( 0 ) // tTbl token with unknown ID
595 << sal_uInt8( 3 ) // pad to word
596 << aClass
; // "Forms.***.1"
597 rStrm
.WriteZeroBytes( nClassNamePad
); // pad to word
598 rStrm
<< mnStrmStart
// start in 'Ctls' stream
599 << mnStrmSize
// size in 'Ctls' stream
600 << sal_uInt32( 0 ); // class ID size
602 rStrm
<< nCellLinkSize
;
604 WriteFormula( rStrm
, *pCellLink
);
606 rStrm
<< nSrcRangeSize
;
608 WriteFormula( rStrm
, *pSrcRange
);
615 XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager
& rRoot
, Reference
< XShape
> xShape
, const Rectangle
* pChildAnchor
) :
616 XclObj( rRoot
, EXC_OBJTYPE_UNKNOWN
, true ),
617 XclMacroHelper( rRoot
),
627 mbFlatButton( false ),
628 mbFlatBorder( false ),
632 namespace FormCompType
= ::com::sun::star::form::FormComponentType
;
633 namespace AwtVisualEffect
= ::com::sun::star::awt::VisualEffect
;
634 namespace AwtScrollOrient
= ::com::sun::star::awt::ScrollBarOrientation
;
636 ScfPropertySet
aCtrlProp( XclControlHelper::GetControlModel( xShape
) );
637 if( !xShape
.is() || !aCtrlProp
.Is() )
640 mnHeight
= xShape
->getSize().Height
;
645 sal_Int16 nClassId
= 0;
646 if( aCtrlProp
.GetProperty( nClassId
, "ClassId" ) )
650 case FormCompType::COMMANDBUTTON
: mnObjType
= EXC_OBJTYPE_BUTTON
; meEventType
= EXC_TBX_EVENT_ACTION
; break;
651 case FormCompType::RADIOBUTTON
: mnObjType
= EXC_OBJTYPE_OPTIONBUTTON
; meEventType
= EXC_TBX_EVENT_ACTION
; break;
652 case FormCompType::CHECKBOX
: mnObjType
= EXC_OBJTYPE_CHECKBOX
; meEventType
= EXC_TBX_EVENT_ACTION
; break;
653 case FormCompType::LISTBOX
: mnObjType
= EXC_OBJTYPE_LISTBOX
; meEventType
= EXC_TBX_EVENT_CHANGE
; break;
654 case FormCompType::COMBOBOX
: mnObjType
= EXC_OBJTYPE_DROPDOWN
; meEventType
= EXC_TBX_EVENT_CHANGE
; break;
655 case FormCompType::GROUPBOX
: mnObjType
= EXC_OBJTYPE_GROUPBOX
; meEventType
= EXC_TBX_EVENT_MOUSE
; break;
656 case FormCompType::FIXEDTEXT
: mnObjType
= EXC_OBJTYPE_LABEL
; meEventType
= EXC_TBX_EVENT_MOUSE
; break;
657 case FormCompType::SCROLLBAR
: mnObjType
= EXC_OBJTYPE_SCROLLBAR
; meEventType
= EXC_TBX_EVENT_VALUE
; break;
658 case FormCompType::SPINBUTTON
: mnObjType
= EXC_OBJTYPE_SPIN
; meEventType
= EXC_TBX_EVENT_VALUE
; break;
661 if( mnObjType
== EXC_OBJTYPE_UNKNOWN
)
665 SetLocked( sal_True
);
666 SetPrintable( aCtrlProp
.GetBoolProperty( "Printable" ) );
667 SetAutoFill( false );
668 SetAutoLine( false );
670 // fill DFF property set
671 mrEscherEx
.OpenContainer( ESCHER_SpContainer
);
672 mrEscherEx
.AddShape( ESCHER_ShpInst_HostControl
, SHAPEFLAG_HAVEANCHOR
| SHAPEFLAG_HAVESPT
);
673 EscherPropertyContainer aPropOpt
;
674 bool bVisible
= aCtrlProp
.GetBoolProperty( "EnableVisible" );
675 aPropOpt
.AddOpt( ESCHER_Prop_fPrint
, bVisible
? 0x00080000 : 0x00080002 ); // visible flag
677 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x01000100 ); // bool field
678 aPropOpt
.AddOpt( ESCHER_Prop_lTxid
, 0 ); // Text ID
679 aPropOpt
.AddOpt( ESCHER_Prop_WrapText
, 0x00000001 );
680 aPropOpt
.AddOpt( ESCHER_Prop_FitTextToShape
, 0x001A0008 ); // bool field
681 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x00100000 ); // bool field
682 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x00080000 ); // bool field
684 // #i51348# name of the control, may overwrite shape name
686 if( aCtrlProp
.GetProperty( aCtrlName
, "Name" ) && !aCtrlName
.isEmpty() )
687 aPropOpt
.AddOpt( ESCHER_Prop_wzName
, aCtrlName
);
689 // write DFF property set to stream
690 aPropOpt
.Commit( mrEscherEx
.GetStream() );
693 ImplWriteAnchor( GetRoot(), SdrObject::getSdrObjectFromXShape( xShape
), pChildAnchor
);
695 mrEscherEx
.AddAtom( 0, ESCHER_ClientData
); // OBJ record
696 mrEscherEx
.UpdateDffFragmentEnd();
700 if( aCtrlProp
.GetProperty( aString
, "Label" ) )
702 /* Be sure to construct the MSODRAWING record containing the
703 ClientTextbox atom after the base OBJ's MSODRAWING record data is
705 pClientTextbox
= new XclExpMsoDrawing( mrEscherEx
);
706 mrEscherEx
.AddAtom( 0, ESCHER_ClientTextbox
); // TXO record
707 mrEscherEx
.UpdateDffFragmentEnd();
709 sal_uInt16 nXclFont
= EXC_FONT_APP
;
710 if( !aString
.isEmpty() )
712 XclFontData aFontData
;
713 GetFontPropSetHelper().ReadFontProperties( aFontData
, aCtrlProp
, EXC_FONTPROPSET_CONTROL
);
714 if( (aFontData
.maName
.Len() > 0) && (aFontData
.mnHeight
> 0) )
715 nXclFont
= GetFontBuffer().Insert( aFontData
, EXC_COLOR_CTRLTEXT
);
718 pTxo
= new XclTxo( aString
, nXclFont
);
719 pTxo
->SetHorAlign( (mnObjType
== EXC_OBJTYPE_BUTTON
) ? EXC_OBJ_HOR_CENTER
: EXC_OBJ_HOR_LEFT
);
720 pTxo
->SetVerAlign( EXC_OBJ_VER_CENTER
);
723 mrEscherEx
.CloseContainer(); // ESCHER_SpContainer
726 aCtrlProp
.GetProperty( mnLineCount
, "LineCount" );
729 sal_Int16 nApiButton
= AwtVisualEffect::LOOK3D
;
730 sal_Int16 nApiBorder
= AwtVisualEffect::LOOK3D
;
733 case FormCompType::LISTBOX
:
734 case FormCompType::COMBOBOX
:
735 aCtrlProp
.GetProperty( nApiBorder
, "Border" );
737 case FormCompType::CHECKBOX
:
738 case FormCompType::RADIOBUTTON
:
739 aCtrlProp
.GetProperty( nApiButton
, "VisualEffect" );
740 nApiBorder
= AwtVisualEffect::NONE
;
742 // Push button cannot be set to flat in Excel
743 case FormCompType::COMMANDBUTTON
:
744 nApiBorder
= AwtVisualEffect::LOOK3D
;
746 // Label does not support a border in Excel
747 case FormCompType::FIXEDTEXT
:
748 nApiBorder
= AwtVisualEffect::NONE
;
750 /* Scroll bar and spin button have a "Border" property, but it is
751 really used for a border, and not for own 3D/flat look (#i34712#). */
752 case FormCompType::SCROLLBAR
:
753 case FormCompType::SPINBUTTON
:
754 nApiButton
= AwtVisualEffect::LOOK3D
;
755 nApiBorder
= AwtVisualEffect::NONE
;
757 // Group box does not support flat style (#i34712#)
758 case FormCompType::GROUPBOX
:
759 nApiBorder
= AwtVisualEffect::LOOK3D
;
762 mbFlatButton
= nApiButton
!= AwtVisualEffect::LOOK3D
;
763 mbFlatBorder
= nApiBorder
!= AwtVisualEffect::LOOK3D
;
766 sal_Int16 nApiState
= 0;
767 if( aCtrlProp
.GetProperty( nApiState
, "State" ) )
771 case 0: mnState
= EXC_OBJ_CHECKBOX_UNCHECKED
; break;
772 case 1: mnState
= EXC_OBJ_CHECKBOX_CHECKED
; break;
773 case 2: mnState
= EXC_OBJ_CHECKBOX_TRISTATE
; break;
777 // special control contents
780 case FormCompType::LISTBOX
:
782 mbMultiSel
= aCtrlProp
.GetBoolProperty( "MultiSelection" );
783 Sequence
< sal_Int16
> aSelection
;
784 if( aCtrlProp
.GetProperty( aSelection
, "SelectedItems" ) )
786 sal_Int32 nLen
= aSelection
.getLength();
789 mnSelEntry
= aSelection
[ 0 ] + 1;
790 maMultiSel
.resize( nLen
);
791 const sal_Int16
* pnBegin
= aSelection
.getConstArray();
792 ::std::copy( pnBegin
, pnBegin
+ nLen
, maMultiSel
.begin() );
796 // convert listbox with dropdown button to Excel dropdown
797 if( aCtrlProp
.GetBoolProperty( "Dropdown" ) )
798 mnObjType
= EXC_OBJTYPE_DROPDOWN
;
802 case FormCompType::COMBOBOX
:
804 Sequence
< OUString
> aStringList
;
806 if( aCtrlProp
.GetProperty( aStringList
, "StringItemList" ) &&
807 aCtrlProp
.GetProperty( aDefText
, "Text" ) &&
808 aStringList
.getLength() && !aDefText
.isEmpty() )
810 const OUString
* pBegin
= aStringList
.getConstArray();
811 const OUString
* pEnd
= pBegin
+ aStringList
.getLength();
812 const OUString
* pString
= ::std::find( pBegin
, pEnd
, aDefText
);
813 if( pString
!= pEnd
)
814 mnSelEntry
= static_cast< sal_Int16
>( pString
- pBegin
+ 1 ); // 1-based
816 maMultiSel
.resize( 1, mnSelEntry
- 1 );
819 // convert combobox without dropdown button to Excel listbox
820 if( !aCtrlProp
.GetBoolProperty( "Dropdown" ) )
821 mnObjType
= EXC_OBJTYPE_LISTBOX
;
825 case FormCompType::SCROLLBAR
:
827 sal_Int32 nApiValue
= 0;
828 if( aCtrlProp
.GetProperty( nApiValue
, "ScrollValueMin" ) )
829 mnScrollMin
= limit_cast
< sal_uInt16
>( nApiValue
, EXC_OBJ_SCROLLBAR_MIN
, EXC_OBJ_SCROLLBAR_MAX
);
830 if( aCtrlProp
.GetProperty( nApiValue
, "ScrollValueMax" ) )
831 mnScrollMax
= limit_cast
< sal_uInt16
>( nApiValue
, mnScrollMin
, EXC_OBJ_SCROLLBAR_MIN
);
832 if( aCtrlProp
.GetProperty( nApiValue
, "ScrollValue" ) )
833 mnScrollValue
= limit_cast
< sal_uInt16
>( nApiValue
, mnScrollMin
, mnScrollMax
);
834 if( aCtrlProp
.GetProperty( nApiValue
, "LineIncrement" ) )
835 mnScrollStep
= limit_cast
< sal_uInt16
>( nApiValue
, EXC_OBJ_SCROLLBAR_MIN
, EXC_OBJ_SCROLLBAR_MAX
);
836 if( aCtrlProp
.GetProperty( nApiValue
, "BlockIncrement" ) )
837 mnScrollPage
= limit_cast
< sal_uInt16
>( nApiValue
, EXC_OBJ_SCROLLBAR_MIN
, EXC_OBJ_SCROLLBAR_MAX
);
838 if( aCtrlProp
.GetProperty( nApiValue
, "Orientation" ) )
839 mbScrollHor
= nApiValue
== AwtScrollOrient::HORIZONTAL
;
843 case FormCompType::SPINBUTTON
:
845 sal_Int32 nApiValue
= 0;
846 if( aCtrlProp
.GetProperty( nApiValue
, "SpinValueMin" ) )
847 mnScrollMin
= limit_cast
< sal_uInt16
>( nApiValue
, EXC_OBJ_SCROLLBAR_MIN
, EXC_OBJ_SCROLLBAR_MAX
);
848 if( aCtrlProp
.GetProperty( nApiValue
, "SpinValueMax" ) )
849 mnScrollMax
= limit_cast
< sal_uInt16
>( nApiValue
, mnScrollMin
, EXC_OBJ_SCROLLBAR_MAX
);
850 if( aCtrlProp
.GetProperty( nApiValue
, "SpinValue" ) )
851 mnScrollValue
= limit_cast
< sal_uInt16
>( nApiValue
, mnScrollMin
, mnScrollMax
);
852 if( aCtrlProp
.GetProperty( nApiValue
, "SpinIncrement" ) )
853 mnScrollStep
= limit_cast
< sal_uInt16
>( nApiValue
, EXC_OBJ_SCROLLBAR_MIN
, EXC_OBJ_SCROLLBAR_MAX
);
854 if( aCtrlProp
.GetProperty( nApiValue
, "Orientation" ) )
855 mbScrollHor
= nApiValue
== AwtScrollOrient::HORIZONTAL
;
861 ConvertSheetLinks( xShape
);
864 bool XclExpTbxControlObj::SetMacroLink( const ScriptEventDescriptor
& rEvent
)
866 return XclMacroHelper::SetMacroLink( rEvent
, meEventType
);
869 void XclExpTbxControlObj::WriteSubRecs( XclExpStream
& rStrm
)
873 // *** Push buttons, labels ***
875 case EXC_OBJTYPE_BUTTON
:
876 case EXC_OBJTYPE_LABEL
:
877 // ftMacro - macro link
878 WriteMacroSubRec( rStrm
);
881 // *** Check boxes, option buttons ***
883 case EXC_OBJTYPE_CHECKBOX
:
884 case EXC_OBJTYPE_OPTIONBUTTON
:
886 // ftCbls - box properties
887 sal_uInt16 nStyle
= 0;
888 ::set_flag( nStyle
, EXC_OBJ_CHECKBOX_FLAT
, mbFlatButton
);
890 rStrm
.StartRecord( EXC_ID_OBJCBLS
, 12 );
892 rStrm
.WriteZeroBytes( 8 );
896 // ftMacro - macro link
897 WriteMacroSubRec( rStrm
);
898 // ftCblsFmla subrecord - cell link
899 WriteCellLinkSubRec( rStrm
, EXC_ID_OBJCBLSFMLA
);
901 // ftCblsData subrecord - box properties, again
902 rStrm
.StartRecord( EXC_ID_OBJCBLS
, 8 );
904 rStrm
.WriteZeroBytes( 4 );
910 // *** List boxes, combo boxes ***
912 case EXC_OBJTYPE_LISTBOX
:
913 case EXC_OBJTYPE_DROPDOWN
:
915 sal_uInt16 nEntryCount
= GetSourceEntryCount();
917 // ftSbs subrecord - Scroll bars
918 sal_Int32 nLineHeight
= XclTools::GetHmmFromTwips( 200 ); // always 10pt
919 if( mnObjType
== EXC_OBJTYPE_LISTBOX
)
920 mnLineCount
= static_cast< sal_uInt16
>( mnHeight
/ nLineHeight
);
923 sal_uInt16 nInvisLines
= (nEntryCount
>= mnLineCount
) ? (nEntryCount
- mnLineCount
) : 0;
924 mnScrollMax
= limit_cast
< sal_uInt16
>( nInvisLines
, EXC_OBJ_SCROLLBAR_MIN
, EXC_OBJ_SCROLLBAR_MAX
);
926 mnScrollPage
= limit_cast
< sal_uInt16
>( mnLineCount
, EXC_OBJ_SCROLLBAR_MIN
, EXC_OBJ_SCROLLBAR_MAX
);
930 // ftMacro - macro link
931 WriteMacroSubRec( rStrm
);
932 // ftSbsFmla subrecord - cell link
933 WriteCellLinkSubRec( rStrm
, EXC_ID_OBJSBSFMLA
);
935 // ftLbsData - source data range and box properties
936 sal_uInt16 nStyle
= 0;
937 ::insert_value( nStyle
, mbMultiSel
? EXC_OBJ_LISTBOX_MULTI
: EXC_OBJ_LISTBOX_SINGLE
, 4, 2 );
938 ::set_flag( nStyle
, EXC_OBJ_LISTBOX_FLAT
, mbFlatBorder
);
940 rStrm
.StartRecord( EXC_ID_OBJLBSDATA
, 0 );
942 if( const XclTokenArray
* pSrcRange
= GetSourceRangeTokArr() )
944 rStrm
<< static_cast< sal_uInt16
>( (pSrcRange
->GetSize() + 7) & 0xFFFE );
945 WriteFormula( rStrm
, *pSrcRange
);
948 rStrm
<< sal_uInt16( 0 );
950 rStrm
<< nEntryCount
<< mnSelEntry
<< nStyle
<< sal_uInt16( 0 );
951 if( mnObjType
== EXC_OBJTYPE_LISTBOX
)
955 ScfUInt8Vec
aSelEx( nEntryCount
, 0 );
956 for( ScfInt16Vec::const_iterator aIt
= maMultiSel
.begin(), aEnd
= maMultiSel
.end(); aIt
!= aEnd
; ++aIt
)
957 if( *aIt
< nEntryCount
)
959 rStrm
.Write( &aSelEx
[ 0 ], aSelEx
.size() );
962 else if( mnObjType
== EXC_OBJTYPE_DROPDOWN
)
964 rStrm
<< sal_uInt16( 0 ) << mnLineCount
<< sal_uInt16( 0 ) << sal_uInt16( 0 );
971 // *** Spin buttons, scrollbars ***
973 case EXC_OBJTYPE_SPIN
:
974 case EXC_OBJTYPE_SCROLLBAR
:
976 // ftSbs subrecord - scroll bars
978 // ftMacro - macro link
979 WriteMacroSubRec( rStrm
);
980 // ftSbsFmla subrecord - cell link
981 WriteCellLinkSubRec( rStrm
, EXC_ID_OBJSBSFMLA
);
985 // *** Group boxes ***
987 case EXC_OBJTYPE_GROUPBOX
:
989 // ftMacro - macro link
990 WriteMacroSubRec( rStrm
);
992 // ftGboData subrecord - group box properties
993 sal_uInt16 nStyle
= 0;
994 ::set_flag( nStyle
, EXC_OBJ_GROUPBOX_FLAT
, mbFlatBorder
);
996 rStrm
.StartRecord( EXC_ID_OBJGBODATA
, 6 );
997 rStrm
<< sal_uInt32( 0 )
1005 void XclExpTbxControlObj::WriteCellLinkSubRec( XclExpStream
& rStrm
, sal_uInt16 nSubRecId
)
1007 if( const XclTokenArray
* pCellLink
= GetCellLinkTokArr() )
1008 WriteFormulaSubRec( rStrm
, nSubRecId
, *pCellLink
);
1011 void XclExpTbxControlObj::WriteSbs( XclExpStream
& rStrm
)
1013 sal_uInt16 nOrient
= 0;
1014 ::set_flag( nOrient
, EXC_OBJ_SCROLLBAR_HOR
, mbScrollHor
);
1015 sal_uInt16 nStyle
= EXC_OBJ_SCROLLBAR_DEFFLAGS
;
1016 ::set_flag( nStyle
, EXC_OBJ_SCROLLBAR_FLAT
, mbFlatButton
);
1018 rStrm
.StartRecord( EXC_ID_OBJSBS
, 20 );
1019 rStrm
<< sal_uInt32( 0 ) // reserved
1020 << mnScrollValue
// thumb position
1021 << mnScrollMin
// thumb min pos
1022 << mnScrollMax
// thumb max pos
1023 << mnScrollStep
// line increment
1024 << mnScrollPage
// page increment
1025 << nOrient
// 0 = vertical, 1 = horizontal
1026 << sal_uInt16( 15 ) // thumb width
1027 << nStyle
; // flags/style
1033 // ----------------------------------------------------------------------------
1035 XclExpChartObj::XclExpChartObj( XclExpObjectManager
& rObjMgr
, Reference
< XShape
> xShape
, const Rectangle
* pChildAnchor
) :
1036 XclObj( rObjMgr
, EXC_OBJTYPE_CHART
),
1037 XclExpRoot( rObjMgr
.GetRoot() ), mxShape( xShape
)
1039 // create the MSODRAWING record contents for the chart object
1040 mrEscherEx
.OpenContainer( ESCHER_SpContainer
);
1041 mrEscherEx
.AddShape( ESCHER_ShpInst_HostControl
, SHAPEFLAG_HAVEANCHOR
| SHAPEFLAG_HAVESPT
);
1042 EscherPropertyContainer aPropOpt
;
1043 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x01040104 );
1044 aPropOpt
.AddOpt( ESCHER_Prop_FitTextToShape
, 0x00080008 );
1045 aPropOpt
.AddOpt( ESCHER_Prop_fillColor
, 0x0800004E );
1046 aPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, 0x0800004D );
1047 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x00110010 );
1048 aPropOpt
.AddOpt( ESCHER_Prop_lineColor
, 0x0800004D );
1049 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x00080008 );
1050 aPropOpt
.AddOpt( ESCHER_Prop_fshadowObscured
, 0x00020000 );
1051 aPropOpt
.AddOpt( ESCHER_Prop_fPrint
, 0x00080000 );
1052 aPropOpt
.Commit( mrEscherEx
.GetStream() );
1055 SdrObject
* pSdrObj
= SdrObject::getSdrObjectFromXShape( xShape
);
1056 ImplWriteAnchor( GetRoot(), pSdrObj
, pChildAnchor
);
1058 // client data (the following OBJ record)
1059 mrEscherEx
.AddAtom( 0, ESCHER_ClientData
);
1060 mrEscherEx
.CloseContainer(); // ESCHER_SpContainer
1061 mrEscherEx
.UpdateDffFragmentEnd();
1063 // load the chart OLE object
1064 if( SdrOle2Obj
* pSdrOleObj
= dynamic_cast< SdrOle2Obj
* >( pSdrObj
) )
1065 svt::EmbeddedObjectRef::TryRunningState( pSdrOleObj
->GetObjRef() );
1067 // create the chart substream object
1068 ScfPropertySet
aShapeProp( xShape
);
1069 Reference
< XModel
> xModel
;
1070 aShapeProp
.GetProperty( xModel
, "Model" );
1071 mxChartDoc
.set( xModel
,UNO_QUERY
);
1072 ::com::sun::star::awt::Rectangle aBoundRect
;
1073 aShapeProp
.GetProperty( aBoundRect
, "BoundRect" );
1074 Rectangle
aChartRect( Point( aBoundRect
.X
, aBoundRect
.Y
), Size( aBoundRect
.Width
, aBoundRect
.Height
) );
1075 mxChart
.reset( new XclExpChart( GetRoot(), xModel
, aChartRect
) );
1078 XclExpChartObj::~XclExpChartObj()
1082 void XclExpChartObj::Save( XclExpStream
& rStrm
)
1084 // content of OBJ record
1085 XclObj::Save( rStrm
);
1087 mxChart
->Save( rStrm
);
1090 void XclExpChartObj::SaveXml( XclExpXmlStream
& rStrm
)
1092 OSL_TRACE("XclExpChartObj::SaveXml -- Entry point to export chart");
1093 sax_fastparser::FSHelperPtr pDrawing
= rStrm
.GetCurrentStream();
1095 // FIXME: two cell? it seems the two cell anchor is incorrect.
1096 pDrawing
->startElement( FSNS( XML_xdr
, XML_twoCellAnchor
), // OOXTODO: oneCellAnchor, absoluteAnchor
1097 XML_editAs
, "oneCell",
1099 Reference
< XPropertySet
> xPropSet( mxShape
, UNO_QUERY
);
1102 XclObjAny::WriteFromTo( rStrm
, mxShape
, GetTab() );
1103 Reference
< XModel
> xModel( mxChartDoc
, UNO_QUERY
);
1104 ChartExport
aChartExport( XML_xdr
, pDrawing
, xModel
, &rStrm
, DrawingML::DOCUMENT_XLSX
);
1105 static sal_Int32 nChartCount
= 0;
1107 aChartExport
.WriteChartObj( mxShape
, nChartCount
);
1108 // TODO: get the correcto chart number
1111 pDrawing
->singleElement( FSNS( XML_xdr
, XML_clientData
),
1112 // OOXTODO: XML_fLocksWithSheet
1113 // OOXTODO: XML_fPrintsWithSheet
1115 pDrawing
->endElement( FSNS( XML_xdr
, XML_twoCellAnchor
) );
1118 void XclExpChartObj::WriteChartObj( sax_fastparser::FSHelperPtr pDrawing
, XclExpXmlStream
& rStrm
)
1120 pDrawing
->startElement( FSNS( XML_xdr
, XML_graphicFrame
), FSEND
);
1122 pDrawing
->startElement( FSNS( XML_xdr
, XML_nvGraphicFramePr
), FSEND
);
1124 // TODO: get the correct chart name chart id
1125 OUString sName
= "Object 1";
1126 Reference
< XNamed
> xNamed( mxShape
, UNO_QUERY
);
1129 sName
= xNamed
->getName();
1131 sal_Int32 nID
= rStrm
.GetUniqueId();
1133 pDrawing
->singleElement( FSNS( XML_xdr
, XML_cNvPr
),
1134 XML_id
, I32S( nID
),
1135 XML_name
, USS( sName
),
1138 pDrawing
->singleElement( FSNS( XML_xdr
, XML_cNvGraphicFramePr
),
1141 pDrawing
->endElement( FSNS( XML_xdr
, XML_nvGraphicFramePr
) );
1143 // visual chart properties
1144 WriteShapeTransformation( pDrawing
, mxShape
);
1146 // writer chart object
1147 pDrawing
->startElement( FSNS( XML_a
, XML_graphic
), FSEND
);
1148 pDrawing
->startElement( FSNS( XML_a
, XML_graphicData
),
1149 XML_uri
, "http://schemas.openxmlformats.org/drawingml/2006/chart",
1153 static sal_Int32 nChartCount
= 0;
1155 sax_fastparser::FSHelperPtr pChart
= rStrm
.CreateOutputStream(
1156 XclXmlUtils::GetStreamName( "xl/", "charts/chart", nChartCount
),
1157 XclXmlUtils::GetStreamName( "../", "charts/chart", nChartCount
),
1158 rStrm
.GetCurrentStream()->getOutputStream(),
1159 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
1160 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
1163 pDrawing
->singleElement( FSNS( XML_c
, XML_chart
),
1164 FSNS( XML_xmlns
, XML_c
), "http://schemas.openxmlformats.org/drawingml/2006/chart",
1165 FSNS( XML_xmlns
, XML_r
), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
1166 FSNS( XML_r
, XML_id
), XclXmlUtils::ToOString( sId
).getStr(),
1169 rStrm
.PushStream( pChart
);
1170 Reference
< XModel
> xModel( mxChartDoc
, UNO_QUERY
);
1171 ChartExport
aChartExport( XML_xdr
, pChart
, xModel
, &rStrm
, DrawingML::DOCUMENT_XLSX
);
1172 aChartExport
.ExportContent();
1176 pDrawing
->endElement( FSNS( XML_a
, XML_graphicData
) );
1177 pDrawing
->endElement( FSNS( XML_a
, XML_graphic
) );
1178 pDrawing
->endElement( FSNS( XML_xdr
, XML_graphicFrame
) );
1182 void XclExpChartObj::WriteShapeTransformation( sax_fastparser::FSHelperPtr pFS
, const XShapeRef
& rXShape
, sal_Bool bFlipH
, sal_Bool bFlipV
, sal_Int32 nRotation
)
1184 ::com::sun::star::awt::Point aPos
= rXShape
->getPosition();
1185 ::com::sun::star::awt::Size aSize
= rXShape
->getSize();
1187 pFS
->startElementNS( XML_xdr
, XML_xfrm
,
1188 XML_flipH
, bFlipH
? "1" : NULL
,
1189 XML_flipV
, bFlipV
? "1" : NULL
,
1190 XML_rot
, nRotation
? I32S( nRotation
) : NULL
,
1193 pFS
->singleElementNS( XML_a
, XML_off
, XML_x
, IS( MM100toEMU( aPos
.X
) ), XML_y
, IS( MM100toEMU( aPos
.Y
) ), FSEND
);
1194 pFS
->singleElementNS( XML_a
, XML_ext
, XML_cx
, IS( MM100toEMU( aSize
.Width
) ), XML_cy
, IS( MM100toEMU( aSize
.Height
) ), FSEND
);
1196 pFS
->endElementNS( XML_xdr
, XML_xfrm
);
1199 // ============================================================================
1201 XclExpNote::XclExpNote( const XclExpRoot
& rRoot
, const ScAddress
& rScPos
,
1202 const ScPostIt
* pScNote
, const String
& rAddText
) :
1203 XclExpRecord( EXC_ID_NOTE
),
1205 mnObjId( EXC_OBJ_INVALID_ID
),
1206 mbVisible( pScNote
&& pScNote
->IsCaptionShown() )
1208 // get the main note text
1212 aNoteText
= pScNote
->GetText();
1213 const EditTextObject
*pEditObj
= pScNote
->GetEditTextObject();
1215 mpNoteContents
= XclExpStringHelper::CreateString( rRoot
, *pEditObj
);
1217 // append additional text
1218 aNoteText
= ScGlobal::addToken( aNoteText
, rAddText
, '\n', 2 );
1219 maOrigNoteText
= aNoteText
;
1221 // initialize record dependent on BIFF type
1222 switch( rRoot
.GetBiff() )
1225 maNoteText
= OUStringToOString(aNoteText
, rRoot
.GetTextEncoding());
1230 // TODO: additional text
1232 if( SdrCaptionObj
* pCaption
= pScNote
->GetOrCreateCaption( maScPos
) )
1234 lcl_GetFromTo( rRoot
, pCaption
->GetLogicRect(), maScPos
.Tab(), maCommentFrom
, maCommentTo
);
1235 if( const OutlinerParaObject
* pOPO
= pCaption
->GetOutlinerParaObject() )
1236 mnObjId
= rRoot
.GetObjectManager().AddObj( new XclObjComment( rRoot
.GetObjectManager(), pCaption
->GetLogicRect(), pOPO
->GetTextObject(), pCaption
, mbVisible
, maScPos
, maCommentFrom
, maCommentTo
) );
1238 SfxItemSet aItemSet
= pCaption
->GetMergedItemSet();
1239 meTVA
= pCaption
->GetTextVerticalAdjust();
1240 meTHA
= pCaption
->GetTextHorizontalAdjust();
1241 mbAutoScale
= pCaption
->GetFitToSize()?true:false;
1242 mbLocked
= pCaption
->IsMoveProtect() | pCaption
->IsResizeProtect();
1244 // AutoFill style would change if Postit.cxx object creation values are changed
1245 OUString
aCol(((XFillColorItem
&)GETITEM(aItemSet
, XFillColorItem
, XATTR_FILLCOLOR
)).GetValue());
1246 mbAutoFill
= aCol
.isEmpty() && (GETITEMVALUE(aItemSet
, XFillStyleItem
, XATTR_FILLSTYLE
, sal_uLong
) == XFILL_SOLID
);
1248 mbRowHidden
= (rRoot
.GetDoc().RowHidden(maScPos
.Row(),maScPos
.Tab()));
1249 mbColHidden
= (rRoot
.GetDoc().ColHidden(maScPos
.Col(),maScPos
.Tab()));
1252 SetRecSize( 9 + maAuthor
.GetSize() );
1256 default: DBG_ERROR_BIFF();
1260 void XclExpNote::Save( XclExpStream
& rStrm
)
1262 switch( rStrm
.GetRoot().GetBiff() )
1266 // write the NOTE record directly, there may be the need to create more than one
1267 const sal_Char
* pcBuffer
= maNoteText
.getStr();
1268 sal_uInt16 nCharsLeft
= static_cast< sal_uInt16
>( maNoteText
.getLength() );
1272 sal_uInt16 nWriteChars
= ::std::min( nCharsLeft
, EXC_NOTE5_MAXLEN
);
1274 rStrm
.StartRecord( EXC_ID_NOTE
, 6 + nWriteChars
);
1275 if( pcBuffer
== maNoteText
.getStr() )
1277 // first record: row, col, length of complete text
1278 rStrm
<< static_cast< sal_uInt16
>( maScPos
.Row() )
1279 << static_cast< sal_uInt16
>( maScPos
.Col() )
1280 << nCharsLeft
; // still contains full length
1284 // next records: -1, 0, length of current text segment
1285 rStrm
<< sal_uInt16( 0xFFFF )
1289 rStrm
.Write( pcBuffer
, nWriteChars
);
1292 pcBuffer
+= nWriteChars
;
1293 nCharsLeft
= nCharsLeft
- nWriteChars
;
1299 if( mnObjId
!= EXC_OBJ_INVALID_ID
)
1300 XclExpRecord::Save( rStrm
);
1303 default: DBG_ERROR_BIFF();
1307 void XclExpNote::WriteBody( XclExpStream
& rStrm
)
1309 // BIFF5/BIFF7 is written separately
1310 OSL_ENSURE_BIFF( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
);
1312 sal_uInt16 nFlags
= 0;
1313 ::set_flag( nFlags
, EXC_NOTE_VISIBLE
, mbVisible
);
1315 rStrm
<< static_cast< sal_uInt16
>( maScPos
.Row() )
1316 << static_cast< sal_uInt16
>( maScPos
.Col() )
1323 void XclExpNote::WriteXml( sal_Int32 nAuthorId
, XclExpXmlStream
& rStrm
)
1325 sax_fastparser::FSHelperPtr rComments
= rStrm
.GetCurrentStream();
1327 rComments
->startElement( XML_comment
,
1328 XML_ref
, XclXmlUtils::ToOString( maScPos
).getStr(),
1329 XML_authorId
, OString::valueOf( nAuthorId
).getStr(),
1330 // OOXTODO: XML_guid,
1332 rComments
->startElement( XML_text
, FSEND
);
1333 // OOXTODO: phoneticPr, rPh, r
1334 if( mpNoteContents
)
1335 mpNoteContents
->WriteXml( rStrm
);
1336 rComments
->endElement( XML_text
);
1339 Export of commentPr is disabled, since the current (Oct 2010)
1340 version of MSO 2010 doesn't yet support commentPr
1342 #if 1//def XLSX_OOXML_FUTURE
1343 if( rStrm
.getVersion() == oox::core::ISOIEC_29500_2008
)
1345 rComments
->startElement( FSNS( XML_mc
, XML_AlternateContent
), FSEND
);
1346 rComments
->startElement( FSNS( XML_mc
, XML_Choice
), XML_Requires
, "v2", FSEND
);
1347 rComments
->startElement( XML_commentPr
,
1348 XML_autoFill
, XclXmlUtils::ToPsz( mbAutoFill
),
1349 XML_autoScale
, XclXmlUtils::ToPsz( mbAutoScale
),
1350 XML_colHidden
, XclXmlUtils::ToPsz( mbColHidden
),
1351 XML_locked
, XclXmlUtils::ToPsz( mbLocked
),
1352 XML_rowHidden
, XclXmlUtils::ToPsz( mbRowHidden
),
1353 XML_textHAlign
, ToHorizAlign( meTHA
),
1354 XML_textVAlign
, ToVertAlign( meTVA
) ,
1356 rComments
->startElement( XML_anchor
,
1357 XML_moveWithCells
, "false",
1358 XML_sizeWithCells
, "false",
1360 rComments
->startElement( FSNS( XML_xdr
, XML_from
), FSEND
);
1361 lcl_WriteAnchorVertex( rComments
, maCommentFrom
);
1362 rComments
->endElement( FSNS( XML_xdr
, XML_from
) );
1363 rComments
->startElement( FSNS( XML_xdr
, XML_to
), FSEND
);
1364 lcl_WriteAnchorVertex( rComments
, maCommentTo
);
1365 rComments
->endElement( FSNS( XML_xdr
, XML_to
) );
1366 rComments
->endElement( XML_anchor
);
1367 rComments
->endElement( XML_commentPr
);
1369 rComments
->endElement( FSNS( XML_mc
, XML_Choice
) );
1370 rComments
->startElement( FSNS( XML_mc
, XML_Fallback
), FSEND
);
1371 // Any fallback code ?
1372 rComments
->endElement( FSNS( XML_mc
, XML_Fallback
) );
1373 rComments
->endElement( FSNS( XML_mc
, XML_AlternateContent
) );
1376 rComments
->endElement( XML_comment
);
1379 // ============================================================================
1381 XclMacroHelper::XclMacroHelper( const XclExpRoot
& rRoot
) :
1382 XclExpControlHelper( rRoot
)
1386 XclMacroHelper::~XclMacroHelper()
1390 void XclMacroHelper::WriteMacroSubRec( XclExpStream
& rStrm
)
1393 WriteFormulaSubRec( rStrm
, EXC_ID_OBJMACRO
, *mxMacroLink
);
1397 XclMacroHelper::SetMacroLink( const ScriptEventDescriptor
& rEvent
, const XclTbxEventType
& nEventType
)
1399 String aMacroName
= XclControlHelper::ExtractFromMacroDescriptor( rEvent
, nEventType
, GetDocShell() );
1400 if( aMacroName
.Len() )
1402 return SetMacroLink( aMacroName
);
1408 XclMacroHelper::SetMacroLink( const String
& rMacroName
)
1410 OSL_TRACE("SetMacroLink( macroname:=%s )", OUStringToOString( rMacroName
, RTL_TEXTENCODING_UTF8
).getStr() );
1411 if( rMacroName
.Len() )
1413 sal_uInt16 nExtSheet
= GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC
);
1414 sal_uInt16 nNameIdx
= GetNameManager().InsertMacroCall( rMacroName
, true, false );
1415 mxMacroLink
= GetFormulaCompiler().CreateNameXFormula( nExtSheet
, nNameIdx
);
1421 XclExpShapeObj::XclExpShapeObj( XclExpObjectManager
& rRoot
, ::com::sun::star::uno::Reference
< ::com::sun::star::drawing::XShape
> xShape
) :
1422 XclObjAny( rRoot
, xShape
),
1423 XclMacroHelper( rRoot
)
1425 if( SdrObject
* pSdrObj
= ::GetSdrObjectFromXShape( xShape
) )
1427 ScMacroInfo
* pInfo
= ScDrawLayer::GetMacroInfo( pSdrObj
);
1428 if ( pInfo
&& !pInfo
->GetMacro().isEmpty() )
1429 // 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
1430 // SetMacroLink( XclControlHelper::GetXclMacroName( pInfo->GetMacro(), rRoot.GetDocShell() ) );
1431 SetMacroLink( XclTools::GetXclMacroName( pInfo
->GetMacro() ) );
1435 XclExpShapeObj::~XclExpShapeObj()
1439 void XclExpShapeObj::WriteSubRecs( XclExpStream
& rStrm
)
1441 XclObjAny::WriteSubRecs( rStrm
);
1442 WriteMacroSubRec( rStrm
);
1445 // ============================================================================
1447 XclExpComments::XclExpComments( SCTAB nTab
, XclExpRecordList
< XclExpNote
>& rNotes
)
1448 : mnTab( nTab
), mrNotes( rNotes
)
1452 struct OUStringLess
: public std::binary_function
<OUString
, OUString
, bool>
1454 bool operator()(const OUString
& x
, const OUString
& y
) const
1456 return x
.compareTo( y
) < 0;
1460 void XclExpComments::SaveXml( XclExpXmlStream
& rStrm
)
1462 if( mrNotes
.IsEmpty() )
1465 sax_fastparser::FSHelperPtr rComments
= rStrm
.CreateOutputStream(
1466 XclXmlUtils::GetStreamName( "xl/", "comments", mnTab
+ 1 ),
1467 XclXmlUtils::GetStreamName( "../", "comments", mnTab
+ 1 ),
1468 rStrm
.GetCurrentStream()->getOutputStream(),
1469 "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
1470 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" );
1471 rStrm
.PushStream( rComments
);
1473 if( rStrm
.getVersion() == oox::core::ISOIEC_29500_2008
)
1474 rComments
->startElement( XML_comments
,
1475 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
1476 FSNS( XML_xmlns
, XML_mc
), "http://schemas.openxmlformats.org/markup-compatibility/2006",
1477 FSNS( XML_xmlns
, XML_xdr
), "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
1478 FSNS( XML_xmlns
, XML_v2
), "http://schemas.openxmlformats.org/spreadsheetml/2006/main/v2",
1479 FSNS( XML_mc
, XML_Ignorable
), "v2",
1482 rComments
->startElement( XML_comments
,
1483 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
1484 FSNS( XML_xmlns
, XML_xdr
), "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
1487 rComments
->startElement( XML_authors
, FSEND
);
1489 typedef std::set
< OUString
, OUStringLess
> Authors
;
1492 size_t nNotes
= mrNotes
.GetSize();
1493 for( size_t i
= 0; i
< nNotes
; ++i
)
1495 aAuthors
.insert( XclXmlUtils::ToOUString( mrNotes
.GetRecord( i
)->GetAuthor() ) );
1498 for( Authors::const_iterator b
= aAuthors
.begin(), e
= aAuthors
.end(); b
!= e
; ++b
)
1500 rComments
->startElement( XML_author
, FSEND
);
1501 rComments
->writeEscaped( *b
);
1502 rComments
->endElement( XML_author
);
1505 rComments
->endElement( XML_authors
);
1506 rComments
->startElement( XML_commentList
, FSEND
);
1508 for( size_t i
= 0; i
< nNotes
; ++i
)
1510 XclExpNoteList::RecordRefType xNote
= mrNotes
.GetRecord( i
);
1511 Authors::iterator aAuthor
= aAuthors
.find(
1512 XclXmlUtils::ToOUString( xNote
->GetAuthor() ) );
1513 sal_Int32 nAuthorId
= distance( aAuthors
.begin(), aAuthor
);
1514 xNote
->WriteXml( nAuthorId
, rStrm
);
1517 rComments
->endElement( XML_commentList
);
1518 rComments
->endElement( XML_comments
);
1523 // object manager =============================================================
1525 XclExpObjectManager::XclExpObjectManager( const XclExpRoot
& rRoot
) :
1529 mxEscherEx
.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm
) );
1532 XclExpObjectManager::XclExpObjectManager( const XclExpObjectManager
& rParent
) :
1533 XclExpRoot( rParent
.GetRoot() )
1535 InitStream( false );
1536 mxEscherEx
.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm
, rParent
.mxEscherEx
.get() ) );
1539 XclExpObjectManager::~XclExpObjectManager()
1543 XclExpDffAnchorBase
* XclExpObjectManager::CreateDffAnchor() const
1545 return new XclExpDffSheetAnchor( GetRoot() );
1548 boost::shared_ptr
< XclExpRecordBase
> XclExpObjectManager::CreateDrawingGroup()
1550 return boost::shared_ptr
< XclExpRecordBase
>( new XclExpMsoDrawingGroup( *mxEscherEx
) );
1553 void XclExpObjectManager::StartSheet()
1555 mxObjList
.reset( new XclExpObjList( GetRoot(), *mxEscherEx
) );
1558 boost::shared_ptr
< XclExpRecordBase
> XclExpObjectManager::ProcessDrawing( SdrPage
* pSdrPage
)
1561 mxEscherEx
->AddSdrPage( *pSdrPage
);
1562 // the first dummy object may still be open
1563 OSL_ENSURE( mxEscherEx
->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1564 while( mxEscherEx
->GetGroupLevel() )
1565 mxEscherEx
->LeaveGroup();
1566 mxObjList
->EndSheet();
1570 boost::shared_ptr
< XclExpRecordBase
> XclExpObjectManager::ProcessDrawing( const Reference
< XShapes
>& rxShapes
)
1573 mxEscherEx
->AddUnoShapes( rxShapes
);
1574 // the first dummy object may still be open
1575 OSL_ENSURE( mxEscherEx
->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
1576 while( mxEscherEx
->GetGroupLevel() )
1577 mxEscherEx
->LeaveGroup();
1578 mxObjList
->EndSheet();
1582 void XclExpObjectManager::EndDocument()
1584 mxEscherEx
->EndDocument();
1587 XclExpMsoDrawing
* XclExpObjectManager::GetMsodrawingPerSheet()
1589 return mxObjList
->GetMsodrawingPerSheet();
1592 bool XclExpObjectManager::HasObj() const
1594 return !mxObjList
->empty();
1597 sal_uInt16
XclExpObjectManager::AddObj( XclObj
* pObjRec
)
1599 return mxObjList
->Add( pObjRec
);
1602 XclObj
* XclExpObjectManager::RemoveLastObj()
1604 XclObj
* pLastObj
= mxObjList
->back();
1605 mxObjList
->pop_back();
1609 void XclExpObjectManager::InitStream( bool bTempFile
)
1613 mxTempFile
.reset( new ::utl::TempFile
);
1614 if( mxTempFile
->IsValid() )
1616 mxTempFile
->EnableKillingFile();
1617 mxDffStrm
.reset( ::utl::UcbStreamHelper::CreateStream( mxTempFile
->GetURL(), STREAM_STD_READWRITE
) );
1621 if( !mxDffStrm
.get() )
1622 mxDffStrm
.reset( new SvMemoryStream
);
1624 mxDffStrm
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
1627 // ----------------------------------------------------------------------------
1629 XclExpEmbeddedObjectManager::XclExpEmbeddedObjectManager(
1630 const XclExpObjectManager
& rParent
, const Size
& rPageSize
, sal_Int32 nScaleX
, sal_Int32 nScaleY
) :
1631 XclExpObjectManager( rParent
),
1632 maPageSize( rPageSize
),
1633 mnScaleX( nScaleX
),
1638 XclExpDffAnchorBase
* XclExpEmbeddedObjectManager::CreateDffAnchor() const
1640 return new XclExpDffEmbeddedAnchor( GetRoot(), maPageSize
, mnScaleX
, mnScaleY
);
1643 // ============================================================================
1645 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */