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