1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <drawingfragment.hxx>
22 #include <basegfx/matrix/b2dhommatrix.hxx>
23 #include <com/sun/star/beans/PropertyValue.hpp>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/container/XIndexContainer.hpp>
26 #include <com/sun/star/container/XNameReplace.hpp>
27 #include <com/sun/star/document/XEventsSupplier.hpp>
28 #include <com/sun/star/drawing/XControlShape.hpp>
29 #include <com/sun/star/drawing/XDrawPage.hpp>
30 #include <com/sun/star/drawing/XShapes.hpp>
31 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
32 #include <com/sun/star/script/XEventAttacherManager.hpp>
33 #include <rtl/strbuf.hxx>
34 #include <svx/svdobj.hxx>
35 #include <drwlayer.hxx>
36 #include <userdat.hxx>
37 #include <oox/core/filterbase.hxx>
38 #include <oox/drawingml/connectorshapecontext.hxx>
39 #include <oox/drawingml/graphicshapecontext.hxx>
40 #include <oox/helper/attributelist.hxx>
41 #include <oox/helper/propertyset.hxx>
42 #include <oox/token/namespaces.hxx>
43 #include <oox/token/properties.hxx>
44 #include <oox/token/tokens.hxx>
45 #include <oox/vml/vmlshape.hxx>
46 #include <oox/vml/vmlshapecontainer.hxx>
47 #include <formulaparser.hxx>
48 #include <stylesbuffer.hxx>
49 #include <themebuffer.hxx>
50 #include <unitconverter.hxx>
51 #include <worksheetbuffer.hxx>
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::uno
;
60 using namespace ::oox::core
;
61 using namespace ::oox::drawingml
;
62 using namespace ::oox::ole
;
64 using ::com::sun::star::awt::Size
;
65 using ::com::sun::star::awt::Point
;
66 using ::com::sun::star::awt::Rectangle
;
67 using ::com::sun::star::awt::XControlModel
;
68 // no using's for ::oox::vml, that may clash with ::oox::drawingml types
70 ShapeMacroAttacher::ShapeMacroAttacher( const OUString
& rMacroName
, const Reference
< XShape
>& rxShape
) :
71 VbaMacroAttacherBase( rMacroName
),
76 void ShapeMacroAttacher::attachMacro( const OUString
& rMacroUrl
)
80 Reference
< XEventsSupplier
> xSupplier( mxShape
, UNO_QUERY_THROW
);
81 Reference
< XNameReplace
> xEvents( xSupplier
->getEvents(), UNO_SET_THROW
);
82 Sequence
< PropertyValue
> aEventProps( 2 );
83 aEventProps
[ 0 ].Name
= "EventType";
84 aEventProps
[ 0 ].Value
<<= OUString( "Script" );
85 aEventProps
[ 1 ].Name
= "Script";
86 aEventProps
[ 1 ].Value
<<= rMacroUrl
;
87 xEvents
->replaceByName( "OnClick", Any( aEventProps
) );
94 Shape::Shape( const WorksheetHelper
& rHelper
, const AttributeList
& rAttribs
, const char* pcServiceName
) :
95 ::oox::drawingml::Shape( pcServiceName
),
96 WorksheetHelper( rHelper
)
98 OUString aMacro
= rAttribs
.getXString( XML_macro
, OUString() );
99 if( !aMacro
.isEmpty() )
100 maMacroName
= getFormulaParser().importMacroName( aMacro
);
103 void Shape::finalizeXShape( XmlFilterBase
& rFilter
, const Reference
< XShapes
>& rxShapes
)
106 getShapeProperties().getProperty( PROP_URL
) >>= sURL
;
107 getWorksheets().convertSheetNameRef( sURL
);
108 if( !maMacroName
.isEmpty() && mxShape
.is() )
110 VbaMacroAttacherRef xAttacher
= std::make_shared
<ShapeMacroAttacher
>( maMacroName
, mxShape
);
111 getBaseFilter().getVbaProject().registerMacroAttacher( xAttacher
);
113 ::oox::drawingml::Shape::finalizeXShape( rFilter
, rxShapes
);
114 if ( !sURL
.isEmpty() )
116 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape( mxShape
);
119 if ( ScMacroInfo
* pInfo
= ScDrawLayer::GetMacroInfo( pObj
, true ) )
120 pInfo
->SetHlink( sURL
);
125 GroupShapeContext::GroupShapeContext( const FragmentHandler2
& rParent
,
126 const WorksheetHelper
& rHelper
, const ShapePtr
& rxParentShape
, const ShapePtr
& rxShape
) :
127 ShapeGroupContext( rParent
, rxParentShape
, rxShape
),
128 WorksheetHelper( rHelper
)
132 /*static*/ ContextHandlerRef
GroupShapeContext::createShapeContext( FragmentHandler2
& rParent
,
133 const WorksheetHelper
& rHelper
, sal_Int32 nElement
, const AttributeList
& rAttribs
,
134 const ShapePtr
& rxParentShape
, ShapePtr
* pxShape
)
138 case XDR_TOKEN( sp
):
140 ShapePtr xShape
= std::make_shared
<Shape
>( rHelper
, rAttribs
, "com.sun.star.drawing.CustomShape" );
141 if( pxShape
) *pxShape
= xShape
;
142 return new ShapeContext( rParent
, rxParentShape
, xShape
);
144 case XDR_TOKEN( cxnSp
):
146 ShapePtr xShape
= std::make_shared
<Shape
>( rHelper
, rAttribs
, "com.sun.star.drawing.ConnectorShape" );
147 if( pxShape
) *pxShape
= xShape
;
148 return new ConnectorShapeContext( rParent
, rxParentShape
, xShape
);
150 case XDR_TOKEN( pic
):
152 ShapePtr xShape
= std::make_shared
<Shape
>( rHelper
, rAttribs
, "com.sun.star.drawing.GraphicObjectShape" );
153 if( pxShape
) *pxShape
= xShape
;
154 return new GraphicShapeContext( rParent
, rxParentShape
, xShape
);
156 case XDR_TOKEN( graphicFrame
):
158 ShapePtr xShape
= std::make_shared
<Shape
>( rHelper
, rAttribs
, "com.sun.star.drawing.GraphicObjectShape" );
159 if( pxShape
) *pxShape
= xShape
;
160 return new GraphicalObjectFrameContext( rParent
, rxParentShape
, xShape
, rHelper
.getSheetType() != WorksheetType::Chart
);
162 case XDR_TOKEN( grpSp
):
164 ShapePtr xShape
= std::make_shared
<Shape
>( rHelper
, rAttribs
, "com.sun.star.drawing.GroupShape" );
165 if( pxShape
) *pxShape
= xShape
;
166 return new GroupShapeContext( rParent
, rHelper
, rxParentShape
, xShape
);
172 ContextHandlerRef
GroupShapeContext::onCreateContext(
173 sal_Int32 nElement
, const AttributeList
& rAttribs
)
175 ContextHandlerRef xContext
= createShapeContext( *this, *this, nElement
, rAttribs
, mpGroupShapePtr
);
176 return xContext
? xContext
: ShapeGroupContext::onCreateContext( nElement
, rAttribs
);
179 DrawingFragment::DrawingFragment( const WorksheetHelper
& rHelper
, const OUString
& rFragmentPath
) :
180 WorksheetFragmentBase( rHelper
, rFragmentPath
),
181 mxDrawPage( rHelper
.getDrawPage() )
183 OSL_ENSURE( mxDrawPage
.is(), "DrawingFragment::DrawingFragment - missing drawing page" );
186 ContextHandlerRef
DrawingFragment::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
188 switch( getCurrentElement() )
190 case XML_ROOT_CONTEXT
:
191 if( nElement
== XDR_TOKEN( wsDr
) ) return this;
194 case XDR_TOKEN( wsDr
):
197 case XDR_TOKEN( absoluteAnchor
):
198 case XDR_TOKEN( oneCellAnchor
):
199 case XDR_TOKEN( twoCellAnchor
):
200 mxAnchor
.reset( new ShapeAnchor( *this ) );
201 mxAnchor
->importAnchor( nElement
, rAttribs
);
206 case XDR_TOKEN( absoluteAnchor
):
207 case XDR_TOKEN( oneCellAnchor
):
208 case XDR_TOKEN( twoCellAnchor
):
212 case XDR_TOKEN( from
):
213 case XDR_TOKEN( to
): return this;
215 case XDR_TOKEN( pos
): if( mxAnchor
) mxAnchor
->importPos( rAttribs
); break;
216 case XDR_TOKEN( ext
): if( mxAnchor
) mxAnchor
->importExt( rAttribs
); break;
217 case XDR_TOKEN( clientData
): if( mxAnchor
) mxAnchor
->importClientData( rAttribs
); break;
219 default: return GroupShapeContext::createShapeContext( *this, *this, nElement
, rAttribs
, ShapePtr(), &mxShape
);
224 case XDR_TOKEN( from
):
225 case XDR_TOKEN( to
):
228 case XDR_TOKEN( col
):
229 case XDR_TOKEN( row
):
230 case XDR_TOKEN( colOff
):
231 case XDR_TOKEN( rowOff
): return this; // collect index in onCharacters()
238 void DrawingFragment::onCharacters( const OUString
& rChars
)
240 switch( getCurrentElement() )
242 case XDR_TOKEN( col
):
243 case XDR_TOKEN( row
):
244 case XDR_TOKEN( colOff
):
245 case XDR_TOKEN( rowOff
):
246 if( mxAnchor
) mxAnchor
->setCellPos( getCurrentElement(), getParentElement(), rChars
);
251 void DrawingFragment::onEndElement()
253 switch( getCurrentElement() )
255 case XDR_TOKEN( absoluteAnchor
):
256 case XDR_TOKEN( oneCellAnchor
):
257 case XDR_TOKEN( twoCellAnchor
):
258 if( mxDrawPage
.is() && mxShape
&& mxAnchor
)
260 EmuRectangle aShapeRectEmu
= mxAnchor
->calcAnchorRectEmu( getDrawPageSize() );
261 const bool bIsShapeVisible
= mxAnchor
->isAnchorValid();
262 if( (aShapeRectEmu
.X
>= 0) && (aShapeRectEmu
.Y
>= 0) && (aShapeRectEmu
.Width
>= 0) && (aShapeRectEmu
.Height
>= 0) )
264 const sal_Int32 aRotation
= mxShape
->getRotation();
265 if ((aRotation
>= 45 * PER_DEGREE
&& aRotation
< 135 * PER_DEGREE
)
266 || (aRotation
>= 225 * PER_DEGREE
&& aRotation
< 315 * PER_DEGREE
))
268 // When rotating any shape in MSO Excel within the range of degrees given above,
269 // Excel changes the cells in which the shape is anchored. The new position of
270 // the anchors are always calculated using a 90 degrees rotation anticlockwise.
271 // There is an important result of this operation: the top left point of the shape changes,
272 // it will be another vertex.
273 // The anchor position is given in the xml file, it is in the xdr:from and xdr:to elements.
274 // Let's see what happens in time order:
275 // We create a shape in Excel, the anchor position is in a given cell, then the rotation happens
276 // as mentioned above, and excel recalculates the cells in which the anchors are positioned.
277 // This new cell is exported into the xml elements xdr:from and xdr:to, when Excel exports the document!
278 // Thus, if we have a 90 degrees rotation and an already rotated point from which we base
279 // our calculations here in LO, the result is an incorrect 180 degrees rotation.
280 // Now, we need to create the bounding rectangle of the shape with this in mind.
281 // (Important to mention that at this point we don't talk about rotations at all, this bounding
282 // rectangle contains the original not-rotated shape. Rotation happens later in the code.)
283 // We get the new (x, y) coords, then swap width with height.
284 // To get the new coords we reflect the rectangle in the line y = x. (This will return the
285 // correct vertex, which is the actual top left one.)
286 // Another fact that appears to be true in Excel is that there are only 2 of possible anchor
287 // positions for a shape that is only rotated (and not resized for example).
288 // The first position happens in the set of degrees {[45, 135) U [225, 315)} and the second
289 // set is all the other angles. The two sets partition the circle (of all rotations: 360 degrees).
290 sal_Int64 nHalfWidth
= aShapeRectEmu
.Width
/ 2;
291 sal_Int64 nHalfHeight
= aShapeRectEmu
.Height
/ 2;
292 aShapeRectEmu
.X
= aShapeRectEmu
.X
+ nHalfWidth
- nHalfHeight
;
293 aShapeRectEmu
.Y
= aShapeRectEmu
.Y
+ nHalfHeight
- nHalfWidth
;
294 std::swap(aShapeRectEmu
.Width
, aShapeRectEmu
.Height
);
297 // TODO: DrawingML implementation expects 32-bit coordinates for EMU rectangles (change that to EmuRectangle)
298 // tdf#135918: Negative X,Y position has to be allowed to avoid shape displacement on rotation.
299 // The negative values can exist because of previous lines where the anchor rectangle must be mirrored in some ranges.
300 Rectangle
aShapeRectEmu32(
301 getLimitedValue
< sal_Int32
, sal_Int64
>( aShapeRectEmu
.X
, SAL_MIN_INT32
, SAL_MAX_INT32
),
302 getLimitedValue
< sal_Int32
, sal_Int64
>( aShapeRectEmu
.Y
, SAL_MIN_INT32
, SAL_MAX_INT32
),
303 getLimitedValue
< sal_Int32
, sal_Int64
>( aShapeRectEmu
.Width
, 0, SAL_MAX_INT32
),
304 getLimitedValue
< sal_Int32
, sal_Int64
>( aShapeRectEmu
.Height
, 0, SAL_MAX_INT32
) );
306 // Make sure to set the position and size *before* calling addShape().
307 mxShape
->setPosition(Point(aShapeRectEmu32
.X
, aShapeRectEmu32
.Y
));
308 mxShape
->setSize(Size(aShapeRectEmu32
.Width
, aShapeRectEmu32
.Height
));
310 basegfx::B2DHomMatrix aTransformation
;
311 if ( !bIsShapeVisible
)
312 mxShape
->setHidden(true);
314 mxShape
->addShape( getOoxFilter(), &getTheme(), mxDrawPage
, aTransformation
, mxShape
->getFillProperties() );
316 /* Collect all shape positions in the WorksheetHelper base
317 class. But first, scale EMUs to 1/100 mm. */
318 Rectangle
aShapeRectHmm(
319 convertEmuToHmm(aShapeRectEmu32
.X
> 0 ? aShapeRectEmu32
.X
: 0), convertEmuToHmm(aShapeRectEmu32
.Y
> 0 ? aShapeRectEmu32
.Y
: 0),
320 convertEmuToHmm(aShapeRectEmu32
.Width
), convertEmuToHmm(aShapeRectEmu32
.Height
) );
321 extendShapeBoundingBox( aShapeRectHmm
);
322 // set cell Anchoring
323 if ( mxAnchor
->getEditAs() != ShapeAnchor::ANCHOR_ABSOLUTE
)
325 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape( mxShape
->getXShape() );
328 bool bResizeWithCell
= mxAnchor
->getEditAs() == ShapeAnchor::ANCHOR_TWOCELL
;
329 ScDrawLayer::SetCellAnchoredFromPosition( *pObj
, getScDocument(), getSheetIndex(), bResizeWithCell
);
344 class VmlFindNoteFunc
347 explicit VmlFindNoteFunc( const ScAddress
& rPos
);
348 bool operator()( const ::oox::vml::ShapeBase
& rShape
) const;
355 VmlFindNoteFunc::VmlFindNoteFunc( const ScAddress
& rPos
) :
361 bool VmlFindNoteFunc::operator()( const ::oox::vml::ShapeBase
& rShape
) const
363 const ::oox::vml::ClientData
* pClientData
= rShape
.getClientData();
364 return pClientData
&& (pClientData
->mnCol
== mnCol
) && (pClientData
->mnRow
== mnRow
);
369 VmlControlMacroAttacher::VmlControlMacroAttacher( const OUString
& rMacroName
,
370 const Reference
< XIndexContainer
>& rxCtrlFormIC
, sal_Int32 nCtrlIndex
, sal_Int32 nCtrlType
, sal_Int32 nDropStyle
) :
371 VbaMacroAttacherBase( rMacroName
),
372 mxCtrlFormIC( rxCtrlFormIC
),
373 mnCtrlIndex( nCtrlIndex
),
374 mnCtrlType( nCtrlType
),
375 mnDropStyle( nDropStyle
)
379 void VmlControlMacroAttacher::attachMacro( const OUString
& rMacroUrl
)
381 ScriptEventDescriptor aEventDesc
;
382 aEventDesc
.ScriptType
= "Script";
383 aEventDesc
.ScriptCode
= rMacroUrl
;
385 // editable drop downs are treated like edit boxes
386 bool bEditDropDown
= (mnCtrlType
== XML_Drop
) && (mnDropStyle
== XML_ComboEdit
);
387 sal_Int32 nCtrlType
= bEditDropDown
? XML_Edit
: mnCtrlType
;
394 aEventDesc
.ListenerType
= "XActionListener";
395 aEventDesc
.EventMethod
= "actionPerformed";
400 aEventDesc
.ListenerType
= "XMouseListener";
401 aEventDesc
.EventMethod
= "mouseReleased";
404 aEventDesc
.ListenerType
= "XTextListener";
405 aEventDesc
.EventMethod
= "textChanged";
409 aEventDesc
.ListenerType
= "XAdjustmentListener";
410 aEventDesc
.EventMethod
= "adjustmentValueChanged";
414 aEventDesc
.ListenerType
= "XChangeListener";
415 aEventDesc
.EventMethod
= "changed";
418 OSL_ENSURE( false, "VmlControlMacroAttacher::attachMacro - unexpected object type" );
424 Reference
< XEventAttacherManager
> xEventMgr( mxCtrlFormIC
, UNO_QUERY_THROW
);
425 xEventMgr
->registerScriptEvent( mnCtrlIndex
, aEventDesc
);
432 VmlDrawing::VmlDrawing( const WorksheetHelper
& rHelper
) :
433 ::oox::vml::Drawing( rHelper
.getOoxFilter(), rHelper
.getDrawPage(), ::oox::vml::VMLDRAWING_EXCEL
),
434 WorksheetHelper( rHelper
),
435 maControlConv( rHelper
.getBaseFilter().getModel(), rHelper
.getBaseFilter().getGraphicHelper() )
437 // default font for legacy listboxes and dropdowns: Tahoma, 8pt
438 maListBoxFont
.moName
= "Tahoma";
439 maListBoxFont
.moColor
= "auto";
440 maListBoxFont
.monSize
= 160;
443 const ::oox::vml::ShapeBase
* VmlDrawing::getNoteShape( const ScAddress
& rPos
) const
445 return getShapes().findShape( VmlFindNoteFunc( rPos
) );
448 bool VmlDrawing::isShapeSupported( const ::oox::vml::ShapeBase
& rShape
) const
450 const ::oox::vml::ClientData
* pClientData
= rShape
.getClientData();
451 return !pClientData
|| (pClientData
->mnObjType
!= XML_Note
);
454 OUString
VmlDrawing::getShapeBaseName( const ::oox::vml::ShapeBase
& rShape
) const
456 if( const ::oox::vml::ClientData
* pClientData
= rShape
.getClientData() )
458 switch( pClientData
->mnObjType
)
460 case XML_Button
: return "Button";
461 case XML_Checkbox
: return "Check Box";
462 case XML_Dialog
: return "Dialog Frame";
463 case XML_Drop
: return "Drop Down";
464 case XML_Edit
: return "Edit Box";
465 case XML_GBox
: return "Group Box";
466 case XML_Label
: return "Label";
467 case XML_List
: return "List Box";
468 case XML_Note
: return "Comment";
469 case XML_Pict
: return (pClientData
->mbDde
|| getOleObjectInfo( rShape
.getShapeId() )) ? OUString( "Object" ) : OUString( "Picture" );
470 case XML_Radio
: return "Option Button";
471 case XML_Scroll
: return "Scroll Bar";
472 case XML_Spin
: return "Spinner";
475 return ::oox::vml::Drawing::getShapeBaseName( rShape
);
478 bool VmlDrawing::convertClientAnchor( Rectangle
& orShapeRect
, const OUString
& rShapeAnchor
) const
480 if( rShapeAnchor
.isEmpty() )
482 ShapeAnchor
aAnchor( *this );
483 aAnchor
.importVmlAnchor( rShapeAnchor
);
484 orShapeRect
= aAnchor
.calcAnchorRectHmm( getDrawPageSize() );
485 return (orShapeRect
.Width
>= 0) && (orShapeRect
.Height
>= 0);
488 Reference
< XShape
> VmlDrawing::createAndInsertClientXShape( const ::oox::vml::ShapeBase
& rShape
,
489 const Reference
< XShapes
>& rxShapes
, const Rectangle
& rShapeRect
) const
491 // simulate the legacy drawing controls with OLE form controls
492 OUString aShapeName
= rShape
.getShapeName();
493 const ::oox::vml::ClientData
* pClientData
= rShape
.getClientData();
494 if( !aShapeName
.isEmpty() && pClientData
)
496 Rectangle aShapeRect
= rShapeRect
;
497 const ::oox::vml::TextBox
* pTextBox
= rShape
.getTextBox();
498 EmbeddedControl
aControl( aShapeName
);
499 switch( pClientData
->mnObjType
)
503 AxCommandButtonModel
& rAxModel
= aControl
.createModel
< AxCommandButtonModel
>();
504 convertControlText( rAxModel
.maFontData
, rAxModel
.mnTextColor
, rAxModel
.maCaption
, pTextBox
, pClientData
->mnTextHAlign
);
505 rAxModel
.mnFlags
= AX_FLAGS_ENABLED
| AX_FLAGS_OPAQUE
| AX_FLAGS_WORDWRAP
;
506 rAxModel
.mnVerticalAlign
= pClientData
->mnTextVAlign
;
512 AxLabelModel
& rAxModel
= aControl
.createModel
< AxLabelModel
>();
513 convertControlText( rAxModel
.maFontData
, rAxModel
.mnTextColor
, rAxModel
.maCaption
, pTextBox
, pClientData
->mnTextHAlign
);
514 rAxModel
.mnFlags
= AX_FLAGS_ENABLED
| AX_FLAGS_WORDWRAP
;
515 rAxModel
.mnBorderStyle
= AX_BORDERSTYLE_NONE
;
516 rAxModel
.mnSpecialEffect
= AX_SPECIALEFFECT_FLAT
;
517 rAxModel
.mnVerticalAlign
= pClientData
->mnTextVAlign
;
523 bool bNumeric
= (pClientData
->mnVTEdit
== ::oox::vml::VML_CLIENTDATA_INTEGER
) || (pClientData
->mnVTEdit
== ::oox::vml::VML_CLIENTDATA_NUMBER
);
524 AxMorphDataModelBase
& rAxModel
= bNumeric
?
525 static_cast< AxMorphDataModelBase
& >( aControl
.createModel
< AxNumericFieldModel
>() ) :
526 static_cast< AxMorphDataModelBase
& >( aControl
.createModel
< AxTextBoxModel
>() );
527 convertControlText( rAxModel
.maFontData
, rAxModel
.mnTextColor
, rAxModel
.maValue
, pTextBox
, pClientData
->mnTextHAlign
);
528 setFlag( rAxModel
.mnFlags
, AX_FLAGS_MULTILINE
, pClientData
->mbMultiLine
);
529 setFlag( rAxModel
.mnScrollBars
, AX_SCROLLBAR_VERTICAL
, pClientData
->mbVScroll
);
530 if( pClientData
->mbSecretEdit
)
531 rAxModel
.mnPasswordChar
= '*';
537 AxFrameModel
& rAxModel
= aControl
.createModel
< AxFrameModel
>();
538 convertControlText( rAxModel
.maFontData
, rAxModel
.mnTextColor
, rAxModel
.maCaption
, pTextBox
, pClientData
->mnTextHAlign
);
539 rAxModel
.mnBorderStyle
= pClientData
->mbNo3D
? AX_BORDERSTYLE_SINGLE
: AX_BORDERSTYLE_NONE
;
540 rAxModel
.mnSpecialEffect
= pClientData
->mbNo3D
? AX_SPECIALEFFECT_FLAT
: AX_SPECIALEFFECT_BUMPED
;
542 /* Move top border of groupbox up by half font height, because
543 Excel specifies Y position of the groupbox border line
544 instead the top border of the caption text. */
545 if( const ::oox::vml::TextFontModel
* pFontModel
= pTextBox
? pTextBox
->getFirstFont() : nullptr )
547 sal_Int32 nFontHeightHmm
= getUnitConverter().scaleToMm100( pFontModel
->monSize
.get( 160 ), Unit::Twip
);
548 sal_Int32 nYDiff
= ::std::min
< sal_Int32
>( nFontHeightHmm
/ 2, aShapeRect
.Y
);
549 aShapeRect
.Y
-= nYDiff
;
550 aShapeRect
.Height
+= nYDiff
;
557 AxCheckBoxModel
& rAxModel
= aControl
.createModel
< AxCheckBoxModel
>();
558 convertControlText( rAxModel
.maFontData
, rAxModel
.mnTextColor
, rAxModel
.maCaption
, pTextBox
, pClientData
->mnTextHAlign
);
559 convertControlBackground( rAxModel
, rShape
);
560 rAxModel
.maValue
= OUString::number( pClientData
->mnChecked
);
561 rAxModel
.mnSpecialEffect
= pClientData
->mbNo3D
? AX_SPECIALEFFECT_FLAT
: AX_SPECIALEFFECT_SUNKEN
;
562 rAxModel
.mnVerticalAlign
= pClientData
->mnTextVAlign
;
563 bool bTriState
= (pClientData
->mnChecked
!= ::oox::vml::VML_CLIENTDATA_UNCHECKED
) && (pClientData
->mnChecked
!= ::oox::vml::VML_CLIENTDATA_CHECKED
);
564 rAxModel
.mnMultiSelect
= bTriState
? AX_SELECTION_MULTI
: AX_SELECTION_SINGLE
;
570 AxOptionButtonModel
& rAxModel
= aControl
.createModel
< AxOptionButtonModel
>();
572 // unique name to prevent autoGrouping with ActiveX controls and which a GroupBox may override - see vmldrawing.cxx.
573 rAxModel
.maGroupName
= "autoGroup_formControl";
574 convertControlText( rAxModel
.maFontData
, rAxModel
.mnTextColor
, rAxModel
.maCaption
, pTextBox
, pClientData
->mnTextHAlign
);
575 convertControlBackground( rAxModel
, rShape
);
576 rAxModel
.maValue
= OUString::number( pClientData
->mnChecked
);
577 rAxModel
.mnSpecialEffect
= pClientData
->mbNo3D
? AX_SPECIALEFFECT_FLAT
: AX_SPECIALEFFECT_SUNKEN
;
578 rAxModel
.mnVerticalAlign
= pClientData
->mnTextVAlign
;
584 AxListBoxModel
& rAxModel
= aControl
.createModel
< AxListBoxModel
>();
585 convertControlFontData( rAxModel
.maFontData
, rAxModel
.mnTextColor
, maListBoxFont
);
586 rAxModel
.mnBorderStyle
= pClientData
->mbNo3D2
? AX_BORDERSTYLE_SINGLE
: AX_BORDERSTYLE_NONE
;
587 rAxModel
.mnSpecialEffect
= pClientData
->mbNo3D2
? AX_SPECIALEFFECT_FLAT
: AX_SPECIALEFFECT_SUNKEN
;
588 switch( pClientData
->mnSelType
)
590 case XML_Single
: rAxModel
.mnMultiSelect
= AX_SELECTION_SINGLE
; break;
591 case XML_Multi
: rAxModel
.mnMultiSelect
= AX_SELECTION_MULTI
; break;
592 case XML_Extend
: rAxModel
.mnMultiSelect
= AX_SELECTION_EXTENDED
; break;
599 AxComboBoxModel
& rAxModel
= aControl
.createModel
< AxComboBoxModel
>();
600 convertControlFontData( rAxModel
.maFontData
, rAxModel
.mnTextColor
, maListBoxFont
);
601 rAxModel
.mnDisplayStyle
= AX_DISPLAYSTYLE_DROPDOWN
;
602 rAxModel
.mnShowDropButton
= AX_SHOWDROPBUTTON_ALWAYS
;
603 rAxModel
.mnBorderStyle
= pClientData
->mbNo3D2
? AX_BORDERSTYLE_SINGLE
: AX_BORDERSTYLE_NONE
;
604 rAxModel
.mnSpecialEffect
= pClientData
->mbNo3D2
? AX_SPECIALEFFECT_FLAT
: AX_SPECIALEFFECT_SUNKEN
;
605 rAxModel
.mnListRows
= pClientData
->mnDropLines
;
611 AxSpinButtonModel
& rAxModel
= aControl
.createModel
< AxSpinButtonModel
>();
612 rAxModel
.mnMin
= pClientData
->mnMin
;
613 rAxModel
.mnMax
= pClientData
->mnMax
;
614 rAxModel
.mnPosition
= pClientData
->mnVal
;
615 rAxModel
.mnSmallChange
= pClientData
->mnInc
;
621 AxScrollBarModel
& rAxModel
= aControl
.createModel
< AxScrollBarModel
>();
622 rAxModel
.mnMin
= pClientData
->mnMin
;
623 rAxModel
.mnMax
= pClientData
->mnMax
;
624 rAxModel
.mnPosition
= pClientData
->mnVal
;
625 rAxModel
.mnSmallChange
= pClientData
->mnInc
;
626 rAxModel
.mnLargeChange
= pClientData
->mnPage
;
632 // fake with a group box
633 AxFrameModel
& rAxModel
= aControl
.createModel
< AxFrameModel
>();
634 convertControlText( rAxModel
.maFontData
, rAxModel
.mnTextColor
, rAxModel
.maCaption
, pTextBox
, XML_Left
);
635 rAxModel
.mnBorderStyle
= AX_BORDERSTYLE_SINGLE
;
636 rAxModel
.mnSpecialEffect
= AX_SPECIALEFFECT_FLAT
;
641 if( ControlModelBase
* pAxModel
= aControl
.getModel() )
643 // create the control shape
644 pAxModel
->maSize
.first
= aShapeRect
.Width
;
645 pAxModel
->maSize
.second
= aShapeRect
.Height
;
646 sal_Int32 nCtrlIndex
= -1;
647 Reference
< XShape
> xShape
= createAndInsertXControlShape( aControl
, rxShapes
, aShapeRect
, nCtrlIndex
);
649 // control shape macro
650 if( xShape
.is() && (nCtrlIndex
>= 0) && !pClientData
->maFmlaMacro
.isEmpty() )
652 OUString aMacroName
= getFormulaParser().importMacroName( pClientData
->maFmlaMacro
);
653 if( !aMacroName
.isEmpty() )
655 Reference
< XIndexContainer
> xFormIC
= getControlForm().getXForm();
656 VbaMacroAttacherRef xAttacher
= std::make_shared
<VmlControlMacroAttacher
>( aMacroName
, xFormIC
, nCtrlIndex
, pClientData
->mnObjType
, pClientData
->mnDropStyle
);
657 getBaseFilter().getVbaProject().registerMacroAttacher( xAttacher
);
665 return Reference
< XShape
>();
668 void VmlDrawing::notifyXShapeInserted( const Reference
< XShape
>& rxShape
,
669 const Rectangle
& rShapeRect
, const ::oox::vml::ShapeBase
& rShape
, bool bGroupChild
)
671 // collect all shape positions in the WorksheetHelper base class (but not children of group shapes)
673 extendShapeBoundingBox( rShapeRect
);
675 // convert settings from VML client data
676 const ::oox::vml::ClientData
* pClientData
= rShape
.getClientData();
680 // specific settings for embedded form controls
683 Reference
< XControlShape
> xCtrlShape( rxShape
, UNO_QUERY_THROW
);
684 Reference
< XControlModel
> xCtrlModel( xCtrlShape
->getControl(), UNO_SET_THROW
);
685 PropertySet
aPropSet( xCtrlModel
);
688 aPropSet
.setProperty( PROP_Printable
, pClientData
->mbPrintObject
);
690 // control source links
691 if( !pClientData
->maFmlaLink
.isEmpty() || !pClientData
->maFmlaRange
.isEmpty() )
692 maControlConv
.bindToSources( xCtrlModel
, pClientData
->maFmlaLink
, pClientData
->maFmlaRange
, getSheetIndex() );
699 // private --------------------------------------------------------------------
701 sal_uInt32
VmlDrawing::convertControlTextColor( const OUString
& rTextColor
) const
703 // color attribute not present or 'auto' - use passed default color
704 if( rTextColor
.isEmpty() || rTextColor
.equalsIgnoreAsciiCase( "auto" ) )
705 return AX_SYSCOLOR_WINDOWTEXT
;
707 if( rTextColor
[ 0 ] == '#' )
709 // RGB colors in the format '#RRGGBB'
710 if( rTextColor
.getLength() == 7 )
711 return OleHelper::encodeOleColor( rTextColor
.copy( 1 ).toUInt32( 16 ) );
713 // RGB colors in the format '#RGB'
714 if( rTextColor
.getLength() == 4 )
716 sal_Int32 nR
= rTextColor
.copy( 1, 1 ).toUInt32( 16 ) * 0x11;
717 sal_Int32 nG
= rTextColor
.copy( 2, 1 ).toUInt32( 16 ) * 0x11;
718 sal_Int32 nB
= rTextColor
.copy( 3, 1 ).toUInt32( 16 ) * 0x11;
719 return OleHelper::encodeOleColor( (nR
<< 16) | (nG
<< 8) | nB
);
722 OSL_ENSURE( false, OStringBuffer( "VmlDrawing::convertControlTextColor - invalid color name '" ).
723 append( OUStringToOString( rTextColor
, RTL_TEXTENCODING_ASCII_US
) ).append( '\'' ).getStr() );
724 return AX_SYSCOLOR_WINDOWTEXT
;
727 const GraphicHelper
& rGraphicHelper
= getBaseFilter().getGraphicHelper();
729 /* Predefined color names or system color names (resolve to RGB to detect
730 valid color name). */
731 sal_Int32 nColorToken
= AttributeConversion::decodeToken( rTextColor
);
732 ::Color nRgbValue
= Color::getVmlPresetColor( nColorToken
, API_RGB_TRANSPARENT
);
733 if( nRgbValue
== API_RGB_TRANSPARENT
)
734 nRgbValue
= rGraphicHelper
.getSystemColor( nColorToken
);
735 if( nRgbValue
!= API_RGB_TRANSPARENT
)
736 return OleHelper::encodeOleColor( nRgbValue
);
739 return OleHelper::encodeOleColor( rGraphicHelper
.getPaletteColor( rTextColor
.toInt32() ) );
742 void VmlDrawing::convertControlFontData( AxFontData
& rAxFontData
, sal_uInt32
& rnOleTextColor
, const ::oox::vml::TextFontModel
& rFontModel
) const
744 if( rFontModel
.moName
.has() )
745 rAxFontData
.maFontName
= rFontModel
.moName
.get();
747 // font height: convert from twips to points, then to internal representation of AX controls
748 rAxFontData
.setHeightPoints( static_cast< sal_Int16
>( (rFontModel
.monSize
.get( 200 ) + 10) / 20 ) );
751 rAxFontData
.mnFontEffects
= AxFontFlags::NONE
;
752 setFlag( rAxFontData
.mnFontEffects
, AxFontFlags::Bold
, rFontModel
.mobBold
.get( false ) );
753 setFlag( rAxFontData
.mnFontEffects
, AxFontFlags::Italic
, rFontModel
.mobItalic
.get( false ) );
754 setFlag( rAxFontData
.mnFontEffects
, AxFontFlags::Strikeout
, rFontModel
.mobStrikeout
.get( false ) );
755 sal_Int32 nUnderline
= rFontModel
.monUnderline
.get( XML_none
);
756 setFlag( rAxFontData
.mnFontEffects
, AxFontFlags::Underline
, nUnderline
!= XML_none
);
757 rAxFontData
.mbDblUnderline
= nUnderline
== XML_double
;
760 rnOleTextColor
= convertControlTextColor( rFontModel
.moColor
.get( OUString() ) );
763 void VmlDrawing::convertControlText( AxFontData
& rAxFontData
, sal_uInt32
& rnOleTextColor
,
764 OUString
& rCaption
, const ::oox::vml::TextBox
* pTextBox
, sal_Int32 nTextHAlign
) const
768 rCaption
= pTextBox
->getText();
769 if( const ::oox::vml::TextFontModel
* pFontModel
= pTextBox
->getFirstFont() )
770 convertControlFontData( rAxFontData
, rnOleTextColor
, *pFontModel
);
773 switch( nTextHAlign
)
775 case XML_Left
: rAxFontData
.mnHorAlign
= AxHorizontalAlign::Left
; break;
776 case XML_Center
: rAxFontData
.mnHorAlign
= AxHorizontalAlign::Center
; break;
777 case XML_Right
: rAxFontData
.mnHorAlign
= AxHorizontalAlign::Right
; break;
778 default: rAxFontData
.mnHorAlign
= AxHorizontalAlign::Left
;
782 void VmlDrawing::convertControlBackground( AxMorphDataModelBase
& rAxModel
, const ::oox::vml::ShapeBase
& rShape
) const
784 const ::oox::vml::FillModel
& rFillModel
= rShape
.getTypeModel().maFillModel
;
785 bool bHasFill
= rFillModel
.moFilled
.get( true );
786 setFlag( rAxModel
.mnFlags
, AX_FLAGS_OPAQUE
, bHasFill
);
789 const GraphicHelper
& rGraphicHelper
= getBaseFilter().getGraphicHelper();
790 ::Color nSysWindowColor
= rGraphicHelper
.getSystemColor( XML_window
, API_RGB_WHITE
);
791 ::oox::drawingml::Color aColor
= ::oox::vml::ConversionHelper::decodeColor( rGraphicHelper
, rFillModel
.moColor
, rFillModel
.moOpacity
, nSysWindowColor
);
792 ::Color nRgbValue
= aColor
.getColor( rGraphicHelper
);
793 rAxModel
.mnBackColor
= OleHelper::encodeOleColor( nRgbValue
);
797 VmlDrawingFragment::VmlDrawingFragment( const WorksheetHelper
& rHelper
, const OUString
& rFragmentPath
) :
798 ::oox::vml::DrawingFragment( rHelper
.getOoxFilter(), rFragmentPath
, rHelper
.getVmlDrawing() ),
799 WorksheetHelper( rHelper
)
803 void VmlDrawingFragment::finalizeImport()
805 ::oox::vml::DrawingFragment::finalizeImport();
806 getVmlDrawing().convertAndInsert();
811 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */