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