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 "drawingml/customshapeproperties.hxx"
21 #include "oox/helper/helper.hxx"
22 #include "oox/helper/propertymap.hxx"
23 #include "oox/helper/propertyset.hxx"
24 #include "oox/token/tokenmap.hxx"
25 #include <com/sun/star/awt/Rectangle.hpp>
26 #include <com/sun/star/awt/Size.hpp>
27 #include <com/sun/star/beans/XMultiPropertySet.hpp>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/graphic/XGraphicTransformer.hpp>
30 #include <com/sun/star/drawing/XShape.hpp>
31 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
32 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
33 #include <osl/diagnose.h>
35 using namespace ::oox::core
;
36 using namespace ::com::sun::star
;
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::beans
;
39 using namespace ::com::sun::star::graphic
;
40 using namespace ::com::sun::star::drawing
;
42 namespace oox
{ namespace drawingml
{
44 CustomShapeProperties::CustomShapeProperties()
45 : mnShapePresetType ( -1 )
46 , mbShapeTypeOverride(false)
47 , mbMirroredX ( false )
48 , mbMirroredY ( false )
49 , mnTextRotateAngle ( 0 )
53 CustomShapeProperties::~CustomShapeProperties()
57 uno::Sequence
< sal_Int8
> CustomShapeProperties::getShapePresetTypeName() const
59 return StaticTokenMap::get().getUtf8TokenName( mnShapePresetType
);
62 sal_Int32
CustomShapeProperties::SetCustomShapeGuideValue( std::vector
< CustomShapeGuide
>& rGuideList
, const CustomShapeGuide
& rGuide
)
64 sal_uInt32 nIndex
= 0;
65 for( ; nIndex
< rGuideList
.size(); nIndex
++ )
67 if ( rGuideList
[ nIndex
].maName
== rGuide
.maName
)
70 if ( nIndex
== rGuideList
.size() )
71 rGuideList
.push_back( rGuide
);
72 return static_cast< sal_Int32
>( nIndex
);
75 // returns the index into the guidelist for a given formula name,
76 // if the return value is < 0 then the guide value could not be found
77 sal_Int32
CustomShapeProperties::GetCustomShapeGuideValue( const std::vector
< CustomShapeGuide
>& rGuideList
, const OUString
& rFormulaName
)
79 // traverse the list from the end, because guide names can be reused
80 // and current is the last one
81 // see a1 guide in gear6 custom shape preset as example
82 sal_Int32 nIndex
= static_cast< sal_Int32
>( rGuideList
.size() ) - 1;
83 for( ; nIndex
>= 0; nIndex
-- )
85 if ( rGuideList
[ nIndex
].maName
== rFormulaName
)
92 CustomShapeProperties::PresetDataMap
CustomShapeProperties::maPresetDataMap
;
94 static OUString
GetConnectorShapeType( sal_Int32 nType
)
97 "oox.drawingml", "preset: " << nType
<< " " << XML_straightConnector1
);
102 case XML_straightConnector1
:
111 void CustomShapeProperties::pushToPropSet( const ::oox::core::FilterBase
& /* rFilterBase */,
112 const Reference
< XPropertySet
>& xPropSet
, const Reference
< XShape
> & xShape
, const awt::Size
&aSize
)
114 if ( mnShapePresetType
>= 0 )
116 SAL_INFO("oox.drawingml", "preset: " << mnShapePresetType
);
118 if (maPresetDataMap
.empty())
119 initializePresetDataMap();
121 PropertyMap aPropertyMap
;
122 PropertySet
aPropSet( xPropSet
);
124 OUString sConnectorShapeType
= GetConnectorShapeType( mnShapePresetType
);
126 if (sConnectorShapeType
.getLength() > 0)
130 "connector shape: " << sConnectorShapeType
<< " ("
131 << mnShapePresetType
<< ")");
132 //const uno::Reference < drawing::XShape > xShape( xPropSet, UNO_QUERY );
133 Reference
< drawing::XEnhancedCustomShapeDefaulter
> xDefaulter( xShape
, UNO_QUERY
);
134 if( xDefaulter
.is() ) {
135 xDefaulter
->createCustomShapeDefaults( sConnectorShapeType
);
136 aPropertyMap
.setProperty( PROP_Type
, sConnectorShapeType
);
139 else if (maPresetDataMap
.find(mnShapePresetType
) != maPresetDataMap
.end())
143 "found property map for preset: " << mnShapePresetType
);
145 aPropertyMap
= maPresetDataMap
[mnShapePresetType
];
147 aPropertyMap
.dumpCode();
151 aPropertyMap
.setProperty( PROP_MirroredX
, mbMirroredX
);
152 aPropertyMap
.setProperty( PROP_MirroredY
, mbMirroredY
);
153 aPropertyMap
.setProperty( PROP_TextPreRotateAngle
, mnTextRotateAngle
);
154 aPropertyMap
.setProperty( PROP_IsPostRotateAngle
, true); // For OpenXML Imports
155 Sequence
< PropertyValue
> aSeq
= aPropertyMap
.makePropertyValueSequence();
156 aPropSet
.setProperty( PROP_CustomShapeGeometry
, aSeq
);
158 const OUString
sCustomShapeGeometry("CustomShapeGeometry");
159 uno::Any aGeoPropSet
= xPropSet
->getPropertyValue( sCustomShapeGeometry
);
160 uno::Sequence
< beans::PropertyValue
> aGeoPropSeq
;
162 sal_Int32 i
, nCount
= 0;
163 if (aGeoPropSet
>>= aGeoPropSeq
)
165 nCount
= aGeoPropSeq
.getLength();
166 for ( i
= 0; i
< nCount
; i
++ )
168 const OUString
sAdjustmentValues("AdjustmentValues");
169 if ( aGeoPropSeq
[ i
].Name
.equals( sAdjustmentValues
) )
171 OUString presetTextWarp
;
172 if ( aGeoPropSeq
[ i
].Value
>>= presetTextWarp
)
174 aPropertyMap
.setProperty( PROP_PresetTextWarp
, Any( presetTextWarp
) );
180 if ( maAdjustmentGuideList
.size() )
182 const OUString sType
= "Type";
183 if ( aGeoPropSet
>>= aGeoPropSeq
)
185 nCount
= aGeoPropSeq
.getLength();
186 for ( i
= 0; i
< nCount
; i
++ )
188 const OUString
sAdjustmentValues("AdjustmentValues");
189 if ( aGeoPropSeq
[ i
].Name
.equals( sAdjustmentValues
) )
191 uno::Sequence
< com::sun::star::drawing::EnhancedCustomShapeAdjustmentValue
> aAdjustmentSeq
;
192 if ( aGeoPropSeq
[ i
].Value
>>= aAdjustmentSeq
)
195 for (std::vector
< CustomShapeGuide
>::const_iterator
aIter( maAdjustmentGuideList
.begin() ), aEnd(maAdjustmentGuideList
.end());
196 aIter
!= aEnd
; ++aIter
)
198 if ( (*aIter
).maName
.getLength() > 3 )
200 sal_Int32 nAdjustmentIndex
= (*aIter
).maName
.copy( 3 ).toInt32() - 1;
201 if ( ( nAdjustmentIndex
>= 0 ) && ( nAdjustmentIndex
< aAdjustmentSeq
.getLength() ) )
203 EnhancedCustomShapeAdjustmentValue aAdjustmentVal
;
204 aAdjustmentVal
.Value
<<= (*aIter
).maFormula
.toInt32();
205 aAdjustmentVal
.State
= PropertyState_DIRECT_VALUE
;
206 aAdjustmentVal
.Name
= (*aIter
).maName
;
207 aAdjustmentSeq
[ nAdjustmentIndex
] = aAdjustmentVal
;
209 } else if ( aAdjustmentSeq
.getLength() > 0 ) {
210 EnhancedCustomShapeAdjustmentValue aAdjustmentVal
;
211 aAdjustmentVal
.Value
<<= (*aIter
).maFormula
.toInt32();
212 aAdjustmentVal
.State
= PropertyState_DIRECT_VALUE
;
213 aAdjustmentVal
.Name
= (*aIter
).maName
;
214 aAdjustmentSeq
[ nIndex
++ ] = aAdjustmentVal
;
217 aGeoPropSeq
[ i
].Value
<<= aAdjustmentSeq
;
218 xPropSet
->setPropertyValue( sCustomShapeGeometry
, Any( aGeoPropSeq
) );
221 else if ( aGeoPropSeq
[ i
].Name
.equals( sType
) )
223 if ( sConnectorShapeType
.getLength() > 0 )
224 aGeoPropSeq
[ i
].Value
<<= sConnectorShapeType
;
226 aGeoPropSeq
[ i
].Value
<<= OUString( "ooxml-CustomShape" );
235 PropertyMap aPropertyMap
;
236 aPropertyMap
.setProperty( PROP_Type
, OUString( "ooxml-non-primitive" ));
237 aPropertyMap
.setProperty( PROP_MirroredX
, mbMirroredX
);
238 aPropertyMap
.setProperty( PROP_MirroredY
, mbMirroredY
);
239 // Note 1: If Equations are defined - they are processed using internal div by 360 coordinates
240 // while if they are not, standard ooxml coordinates are used.
241 // This size specifically affects scaling.
242 // Note 2: Width and Height are set to 0 to force scaling to 1.
243 awt::Rectangle
aViewBox( 0, 0, aSize
.Width
, aSize
.Height
);
244 if( maGuideList
.size() )
245 aViewBox
= awt::Rectangle( 0, 0, 0, 0 );
246 aPropertyMap
.setProperty( PROP_ViewBox
, aViewBox
);
248 Sequence
< EnhancedCustomShapeAdjustmentValue
> aAdjustmentValues( maAdjustmentGuideList
.size() );
249 for ( i
= 0; i
< maAdjustmentGuideList
.size(); i
++ )
251 EnhancedCustomShapeAdjustmentValue aAdjustmentVal
;
252 aAdjustmentVal
.Value
<<= maAdjustmentGuideList
[ i
].maFormula
.toInt32();
253 aAdjustmentVal
.State
= PropertyState_DIRECT_VALUE
;
254 aAdjustmentVal
.Name
= maAdjustmentGuideList
[ i
].maName
;
255 aAdjustmentValues
[ i
] = aAdjustmentVal
;
257 aPropertyMap
.setProperty( PROP_AdjustmentValues
, aAdjustmentValues
);
261 Sequence
< EnhancedCustomShapeSegment
> aSegments( maSegments
.size() );
262 for ( i
= 0; i
< maSegments
.size(); i
++ )
263 aSegments
[ i
] = maSegments
[ i
];
264 aPath
.setProperty( PROP_Segments
, aSegments
);
266 if ( maTextRect
.has() ) {
267 Sequence
< EnhancedCustomShapeTextFrame
> aTextFrames(1);
268 aTextFrames
[0].TopLeft
.First
= maTextRect
.get().l
;
269 aTextFrames
[0].TopLeft
.Second
= maTextRect
.get().t
;
270 aTextFrames
[0].BottomRight
.First
= maTextRect
.get().r
;
271 aTextFrames
[0].BottomRight
.Second
= maTextRect
.get().b
;
272 aPath
.setProperty( PROP_TextFrames
, aTextFrames
);
275 sal_uInt32 j
, k
, nParameterPairs
= 0;
276 for ( i
= 0; i
< maPath2DList
.size(); i
++ )
277 nParameterPairs
+= maPath2DList
[ i
].parameter
.size();
279 Sequence
< EnhancedCustomShapeParameterPair
> aParameterPairs( nParameterPairs
);
280 for ( i
= 0, k
= 0; i
< maPath2DList
.size(); i
++ )
281 for ( j
= 0; j
< maPath2DList
[ i
].parameter
.size(); j
++ )
282 aParameterPairs
[ k
++ ] = maPath2DList
[ i
].parameter
[ j
];
283 aPath
.setProperty( PROP_Coordinates
, aParameterPairs
);
285 if ( maPath2DList
.size() )
287 bool bAllZero
= true;
288 for ( i
=0; i
< maPath2DList
.size(); i
++ )
290 if ( maPath2DList
[i
].w
|| maPath2DList
[i
].h
) {
297 Sequence
< awt::Size
> aSubViewSize( maPath2DList
.size() );
298 for ( i
=0; i
< maPath2DList
.size(); i
++ )
300 aSubViewSize
[i
].Width
= static_cast< sal_Int32
>( maPath2DList
[i
].w
);
301 aSubViewSize
[i
].Height
= static_cast< sal_Int32
>( maPath2DList
[i
].h
);
304 "set subpath " << i
<< " size: " << maPath2DList
[i
].w
305 << " x " << maPath2DList
[i
].h
);
307 aPath
.setProperty( PROP_SubViewSize
, aSubViewSize
);
311 Sequence
< PropertyValue
> aPathSequence
= aPath
.makePropertyValueSequence();
312 aPropertyMap
.setProperty( PROP_Path
, aPathSequence
);
314 Sequence
< OUString
> aEquations( maGuideList
.size() );
315 for ( i
= 0; i
< maGuideList
.size(); i
++ )
316 aEquations
[ i
] = maGuideList
[ i
].maFormula
;
317 aPropertyMap
.setProperty( PROP_Equations
, aEquations
);
319 Sequence
< PropertyValues
> aHandles( maAdjustHandleList
.size() );
320 for ( i
= 0; i
< maAdjustHandleList
.size(); i
++ )
323 // maAdjustmentHandle[ i ].gdRef1 ... maAdjustmentHandle[ i ].gdRef2 ... :(
324 // gdRef1 && gdRef2 -> we do not offer such reference, so it is difficult
325 // to determine the correct adjustment handle that should be updated with the adjustment
326 // position. here is the solution: the adjustment value that is used within the position
327 // has to be updated, in case the position is a formula the first usage of a
328 // adjustment value is decisive
329 if ( maAdjustHandleList
[ i
].polar
)
331 aHandle
.setProperty( PROP_Position
, maAdjustHandleList
[ i
].pos
);
332 if ( maAdjustHandleList
[ i
].min1
.has() )
333 aHandle
.setProperty( PROP_RadiusRangeMinimum
, maAdjustHandleList
[ i
].min1
.get());
334 if ( maAdjustHandleList
[ i
].max1
.has() )
335 aHandle
.setProperty( PROP_RadiusRangeMaximum
, maAdjustHandleList
[ i
].max1
.get());
337 /* TODO: AngleMin & AngleMax
338 if ( maAdjustHandleList[ i ].min2.has() )
339 aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].min2.get());
340 if ( maAdjustHandleList[ i ].max2.has() )
341 aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].max2.get());
346 aHandle
.setProperty( PROP_Position
, maAdjustHandleList
[ i
].pos
);
347 if ( maAdjustHandleList
[ i
].gdRef1
.has() )
349 // TODO: PROP_RefX and PROP_RefY are not yet part of our file format,
350 // so the handles will not work after save/reload
351 sal_Int32 nIndex
= GetCustomShapeGuideValue( maAdjustmentGuideList
, maAdjustHandleList
[ i
].gdRef1
.get() );
353 aHandle
.setProperty( PROP_RefX
, nIndex
);
355 if ( maAdjustHandleList
[ i
].gdRef2
.has() )
357 sal_Int32 nIndex
= GetCustomShapeGuideValue( maAdjustmentGuideList
, maAdjustHandleList
[ i
].gdRef2
.get() );
359 aHandle
.setProperty( PROP_RefY
, nIndex
);
361 if ( maAdjustHandleList
[ i
].min1
.has() )
362 aHandle
.setProperty( PROP_RangeXMinimum
, maAdjustHandleList
[ i
].min1
.get());
363 if ( maAdjustHandleList
[ i
].max1
.has() )
364 aHandle
.setProperty( PROP_RangeXMaximum
, maAdjustHandleList
[ i
].max1
.get());
365 if ( maAdjustHandleList
[ i
].min2
.has() )
366 aHandle
.setProperty( PROP_RangeYMinimum
, maAdjustHandleList
[ i
].min2
.get());
367 if ( maAdjustHandleList
[ i
].max2
.has() )
368 aHandle
.setProperty( PROP_RangeYMaximum
, maAdjustHandleList
[ i
].max2
.get());
370 aHandles
[ i
] = aHandle
.makePropertyValueSequence();
372 aPropertyMap
.setProperty( PROP_Handles
, aHandles
);
375 SAL_INFO("oox.cscode", "==cscode== begin");
376 aPropertyMap
.dumpCode();
377 SAL_INFO("oox.cscode", "==cscode== end");
378 SAL_INFO("oox.csdata", "==csdata== begin");
379 aPropertyMap
.dumpData();
380 SAL_INFO("oox.csdata", "==csdata== end");
382 // converting the vector to a sequence
383 Sequence
< PropertyValue
> aSeq
= aPropertyMap
.makePropertyValueSequence();
384 PropertySet
aPropSet( xPropSet
);
385 aPropSet
.setProperty( PROP_CustomShapeGeometry
, aSeq
);
391 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */