xref: /trunk/main/oox/source/xls/drawingfragment.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/xls/drawingfragment.hxx"
29 
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/container/XNameReplace.hpp>
32 #include <com/sun/star/document/XEventsSupplier.hpp>
33 #include <com/sun/star/drawing/XControlShape.hpp>
34 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
35 #include <com/sun/star/script/XEventAttacherManager.hpp>
36 #include <rtl/strbuf.hxx>
37 #include "oox/drawingml/connectorshapecontext.hxx"
38 #include "oox/drawingml/graphicshapecontext.hxx"
39 #include "oox/helper/attributelist.hxx"
40 #include "oox/helper/propertyset.hxx"
41 #include "oox/vml/vmlshape.hxx"
42 #include "oox/vml/vmlshapecontainer.hxx"
43 #include "oox/xls/formulaparser.hxx"
44 #include "oox/xls/stylesbuffer.hxx"
45 #include "oox/xls/themebuffer.hxx"
46 #include "oox/xls/unitconverter.hxx"
47 
48 namespace oox {
49 namespace xls {
50 
51 // ============================================================================
52 
53 using namespace ::com::sun::star::awt;
54 using namespace ::com::sun::star::beans;
55 using namespace ::com::sun::star::container;
56 using namespace ::com::sun::star::document;
57 using namespace ::com::sun::star::drawing;
58 using namespace ::com::sun::star::script;
59 using namespace ::com::sun::star::table;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::xml::sax;
62 using namespace ::oox::core;
63 using namespace ::oox::drawingml;
64 using namespace ::oox::ole;
65 
66 using ::rtl::OStringBuffer;
67 using ::rtl::OUString;
68 using ::rtl::OUStringToOString;
69 // no using's for ::oox::vml, that may clash with ::oox::drawingml types
70 
71 // ============================================================================
72 // DrawingML
73 // ============================================================================
74 
75 ShapeMacroAttacher::ShapeMacroAttacher( const OUString& rMacroName, const Reference< XShape >& rxShape ) :
76     VbaMacroAttacherBase( rMacroName ),
77     mxShape( rxShape )
78 {
79 }
80 
81 void ShapeMacroAttacher::attachMacro( const OUString& rMacroUrl )
82 {
83     try
84     {
85         Reference< XEventsSupplier > xSupplier( mxShape, UNO_QUERY_THROW );
86         Reference< XNameReplace > xEvents( xSupplier->getEvents(), UNO_SET_THROW );
87         Sequence< PropertyValue > aEventProps( 2 );
88         aEventProps[ 0 ].Name = CREATE_OUSTRING( "EventType" );
89         aEventProps[ 0 ].Value <<= CREATE_OUSTRING( "Script" );
90         aEventProps[ 1 ].Name = CREATE_OUSTRING( "Script" );
91         aEventProps[ 1 ].Value <<= rMacroUrl;
92         xEvents->replaceByName( CREATE_OUSTRING( "OnClick" ), Any( aEventProps ) );
93     }
94     catch( Exception& )
95     {
96     }
97 }
98 
99 // ============================================================================
100 
101 Shape::Shape( const WorksheetHelper& rHelper, const AttributeList& rAttribs, const sal_Char* pcServiceName ) :
102     ::oox::drawingml::Shape( pcServiceName ),
103     WorksheetHelper( rHelper )
104 {
105     OUString aMacro = rAttribs.getXString( XML_macro, OUString() );
106     if( aMacro.getLength() > 0 )
107         maMacroName = getFormulaParser().importMacroName( aMacro );
108 }
109 
110 void Shape::finalizeXShape( XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes )
111 {
112     if( (maMacroName.getLength() > 0) && mxShape.is() )
113     {
114         VbaMacroAttacherRef xAttacher( new ShapeMacroAttacher( maMacroName, mxShape ) );
115         getBaseFilter().getVbaProject().registerMacroAttacher( xAttacher );
116     }
117     ::oox::drawingml::Shape::finalizeXShape( rFilter, rxShapes );
118 }
119 
120 // ============================================================================
121 
122 GroupShapeContext::GroupShapeContext( ContextHandler& rParent,
123         const WorksheetHelper& rHelper, const ShapePtr& rxParentShape, const ShapePtr& rxShape ) :
124     ShapeGroupContext( rParent, rxParentShape, rxShape ),
125     WorksheetHelper( rHelper )
126 {
127 }
128 
129 /*static*/ ContextHandlerRef GroupShapeContext::createShapeContext( ContextHandler& rParent,
130         const WorksheetHelper& rHelper, sal_Int32 nElement, const AttributeList& rAttribs,
131         const ShapePtr& rxParentShape, ShapePtr* pxShape )
132 {
133     switch( nElement )
134     {
135         case XDR_TOKEN( sp ):
136         {
137             ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.CustomShape" ) );
138             if( pxShape ) *pxShape = xShape;
139             return new ShapeContext( rParent, rxParentShape, xShape );
140         }
141         case XDR_TOKEN( cxnSp ):
142         {
143             ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.ConnectorShape" ) );
144             if( pxShape ) *pxShape = xShape;
145             return new ConnectorShapeContext( rParent, rxParentShape, xShape );
146         }
147         case XDR_TOKEN( pic ):
148         {
149             ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.GraphicObjectShape" ) );
150             if( pxShape ) *pxShape = xShape;
151             return new GraphicShapeContext( rParent, rxParentShape, xShape );
152         }
153         case XDR_TOKEN( graphicFrame ):
154         {
155             ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.GraphicObjectShape" ) );
156             if( pxShape ) *pxShape = xShape;
157             return new GraphicalObjectFrameContext( rParent, rxParentShape, xShape, rHelper.getSheetType() != SHEETTYPE_CHARTSHEET );
158         }
159         case XDR_TOKEN( grpSp ):
160         {
161             ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.GroupShape" ) );
162             if( pxShape ) *pxShape = xShape;
163             return new GroupShapeContext( rParent, rHelper, rxParentShape, xShape );
164         }
165     }
166     return 0;
167 }
168 
169 Reference< XFastContextHandler > SAL_CALL GroupShapeContext::createFastChildContext(
170         sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs ) throw (SAXException, RuntimeException)
171 {
172     ContextHandlerRef xContext = createShapeContext( *this, *this, nElement, AttributeList( rxAttribs ), mpGroupShapePtr );
173     return xContext.get() ? xContext.get() : ShapeGroupContext::createFastChildContext( nElement, rxAttribs );
174 }
175 
176 // ============================================================================
177 
178 DrawingFragment::DrawingFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
179     WorksheetFragmentBase( rHelper, rFragmentPath ),
180     mxDrawPage( rHelper.getDrawPage(), UNO_QUERY )
181 {
182     OSL_ENSURE( mxDrawPage.is(), "DrawingFragment::DrawingFragment - missing drawing page" );
183 }
184 
185 ContextHandlerRef DrawingFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
186 {
187     switch( getCurrentElement() )
188     {
189         case XML_ROOT_CONTEXT:
190             if( nElement == XDR_TOKEN( wsDr ) ) return this;
191         break;
192 
193         case XDR_TOKEN( wsDr ):
194             switch( nElement )
195             {
196                 case XDR_TOKEN( absoluteAnchor ):
197                 case XDR_TOKEN( oneCellAnchor ):
198                 case XDR_TOKEN( twoCellAnchor ):
199                     mxAnchor.reset( new ShapeAnchor( *this ) );
200                     mxAnchor->importAnchor( nElement, rAttribs );
201                     return this;
202             }
203         break;
204 
205         case XDR_TOKEN( absoluteAnchor ):
206         case XDR_TOKEN( oneCellAnchor ):
207         case XDR_TOKEN( twoCellAnchor ):
208         {
209             switch( nElement )
210             {
211                 case XDR_TOKEN( from ):
212                 case XDR_TOKEN( to ):           return this;
213 
214                 case XDR_TOKEN( pos ):          if( mxAnchor.get() ) mxAnchor->importPos( rAttribs );           break;
215                 case XDR_TOKEN( ext ):          if( mxAnchor.get() ) mxAnchor->importExt( rAttribs );           break;
216                 case XDR_TOKEN( clientData ):   if( mxAnchor.get() ) mxAnchor->importClientData( rAttribs );    break;
217 
218                 default:                        return GroupShapeContext::createShapeContext( *this, *this, nElement, rAttribs, ShapePtr(), &mxShape );
219             }
220         }
221         break;
222 
223         case XDR_TOKEN( from ):
224         case XDR_TOKEN( to ):
225             switch( nElement )
226             {
227                 case XDR_TOKEN( col ):
228                 case XDR_TOKEN( row ):
229                 case XDR_TOKEN( colOff ):
230                 case XDR_TOKEN( rowOff ):       return this;    // collect index in onCharacters()
231             }
232         break;
233     }
234     return 0;
235 }
236 
237 void DrawingFragment::onCharacters( const OUString& rChars )
238 {
239     switch( getCurrentElement() )
240     {
241         case XDR_TOKEN( col ):
242         case XDR_TOKEN( row ):
243         case XDR_TOKEN( colOff ):
244         case XDR_TOKEN( rowOff ):
245             if( mxAnchor.get() ) mxAnchor->setCellPos( getCurrentElement(), getParentElement(), rChars );
246         break;
247     }
248 }
249 
250 void DrawingFragment::onEndElement()
251 {
252     switch( getCurrentElement() )
253     {
254         case XDR_TOKEN( absoluteAnchor ):
255         case XDR_TOKEN( oneCellAnchor ):
256         case XDR_TOKEN( twoCellAnchor ):
257             if( mxDrawPage.is() && mxShape.get() && mxAnchor.get() )
258             {
259                 EmuRectangle aShapeRectEmu = mxAnchor->calcAnchorRectEmu( getDrawPageSize() );
260                 if( (aShapeRectEmu.X >= 0) && (aShapeRectEmu.Y >= 0) && (aShapeRectEmu.Width >= 0) && (aShapeRectEmu.Height >= 0) )
261                 {
262                     // TODO: DrawingML implementation expects 32-bit coordinates for EMU rectangles (change that to EmuRectangle)
263                     Rectangle aShapeRectEmu32(
264                         getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.X, 0, SAL_MAX_INT32 ),
265                         getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Y, 0, SAL_MAX_INT32 ),
266                         getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Width, 0, SAL_MAX_INT32 ),
267                         getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Height, 0, SAL_MAX_INT32 ) );
268                     mxShape->addShape( getOoxFilter(), &getTheme(), mxDrawPage, &aShapeRectEmu32 );
269                     /*  Collect all shape positions in the WorksheetHelper base
270                         class. But first, scale EMUs to 1/100 mm. */
271                     Rectangle aShapeRectHmm(
272                         convertEmuToHmm( aShapeRectEmu.X ), convertEmuToHmm( aShapeRectEmu.Y ),
273                         convertEmuToHmm( aShapeRectEmu.Width ), convertEmuToHmm( aShapeRectEmu.Height ) );
274                     extendShapeBoundingBox( aShapeRectHmm );
275                 }
276             }
277             mxShape.reset();
278             mxAnchor.reset();
279         break;
280     }
281 }
282 
283 // ============================================================================
284 // VML
285 // ============================================================================
286 
287 namespace {
288 
289 class VmlFindNoteFunc
290 {
291 public:
292     explicit            VmlFindNoteFunc( const CellAddress& rPos );
293     bool                operator()( const ::oox::vml::ShapeBase& rShape ) const;
294 
295 private:
296     sal_Int32           mnCol;
297     sal_Int32           mnRow;
298 };
299 
300 // ----------------------------------------------------------------------------
301 
302 VmlFindNoteFunc::VmlFindNoteFunc( const CellAddress& rPos ) :
303     mnCol( rPos.Column ),
304     mnRow( rPos.Row )
305 {
306 }
307 
308 bool VmlFindNoteFunc::operator()( const ::oox::vml::ShapeBase& rShape ) const
309 {
310     const ::oox::vml::ClientData* pClientData = rShape.getClientData();
311     return pClientData && (pClientData->mnCol == mnCol) && (pClientData->mnRow == mnRow);
312 }
313 
314 } // namespace
315 
316 // ============================================================================
317 
318 VmlControlMacroAttacher::VmlControlMacroAttacher( const OUString& rMacroName,
319         const Reference< XIndexContainer >& rxCtrlFormIC, sal_Int32 nCtrlIndex, sal_Int32 nCtrlType, sal_Int32 nDropStyle ) :
320     VbaMacroAttacherBase( rMacroName ),
321     mxCtrlFormIC( rxCtrlFormIC ),
322     mnCtrlIndex( nCtrlIndex ),
323     mnCtrlType( nCtrlType ),
324     mnDropStyle( nDropStyle )
325 {
326 }
327 
328 void VmlControlMacroAttacher::attachMacro( const OUString& rMacroUrl )
329 {
330     ScriptEventDescriptor aEventDesc;
331     aEventDesc.ScriptType = CREATE_OUSTRING( "Script" );
332     aEventDesc.ScriptCode = rMacroUrl;
333 
334     // editable drop downs are treated like edit boxes
335     bool bEditDropDown = (mnCtrlType == XML_Drop) && (mnDropStyle == XML_ComboEdit);
336     sal_Int32 nCtrlType = bEditDropDown ? XML_Edit : mnCtrlType;
337 
338     switch( nCtrlType )
339     {
340         case XML_Button:
341         case XML_Checkbox:
342         case XML_Radio:
343             aEventDesc.ListenerType = CREATE_OUSTRING( "XActionListener" );
344             aEventDesc.EventMethod = CREATE_OUSTRING( "actionPerformed" );
345         break;
346         case XML_Label:
347         case XML_GBox:
348         case XML_Dialog:
349             aEventDesc.ListenerType = CREATE_OUSTRING( "XMouseListener" );
350             aEventDesc.EventMethod = CREATE_OUSTRING( "mouseReleased" );
351         break;
352         case XML_Edit:
353             aEventDesc.ListenerType = CREATE_OUSTRING( "XTextListener" );
354             aEventDesc.EventMethod = CREATE_OUSTRING( "textChanged" );
355         break;
356         case XML_Spin:
357         case XML_Scroll:
358             aEventDesc.ListenerType = CREATE_OUSTRING( "XAdjustmentListener" );
359             aEventDesc.EventMethod = CREATE_OUSTRING( "adjustmentValueChanged" );
360         break;
361         case XML_List:
362         case XML_Drop:
363             aEventDesc.ListenerType = CREATE_OUSTRING( "XChangeListener" );
364             aEventDesc.EventMethod = CREATE_OUSTRING( "changed" );
365         break;
366         default:
367             OSL_ENSURE( false, "VmlControlMacroAttacher::attachMacro - unexpected object type" );
368             return;
369     }
370 
371     try
372     {
373         Reference< XEventAttacherManager > xEventMgr( mxCtrlFormIC, UNO_QUERY_THROW );
374         xEventMgr->registerScriptEvent( mnCtrlIndex, aEventDesc );
375     }
376     catch( Exception& )
377     {
378     }
379 }
380 
381 // ============================================================================
382 
383 VmlDrawing::VmlDrawing( const WorksheetHelper& rHelper ) :
384     ::oox::vml::Drawing( rHelper.getOoxFilter(), rHelper.getDrawPage(), ::oox::vml::VMLDRAWING_EXCEL ),
385     WorksheetHelper( rHelper ),
386     maControlConv( rHelper.getBaseFilter().getModel(), rHelper.getBaseFilter().getGraphicHelper() )
387 {
388     // default font for legacy listboxes and dropdowns: Tahoma, 8pt
389     maListBoxFont.moName = CREATE_OUSTRING( "Tahoma" );
390     maListBoxFont.moColor = CREATE_OUSTRING( "auto" );
391     maListBoxFont.monSize = 160;
392 }
393 
394 const ::oox::vml::ShapeBase* VmlDrawing::getNoteShape( const CellAddress& rPos ) const
395 {
396     return getShapes().findShape( VmlFindNoteFunc( rPos ) );
397 }
398 
399 bool VmlDrawing::isShapeSupported( const ::oox::vml::ShapeBase& rShape ) const
400 {
401     const ::oox::vml::ClientData* pClientData = rShape.getClientData();
402     return !pClientData || (pClientData->mnObjType != XML_Note);
403 }
404 
405 OUString VmlDrawing::getShapeBaseName( const ::oox::vml::ShapeBase& rShape ) const
406 {
407     if( const ::oox::vml::ClientData* pClientData = rShape.getClientData() )
408     {
409         switch( pClientData->mnObjType )
410         {
411             case XML_Button:    return CREATE_OUSTRING( "Button" );
412             case XML_Checkbox:  return CREATE_OUSTRING( "Check Box" );
413             case XML_Dialog:    return CREATE_OUSTRING( "Dialog Frame" );
414             case XML_Drop:      return CREATE_OUSTRING( "Drop Down" );
415             case XML_Edit:      return CREATE_OUSTRING( "Edit Box" );
416             case XML_GBox:      return CREATE_OUSTRING( "Group Box" );
417             case XML_Label:     return CREATE_OUSTRING( "Label" );
418             case XML_List:      return CREATE_OUSTRING( "List Box" );
419             case XML_Note:      return CREATE_OUSTRING( "Comment" );
420             case XML_Pict:      return (pClientData->mbDde || getOleObjectInfo( rShape.getShapeId() )) ? CREATE_OUSTRING( "Object" ) : CREATE_OUSTRING( "Picture" );
421             case XML_Radio:     return CREATE_OUSTRING( "Option Button" );
422             case XML_Scroll:    return CREATE_OUSTRING( "Scroll Bar" );
423             case XML_Spin:      return CREATE_OUSTRING( "Spinner" );
424         }
425     }
426     return ::oox::vml::Drawing::getShapeBaseName( rShape );
427 }
428 
429 bool VmlDrawing::convertClientAnchor( Rectangle& orShapeRect, const OUString& rShapeAnchor ) const
430 {
431     if( rShapeAnchor.getLength() == 0 )
432         return false;
433     ShapeAnchor aAnchor( *this );
434     aAnchor.importVmlAnchor( rShapeAnchor );
435     orShapeRect = aAnchor.calcAnchorRectHmm( getDrawPageSize() );
436     return (orShapeRect.Width >= 0) && (orShapeRect.Height >= 0);
437 }
438 
439 Reference< XShape > VmlDrawing::createAndInsertClientXShape( const ::oox::vml::ShapeBase& rShape,
440         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
441 {
442     // simulate the legacy drawing controls with OLE form controls
443     OUString aShapeName = rShape.getShapeName();
444     const ::oox::vml::ClientData* pClientData = rShape.getClientData();
445     if( (aShapeName.getLength() > 0) && pClientData )
446     {
447         Rectangle aShapeRect = rShapeRect;
448         const ::oox::vml::TextBox* pTextBox = rShape.getTextBox();
449         EmbeddedControl aControl( aShapeName );
450         switch( pClientData->mnObjType )
451         {
452             case XML_Button:
453             {
454                 AxCommandButtonModel& rAxModel = aControl.createModel< AxCommandButtonModel >();
455                 convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
456                 rAxModel.mnFlags = AX_FLAGS_ENABLED | AX_FLAGS_OPAQUE | AX_FLAGS_WORDWRAP;
457                 rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
458             }
459             break;
460 
461             case XML_Label:
462             {
463                 AxLabelModel& rAxModel = aControl.createModel< AxLabelModel >();
464                 convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
465                 rAxModel.mnFlags = AX_FLAGS_ENABLED | AX_FLAGS_WORDWRAP;
466                 rAxModel.mnBorderStyle = AX_BORDERSTYLE_NONE;
467                 rAxModel.mnSpecialEffect = AX_SPECIALEFFECT_FLAT;
468                 rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
469             }
470             break;
471 
472             case XML_Edit:
473             {
474                 bool bNumeric = (pClientData->mnVTEdit == ::oox::vml::VML_CLIENTDATA_INTEGER) || (pClientData->mnVTEdit == ::oox::vml::VML_CLIENTDATA_NUMBER);
475                 AxMorphDataModelBase& rAxModel = bNumeric ?
476                     static_cast< AxMorphDataModelBase& >( aControl.createModel< AxNumericFieldModel >() ) :
477                     static_cast< AxMorphDataModelBase& >( aControl.createModel< AxTextBoxModel >() );
478                 convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maValue, pTextBox, pClientData->mnTextHAlign );
479                 setFlag( rAxModel.mnFlags, AX_FLAGS_MULTILINE, pClientData->mbMultiLine );
480                 setFlag( rAxModel.mnScrollBars, AX_SCROLLBAR_VERTICAL, pClientData->mbVScroll );
481                 if( pClientData->mbSecretEdit )
482                     rAxModel.mnPasswordChar = '*';
483             }
484             break;
485 
486             case XML_GBox:
487             {
488                 AxFrameModel& rAxModel = aControl.createModel< AxFrameModel >();
489                 convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
490                 rAxModel.mnBorderStyle = pClientData->mbNo3D ? AX_BORDERSTYLE_SINGLE : AX_BORDERSTYLE_NONE;
491                 rAxModel.mnSpecialEffect = pClientData->mbNo3D ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_BUMPED;
492 
493                 /*  Move top border of groupbox up by half font height, because
494                     Excel specifies Y position of the groupbox border line
495                     instead the top border of the caption text. */
496                 if( const ::oox::vml::TextFontModel* pFontModel = pTextBox ? pTextBox->getFirstFont() : 0 )
497                 {
498                     sal_Int32 nFontHeightHmm = getUnitConverter().scaleToMm100( pFontModel->monSize.get( 160 ), UNIT_TWIP );
499                     sal_Int32 nYDiff = ::std::min< sal_Int32 >( nFontHeightHmm / 2, aShapeRect.Y );
500                     aShapeRect.Y -= nYDiff;
501                     aShapeRect.Height += nYDiff;
502                 }
503             }
504             break;
505 
506             case XML_Checkbox:
507             {
508                 AxCheckBoxModel& rAxModel = aControl.createModel< AxCheckBoxModel >();
509                 convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
510                 convertControlBackground( rAxModel, rShape );
511                 rAxModel.maValue = OUString::valueOf( pClientData->mnChecked );
512                 rAxModel.mnSpecialEffect = pClientData->mbNo3D ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
513                 rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
514                 bool bTriState = (pClientData->mnChecked != ::oox::vml::VML_CLIENTDATA_UNCHECKED) && (pClientData->mnChecked != ::oox::vml::VML_CLIENTDATA_CHECKED);
515                 rAxModel.mnMultiSelect = bTriState ? AX_SELCTION_MULTI : AX_SELCTION_SINGLE;
516             }
517             break;
518 
519             case XML_Radio:
520             {
521                 AxOptionButtonModel& rAxModel = aControl.createModel< AxOptionButtonModel >();
522                 convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
523                 convertControlBackground( rAxModel, rShape );
524                 rAxModel.maValue = OUString::valueOf( pClientData->mnChecked );
525                 rAxModel.mnSpecialEffect = pClientData->mbNo3D ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
526                 rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
527             }
528             break;
529 
530             case XML_List:
531             {
532                 AxListBoxModel& rAxModel = aControl.createModel< AxListBoxModel >();
533                 convertControlFontData( rAxModel.maFontData, rAxModel.mnTextColor, maListBoxFont );
534                 rAxModel.mnBorderStyle = pClientData->mbNo3D2 ? AX_BORDERSTYLE_SINGLE : AX_BORDERSTYLE_NONE;
535                 rAxModel.mnSpecialEffect = pClientData->mbNo3D2 ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
536                 switch( pClientData->mnSelType )
537                 {
538                     case XML_Single:    rAxModel.mnMultiSelect = AX_SELCTION_SINGLE;    break;
539                     case XML_Multi:     rAxModel.mnMultiSelect = AX_SELCTION_MULTI;     break;
540                     case XML_Extend:    rAxModel.mnMultiSelect = AX_SELCTION_EXTENDED;  break;
541                 }
542             }
543             break;
544 
545             case XML_Drop:
546             {
547                 AxComboBoxModel& rAxModel = aControl.createModel< AxComboBoxModel >();
548                 convertControlFontData( rAxModel.maFontData, rAxModel.mnTextColor, maListBoxFont );
549                 rAxModel.mnDisplayStyle = AX_DISPLAYSTYLE_DROPDOWN;
550                 rAxModel.mnShowDropButton = AX_SHOWDROPBUTTON_ALWAYS;
551                 rAxModel.mnBorderStyle = pClientData->mbNo3D2 ? AX_BORDERSTYLE_SINGLE : AX_BORDERSTYLE_NONE;
552                 rAxModel.mnSpecialEffect = pClientData->mbNo3D2 ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
553                 rAxModel.mnListRows = pClientData->mnDropLines;
554             }
555             break;
556 
557             case XML_Spin:
558             {
559                 AxSpinButtonModel& rAxModel = aControl.createModel< AxSpinButtonModel >();
560                 rAxModel.mnMin = pClientData->mnMin;
561                 rAxModel.mnMax = pClientData->mnMax;
562                 rAxModel.mnPosition = pClientData->mnVal;
563                 rAxModel.mnSmallChange = pClientData->mnInc;
564             }
565             break;
566 
567             case XML_Scroll:
568             {
569                 AxScrollBarModel& rAxModel = aControl.createModel< AxScrollBarModel >();
570                 rAxModel.mnMin = pClientData->mnMin;
571                 rAxModel.mnMax = pClientData->mnMax;
572                 rAxModel.mnPosition = pClientData->mnVal;
573                 rAxModel.mnSmallChange = pClientData->mnInc;
574                 rAxModel.mnLargeChange = pClientData->mnPage;
575             }
576             break;
577 
578             case XML_Dialog:
579             {
580                 // fake with a group box
581                 AxFrameModel& rAxModel = aControl.createModel< AxFrameModel >();
582                 convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, XML_Left );
583                 rAxModel.mnBorderStyle = AX_BORDERSTYLE_SINGLE;
584                 rAxModel.mnSpecialEffect = AX_SPECIALEFFECT_FLAT;
585             }
586             break;
587         }
588 
589         if( ControlModelBase* pAxModel = aControl.getModel() )
590         {
591             // create the control shape
592             pAxModel->maSize.first = aShapeRect.Width;
593             pAxModel->maSize.second = aShapeRect.Height;
594             sal_Int32 nCtrlIndex = -1;
595             Reference< XShape > xShape = createAndInsertXControlShape( aControl, rxShapes, aShapeRect, nCtrlIndex );
596 
597             // control shape macro
598             if( xShape.is() && (nCtrlIndex >= 0) && (pClientData->maFmlaMacro.getLength() > 0) )
599             {
600                 OUString aMacroName = getFormulaParser().importMacroName( pClientData->maFmlaMacro );
601                 if( aMacroName.getLength() > 0 )
602                 {
603                     Reference< XIndexContainer > xFormIC = getControlForm().getXForm();
604                     VbaMacroAttacherRef xAttacher( new VmlControlMacroAttacher( aMacroName, xFormIC, nCtrlIndex, pClientData->mnObjType, pClientData->mnDropStyle ) );
605                     getBaseFilter().getVbaProject().registerMacroAttacher( xAttacher );
606                 }
607             }
608 
609             return xShape;
610         }
611     }
612 
613     return Reference< XShape >();
614 }
615 
616 void VmlDrawing::notifyXShapeInserted( const Reference< XShape >& rxShape,
617         const Rectangle& rShapeRect, const ::oox::vml::ShapeBase& rShape, bool bGroupChild )
618 {
619     // collect all shape positions in the WorksheetHelper base class (but not children of group shapes)
620     if( !bGroupChild )
621         extendShapeBoundingBox( rShapeRect );
622 
623     // convert settings from VML client data
624     if( const ::oox::vml::ClientData* pClientData = rShape.getClientData() )
625     {
626         // specific settings for embedded form controls
627         try
628         {
629             Reference< XControlShape > xCtrlShape( rxShape, UNO_QUERY_THROW );
630             Reference< XControlModel > xCtrlModel( xCtrlShape->getControl(), UNO_SET_THROW );
631             PropertySet aPropSet( xCtrlModel );
632 
633             // printable
634             aPropSet.setProperty( PROP_Printable, pClientData->mbPrintObject );
635 
636             // control source links
637             if( (pClientData->maFmlaLink.getLength() > 0) || (pClientData->maFmlaRange.getLength() > 0) )
638                 maControlConv.bindToSources( xCtrlModel, pClientData->maFmlaLink, pClientData->maFmlaRange, getSheetIndex() );
639         }
640         catch( Exception& )
641         {
642         }
643     }
644 }
645 
646 // private --------------------------------------------------------------------
647 
648 sal_uInt32 VmlDrawing::convertControlTextColor( const OUString& rTextColor ) const
649 {
650     // color attribute not present or 'auto' - use passed default color
651     if( (rTextColor.getLength() == 0) || rTextColor.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "auto" ) ) )
652         return AX_SYSCOLOR_WINDOWTEXT;
653 
654     if( rTextColor[ 0 ] == '#' )
655     {
656         // RGB colors in the format '#RRGGBB'
657         if( rTextColor.getLength() == 7 )
658             return OleHelper::encodeOleColor( rTextColor.copy( 1 ).toInt32( 16 ) );
659 
660         // RGB colors in the format '#RGB'
661         if( rTextColor.getLength() == 4 )
662         {
663             sal_Int32 nR = rTextColor.copy( 1, 1 ).toInt32( 16 ) * 0x11;
664             sal_Int32 nG = rTextColor.copy( 2, 1 ).toInt32( 16 ) * 0x11;
665             sal_Int32 nB = rTextColor.copy( 3, 1 ).toInt32( 16 ) * 0x11;
666             return OleHelper::encodeOleColor( (nR << 16) | (nG << 8) | nB );
667         }
668 
669         OSL_ENSURE( false, OStringBuffer( "VmlDrawing::convertControlTextColor - invalid color name '" ).
670             append( OUStringToOString( rTextColor, RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() );
671         return AX_SYSCOLOR_WINDOWTEXT;
672     }
673 
674     const GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
675 
676     /*  Predefined color names or system color names (resolve to RGB to detect
677         valid color name). */
678     sal_Int32 nColorToken = AttributeConversion::decodeToken( rTextColor );
679     sal_Int32 nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT );
680     if( nRgbValue == API_RGB_TRANSPARENT )
681         nRgbValue = rGraphicHelper.getSystemColor( nColorToken, API_RGB_TRANSPARENT );
682     if( nRgbValue != API_RGB_TRANSPARENT )
683         return OleHelper::encodeOleColor( nRgbValue );
684 
685     // try palette color
686     return OleHelper::encodeOleColor( rGraphicHelper.getPaletteColor( rTextColor.toInt32() ) );
687 }
688 
689 void VmlDrawing::convertControlFontData( AxFontData& rAxFontData, sal_uInt32& rnOleTextColor, const ::oox::vml::TextFontModel& rFontModel ) const
690 {
691     if( rFontModel.moName.has() )
692         rAxFontData.maFontName = rFontModel.moName.get();
693 
694     // font height: convert from twips to points, then to internal representation of AX controls
695     rAxFontData.setHeightPoints( static_cast< sal_Int16 >( (rFontModel.monSize.get( 200 ) + 10) / 20 ) );
696 
697     // font effects
698     rAxFontData.mnFontEffects = 0;
699     setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_BOLD, rFontModel.mobBold.get( false ) );
700     setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_ITALIC, rFontModel.mobItalic.get( false ) );
701     setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_STRIKEOUT, rFontModel.mobStrikeout.get( false ) );
702     sal_Int32 nUnderline = rFontModel.monUnderline.get( XML_none );
703     setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_UNDERLINE, nUnderline != XML_none );
704     rAxFontData.mbDblUnderline = nUnderline == XML_double;
705 
706     // font color
707     rnOleTextColor = convertControlTextColor( rFontModel.moColor.get( OUString() ) );
708 }
709 
710 void VmlDrawing::convertControlText( AxFontData& rAxFontData, sal_uInt32& rnOleTextColor,
711         OUString& rCaption, const ::oox::vml::TextBox* pTextBox, sal_Int32 nTextHAlign ) const
712 {
713     if( pTextBox )
714     {
715         rCaption = pTextBox->getText();
716         if( const ::oox::vml::TextFontModel* pFontModel = pTextBox->getFirstFont() )
717             convertControlFontData( rAxFontData, rnOleTextColor, *pFontModel );
718     }
719 
720     switch( nTextHAlign )
721     {
722         case XML_Left:      rAxFontData.mnHorAlign = AX_FONTDATA_LEFT;      break;
723         case XML_Center:    rAxFontData.mnHorAlign = AX_FONTDATA_CENTER;    break;
724         case XML_Right:     rAxFontData.mnHorAlign = AX_FONTDATA_RIGHT;     break;
725         default:            rAxFontData.mnHorAlign = AX_FONTDATA_LEFT;
726     }
727 }
728 
729 void VmlDrawing::convertControlBackground( AxMorphDataModelBase& rAxModel, const ::oox::vml::ShapeBase& rShape ) const
730 {
731     const ::oox::vml::FillModel& rFillModel = rShape.getTypeModel().maFillModel;
732     bool bHasFill = rFillModel.moFilled.get( true );
733     setFlag( rAxModel.mnFlags, AX_FLAGS_OPAQUE, bHasFill );
734     if( bHasFill )
735     {
736         const GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
737         sal_Int32 nSysWindowColor = rGraphicHelper.getSystemColor( XML_window, API_RGB_WHITE );
738         ::oox::drawingml::Color aColor = ::oox::vml::ConversionHelper::decodeColor( rGraphicHelper, rFillModel.moColor, rFillModel.moOpacity, nSysWindowColor );
739         sal_Int32 nRgbValue = aColor.getColor( rGraphicHelper );
740         rAxModel.mnBackColor = OleHelper::encodeOleColor( nRgbValue );
741     }
742 }
743 
744 // ============================================================================
745 
746 VmlDrawingFragment::VmlDrawingFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
747     ::oox::vml::DrawingFragment( rHelper.getOoxFilter(), rFragmentPath, rHelper.getVmlDrawing() ),
748     WorksheetHelper( rHelper )
749 {
750 }
751 
752 void VmlDrawingFragment::finalizeImport()
753 {
754     ::oox::vml::DrawingFragment::finalizeImport();
755     getVmlDrawing().convertAndInsert();
756 }
757 
758 // ============================================================================
759 
760 } // namespace xls
761 } // namespace oox
762