Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / oox / source / drawingml / customshapeproperties.cxx
blob5cf9cd235b9396e66dba07d571ce0331c610ce0c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/propertymap.hxx"
22 #include "oox/helper/propertyset.hxx"
23 #include <oox/token/properties.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/PropertyValues.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
30 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
31 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
32 #include <com/sun/star/drawing/XShape.hpp>
33 #include <comphelper/sequence.hxx>
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::uno;
37 using namespace ::com::sun::star::beans;
38 using namespace ::com::sun::star::drawing;
40 namespace oox { namespace drawingml {
42 CustomShapeProperties::CustomShapeProperties()
43 : mnShapePresetType ( -1 )
44 , mbShapeTypeOverride(false)
45 , mbMirroredX ( false )
46 , mbMirroredY ( false )
47 , mnTextRotateAngle ( 0 )
48 , mnArcNum ( 0 )
51 CustomShapeProperties::~CustomShapeProperties()
55 uno::Sequence< sal_Int8 > CustomShapeProperties::getShapePresetTypeName() const
57 return StaticTokenMap::get().getUtf8TokenName( mnShapePresetType );
60 sal_Int32 CustomShapeProperties::SetCustomShapeGuideValue( std::vector< CustomShapeGuide >& rGuideList, const CustomShapeGuide& rGuide )
62 std::vector<CustomShapeGuide>::size_type nIndex = 0;
63 for( ; nIndex < rGuideList.size(); nIndex++ )
65 if ( rGuideList[ nIndex ].maName == rGuide.maName )
66 break;
68 if ( nIndex == rGuideList.size() )
69 rGuideList.push_back( rGuide );
70 return static_cast< sal_Int32 >( nIndex );
73 // returns the index into the guidelist for a given formula name,
74 // if the return value is < 0 then the guide value could not be found
75 sal_Int32 CustomShapeProperties::GetCustomShapeGuideValue( const std::vector< CustomShapeGuide >& rGuideList, const OUString& rFormulaName )
77 // traverse the list from the end, because guide names can be reused
78 // and current is the last one
79 // see a1 guide in gear6 custom shape preset as example
80 sal_Int32 nIndex = static_cast< sal_Int32 >( rGuideList.size() ) - 1;
81 for( ; nIndex >= 0; nIndex-- )
83 if ( rGuideList[ nIndex ].maName == rFormulaName )
84 break;
87 return nIndex;
90 CustomShapeProperties::PresetDataMap CustomShapeProperties::maPresetDataMap;
92 static OUString GetConnectorShapeType( sal_Int32 nType )
94 SAL_INFO(
95 "oox.drawingml", "preset: " << nType << " " << XML_straightConnector1);
97 OUString sType;
98 switch( nType )
100 case XML_straightConnector1:
101 sType = "mso-spt32";
102 break;
103 default:
104 break;
106 return sType;
109 void CustomShapeProperties::pushToPropSet(
110 const Reference < XPropertySet >& xPropSet, const Reference < XShape > & xShape, const awt::Size &aSize )
112 if ( mnShapePresetType >= 0 )
114 SAL_INFO("oox.drawingml", "preset: " << mnShapePresetType);
116 if (maPresetDataMap.empty())
117 initializePresetDataMap();
119 PropertyMap aPropertyMap;
120 PropertySet aPropSet( xPropSet );
122 OUString sConnectorShapeType = GetConnectorShapeType( mnShapePresetType );
124 if (sConnectorShapeType.getLength() > 0)
126 SAL_INFO(
127 "oox.drawingml",
128 "connector shape: " << sConnectorShapeType << " ("
129 << mnShapePresetType << ")");
130 //const uno::Reference < drawing::XShape > xShape( xPropSet, UNO_QUERY );
131 Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY );
132 if( xDefaulter.is() ) {
133 xDefaulter->createCustomShapeDefaults( sConnectorShapeType );
134 aPropertyMap.setProperty( PROP_Type, sConnectorShapeType );
137 else if (maPresetDataMap.find(mnShapePresetType) != maPresetDataMap.end())
139 SAL_INFO(
140 "oox.drawingml",
141 "found property map for preset: " << mnShapePresetType);
143 aPropertyMap = maPresetDataMap[mnShapePresetType];
144 #ifdef DEBUG
145 aPropertyMap.dumpCode( aPropertyMap.makePropertySet() );
146 #endif
149 aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
150 aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
151 aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextRotateAngle );
152 aPropertyMap.setProperty( PROP_IsPostRotateAngle, true); // For OpenXML Imports
153 Sequence< PropertyValue > aSeq = aPropertyMap.makePropertyValueSequence();
154 aPropSet.setProperty( PROP_CustomShapeGeometry, aSeq );
156 const OUString sCustomShapeGeometry("CustomShapeGeometry");
157 uno::Any aGeoPropSet = xPropSet->getPropertyValue( sCustomShapeGeometry );
158 uno::Sequence< beans::PropertyValue > aGeoPropSeq;
160 sal_Int32 i, nCount = 0;
161 if (aGeoPropSet >>= aGeoPropSeq)
163 nCount = aGeoPropSeq.getLength();
164 for ( i = 0; i < nCount; i++ )
166 const OUString sAdjustmentValues("AdjustmentValues");
167 if ( aGeoPropSeq[ i ].Name.equals( sAdjustmentValues ) )
169 OUString presetTextWarp;
170 if ( aGeoPropSeq[ i ].Value >>= presetTextWarp )
172 aPropertyMap.setProperty( PROP_PresetTextWarp, presetTextWarp );
178 if ( maAdjustmentGuideList.size() )
180 const OUString sType = "Type";
181 if ( aGeoPropSet >>= aGeoPropSeq )
183 nCount = aGeoPropSeq.getLength();
184 for ( i = 0; i < nCount; i++ )
186 const OUString sAdjustmentValues("AdjustmentValues");
187 if ( aGeoPropSeq[ i ].Name.equals( sAdjustmentValues ) )
189 uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq;
190 if ( aGeoPropSeq[ i ].Value >>= aAdjustmentSeq )
192 int nIndex=0;
193 for (std::vector< CustomShapeGuide >::const_iterator aIter( maAdjustmentGuideList.begin() ), aEnd(maAdjustmentGuideList.end());
194 aIter != aEnd; ++aIter)
196 if ( (*aIter).maName.getLength() > 3 )
198 sal_Int32 nAdjustmentIndex = (*aIter).maName.copy( 3 ).toInt32() - 1;
199 if ( ( nAdjustmentIndex >= 0 ) && ( nAdjustmentIndex < aAdjustmentSeq.getLength() ) )
201 EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
202 aAdjustmentVal.Value <<= (*aIter).maFormula.toInt32();
203 aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
204 aAdjustmentVal.Name = (*aIter).maName;
205 aAdjustmentSeq[ nAdjustmentIndex ] = aAdjustmentVal;
207 } else if ( aAdjustmentSeq.getLength() > 0 ) {
208 EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
209 aAdjustmentVal.Value <<= (*aIter).maFormula.toInt32();
210 aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
211 aAdjustmentVal.Name = (*aIter).maName;
212 aAdjustmentSeq[ nIndex++ ] = aAdjustmentVal;
215 aGeoPropSeq[ i ].Value <<= aAdjustmentSeq;
216 xPropSet->setPropertyValue( sCustomShapeGeometry, Any( aGeoPropSeq ) );
219 else if ( aGeoPropSeq[ i ].Name.equals( sType ) )
221 if ( sConnectorShapeType.getLength() > 0 )
222 aGeoPropSeq[ i ].Value <<= sConnectorShapeType;
223 else
224 aGeoPropSeq[ i ].Value <<= OUString( "ooxml-CustomShape" );
230 else
232 PropertyMap aPropertyMap;
233 aPropertyMap.setProperty( PROP_Type, OUString( "ooxml-non-primitive" ));
234 aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
235 aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
236 // Note 1: If Equations are defined - they are processed using internal div by 360 coordinates
237 // while if they are not, standard ooxml coordinates are used.
238 // This size specifically affects scaling.
239 // Note 2: Width and Height are set to 0 to force scaling to 1.
240 awt::Rectangle aViewBox( 0, 0, aSize.Width, aSize.Height );
241 if( maGuideList.size() )
242 aViewBox = awt::Rectangle( 0, 0, 0, 0 );
243 aPropertyMap.setProperty( PROP_ViewBox, aViewBox);
245 Sequence< EnhancedCustomShapeAdjustmentValue > aAdjustmentValues( maAdjustmentGuideList.size() );
246 for ( std::vector<CustomShapeGuide>::size_type i = 0; i < maAdjustmentGuideList.size(); i++ )
248 EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
249 aAdjustmentVal.Value <<= maAdjustmentGuideList[ i ].maFormula.toInt32();
250 aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
251 aAdjustmentVal.Name = maAdjustmentGuideList[ i ].maName;
252 aAdjustmentValues[ i ] = aAdjustmentVal;
254 aPropertyMap.setProperty( PROP_AdjustmentValues, aAdjustmentValues);
256 PropertyMap aPath;
258 aPath.setProperty( PROP_Segments, comphelper::containerToSequence(maSegments) );
260 if ( maTextRect.has() ) {
261 Sequence< EnhancedCustomShapeTextFrame > aTextFrames(1);
262 aTextFrames[0].TopLeft.First = maTextRect.get().l;
263 aTextFrames[0].TopLeft.Second = maTextRect.get().t;
264 aTextFrames[0].BottomRight.First = maTextRect.get().r;
265 aTextFrames[0].BottomRight.Second = maTextRect.get().b;
266 aPath.setProperty( PROP_TextFrames, aTextFrames);
269 sal_uInt32 nParameterPairs = 0;
270 for ( auto const & i: maPath2DList )
271 nParameterPairs += i.parameter.size();
273 Sequence< EnhancedCustomShapeParameterPair > aParameterPairs( nParameterPairs );
274 sal_uInt32 k = 0;
275 for ( auto const & i: maPath2DList )
276 for ( auto const & j: i.parameter )
277 aParameterPairs[ k++ ] = j;
278 aPath.setProperty( PROP_Coordinates, aParameterPairs);
280 if ( maPath2DList.size() )
282 bool bAllZero = true;
283 for ( auto const & i: maPath2DList )
285 if ( i.w || i.h ) {
286 bAllZero = false;
287 break;
291 if ( !bAllZero ) {
292 Sequence< awt::Size > aSubViewSize( maPath2DList.size() );
293 for ( std::vector<Path2D>::size_type i=0; i < maPath2DList.size(); i++ )
295 aSubViewSize[i].Width = static_cast< sal_Int32 >( maPath2DList[i].w );
296 aSubViewSize[i].Height = static_cast< sal_Int32 >( maPath2DList[i].h );
297 SAL_INFO(
298 "oox.cscode",
299 "set subpath " << i << " size: " << maPath2DList[i].w
300 << " x " << maPath2DList[i].h);
302 aPath.setProperty( PROP_SubViewSize, aSubViewSize);
306 Sequence< PropertyValue > aPathSequence = aPath.makePropertyValueSequence();
307 aPropertyMap.setProperty( PROP_Path, aPathSequence);
309 Sequence< OUString > aEquations( maGuideList.size() );
310 for ( std::vector<CustomShapeGuide>::size_type i = 0; i < maGuideList.size(); i++ )
311 aEquations[ i ] = maGuideList[ i ].maFormula;
312 aPropertyMap.setProperty( PROP_Equations, aEquations);
314 Sequence< PropertyValues > aHandles( maAdjustHandleList.size() );
315 for ( std::vector<AdjustHandle>::size_type i = 0; i < maAdjustHandleList.size(); i++ )
317 PropertyMap aHandle;
318 // maAdjustmentHandle[ i ].gdRef1 ... maAdjustmentHandle[ i ].gdRef2 ... :(
319 // gdRef1 && gdRef2 -> we do not offer such reference, so it is difficult
320 // to determine the correct adjustment handle that should be updated with the adjustment
321 // position. here is the solution: the adjustment value that is used within the position
322 // has to be updated, in case the position is a formula the first usage of a
323 // adjustment value is decisive
324 if ( maAdjustHandleList[ i ].polar )
326 // Polar handles in DrawingML
327 // 1. don't have reference center, so PROP_Polar isn't needed.
328 // 2. position always use planar coordinates.
329 // 3. use RefAngle and RefR to specify adjustment value to be updated.
330 // 4. The unit of angular adjustment values are 6000th degree.
332 aHandle.setProperty( PROP_Position, maAdjustHandleList[ i ].pos);
333 if ( maAdjustHandleList[ i ].gdRef1.has() )
335 sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef1.get() );
336 if ( nIndex >= 0 )
337 aHandle.setProperty( PROP_RefR, nIndex);
339 if ( maAdjustHandleList[ i ].gdRef2.has() )
341 sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef2.get() );
342 if ( nIndex >= 0 )
343 aHandle.setProperty( PROP_RefAngle, nIndex);
345 if ( maAdjustHandleList[ i ].min1.has() )
346 aHandle.setProperty( PROP_RadiusRangeMinimum, maAdjustHandleList[ i ].min1.get());
347 if ( maAdjustHandleList[ i ].max1.has() )
348 aHandle.setProperty( PROP_RadiusRangeMaximum, maAdjustHandleList[ i ].max1.get());
350 /* TODO: AngleMin & AngleMax
351 if ( maAdjustHandleList[ i ].min2.has() )
352 aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].min2.get());
353 if ( maAdjustHandleList[ i ].max2.has() )
354 aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].max2.get());
357 else
359 aHandle.setProperty( PROP_Position, maAdjustHandleList[ i ].pos);
360 if ( maAdjustHandleList[ i ].gdRef1.has() )
362 // TODO: PROP_RefX and PROP_RefY are not yet part of our file format,
363 // so the handles will not work after save/reload
364 sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef1.get() );
365 if ( nIndex >= 0 )
366 aHandle.setProperty( PROP_RefX, nIndex);
368 if ( maAdjustHandleList[ i ].gdRef2.has() )
370 sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef2.get() );
371 if ( nIndex >= 0 )
372 aHandle.setProperty( PROP_RefY, nIndex);
374 if ( maAdjustHandleList[ i ].min1.has() )
375 aHandle.setProperty( PROP_RangeXMinimum, maAdjustHandleList[ i ].min1.get());
376 if ( maAdjustHandleList[ i ].max1.has() )
377 aHandle.setProperty( PROP_RangeXMaximum, maAdjustHandleList[ i ].max1.get());
378 if ( maAdjustHandleList[ i ].min2.has() )
379 aHandle.setProperty( PROP_RangeYMinimum, maAdjustHandleList[ i ].min2.get());
380 if ( maAdjustHandleList[ i ].max2.has() )
381 aHandle.setProperty( PROP_RangeYMaximum, maAdjustHandleList[ i ].max2.get());
383 aHandles[ i ] = aHandle.makePropertyValueSequence();
385 aPropertyMap.setProperty( PROP_Handles, aHandles);
387 #ifdef DEBUG
388 // Note that the script oox/source/drawingml/customshapes/generatePresetsData.pl looks
389 // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs.
390 SAL_INFO("oox.cscode", "==cscode== begin");
391 aPropertyMap.dumpCode( aPropertyMap.makePropertySet() );
392 SAL_INFO("oox.cscode", "==cscode== end");
393 SAL_INFO("oox.csdata", "==csdata== begin");
394 aPropertyMap.dumpData( aPropertyMap.makePropertySet() );
395 SAL_INFO("oox.csdata", "==csdata== end");
396 #endif
397 // converting the vector to a sequence
398 Sequence< PropertyValue > aSeq = aPropertyMap.makePropertyValueSequence();
399 PropertySet aPropSet( xPropSet );
400 aPropSet.setProperty( PROP_CustomShapeGeometry, aSeq );
406 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */