Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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 <basegfx/numeric/ftools.hxx>
34 :
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;
41 :
42 : # define USS(x) OUStringToOString( x, RTL_TEXTENCODING_UTF8 ).getStr()
43 :
44 : namespace oox { namespace drawingml {
45 :
46 22440 : CustomShapeProperties::CustomShapeProperties()
47 : : mnShapePresetType ( -1 )
48 : , mbShapeTypeOverride(false)
49 : , mbMirroredX ( false )
50 : , mbMirroredY ( false )
51 : , mnTextRotateAngle ( 0 )
52 22440 : , mnArcNum ( 0 )
53 : {
54 22440 : }
55 45756 : CustomShapeProperties::~CustomShapeProperties()
56 : {
57 45756 : }
58 :
59 0 : uno::Sequence< sal_Int8 > CustomShapeProperties::getShapePresetTypeName() const
60 : {
61 0 : return StaticTokenMap::get().getUtf8TokenName( mnShapePresetType );
62 : }
63 :
64 8092 : sal_Int32 CustomShapeProperties::SetCustomShapeGuideValue( std::vector< CustomShapeGuide >& rGuideList, const CustomShapeGuide& rGuide )
65 : {
66 8092 : sal_uInt32 nIndex = 0;
67 150720 : for( ; nIndex < rGuideList.size(); nIndex++ )
68 : {
69 146986 : if ( rGuideList[ nIndex ].maName == rGuide.maName )
70 4358 : break;
71 : }
72 8092 : if ( nIndex == rGuideList.size() )
73 3734 : rGuideList.push_back( rGuide );
74 8092 : return static_cast< sal_Int32 >( nIndex );
75 : }
76 :
77 : // returns the index into the guidelist for a given formula name,
78 : // if the return value is < 0 then the guide value could not be found
79 39214 : sal_Int32 CustomShapeProperties::GetCustomShapeGuideValue( const std::vector< CustomShapeGuide >& rGuideList, const OUString& rFormulaName )
80 : {
81 : // traverse the list from the end, because guide names can be reused
82 : // and current is the last one
83 : // see a1 guide in gear6 custom shape preset as example
84 39214 : sal_Int32 nIndex = static_cast< sal_Int32 >( rGuideList.size() ) - 1;
85 417768 : for( ; nIndex >= 0; nIndex-- )
86 : {
87 398724 : if ( rGuideList[ nIndex ].maName == rFormulaName )
88 20170 : break;
89 : }
90 :
91 39214 : return nIndex;
92 : }
93 :
94 136 : CustomShapeProperties::PresetDataMap CustomShapeProperties::maPresetDataMap;
95 :
96 2954 : static OUString GetConnectorShapeType( sal_Int32 nType )
97 : {
98 : OSL_TRACE("GetConnectorShapeType preset: %d %d", nType, XML_straightConnector1);
99 :
100 2954 : OUString sType;
101 2954 : switch( nType )
102 : {
103 : case XML_straightConnector1:
104 324 : sType = "mso-spt32";
105 324 : break;
106 : default:
107 2630 : break;
108 : }
109 2954 : return sType;
110 : }
111 :
112 3680 : void CustomShapeProperties::pushToPropSet( const ::oox::core::FilterBase& /* rFilterBase */,
113 : const Reference < XPropertySet >& xPropSet, const Reference < XShape > & xShape, const awt::Size &aSize )
114 : {
115 3680 : if ( mnShapePresetType >= 0 )
116 : {
117 : OSL_TRACE("preset: %d", mnShapePresetType);
118 :
119 2954 : if (maPresetDataMap.empty())
120 26 : initializePresetDataMap();
121 :
122 2954 : PropertyMap aPropertyMap;
123 5908 : PropertySet aPropSet( xPropSet );
124 :
125 5908 : OUString sConnectorShapeType = GetConnectorShapeType( mnShapePresetType );
126 :
127 2954 : if (sConnectorShapeType.getLength() > 0)
128 : {
129 : OSL_TRACE("connector shape: %s (%d)", USS(sConnectorShapeType), mnShapePresetType);
130 : //const uno::Reference < drawing::XShape > xShape( xPropSet, UNO_QUERY );
131 324 : Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY );
132 324 : if( xDefaulter.is() ) {
133 324 : xDefaulter->createCustomShapeDefaults( sConnectorShapeType );
134 324 : aPropertyMap.setProperty( PROP_Type, sConnectorShapeType );
135 324 : }
136 : }
137 2630 : else if (maPresetDataMap.find(mnShapePresetType) != maPresetDataMap.end())
138 : {
139 : OSL_TRACE("found property map for preset: %d", mnShapePresetType);
140 :
141 2630 : aPropertyMap = maPresetDataMap[mnShapePresetType];
142 : #ifdef DEBUG
143 : aPropertyMap.dumpCode();
144 : #endif
145 : }
146 :
147 2954 : aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
148 2954 : aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
149 2954 : aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextRotateAngle );
150 2954 : aPropertyMap.setProperty( PROP_IsPostRotateAngle, true); // For OpenXML Imports
151 5908 : Sequence< PropertyValue > aSeq = aPropertyMap.makePropertyValueSequence();
152 2954 : aPropSet.setProperty( PROP_CustomShapeGeometry, aSeq );
153 :
154 5908 : const OUString sCustomShapeGeometry("CustomShapeGeometry");
155 5908 : uno::Any aGeoPropSet = xPropSet->getPropertyValue( sCustomShapeGeometry );
156 5908 : uno::Sequence< beans::PropertyValue > aGeoPropSeq;
157 :
158 2954 : sal_Int32 i, nCount = 0;
159 2954 : if (aGeoPropSet >>= aGeoPropSeq)
160 : {
161 2954 : nCount = aGeoPropSeq.getLength();
162 31846 : for ( i = 0; i < nCount; i++ )
163 : {
164 28892 : const OUString sAdjustmentValues("AdjustmentValues");
165 28892 : if ( aGeoPropSeq[ i ].Name.equals( sAdjustmentValues ) )
166 : {
167 2954 : OUString presetTextWarp;
168 2954 : if ( aGeoPropSeq[ i ].Value >>= presetTextWarp )
169 : {
170 0 : aPropertyMap.setProperty( PROP_PresetTextWarp, Any( presetTextWarp ) );
171 2954 : }
172 : }
173 28892 : }
174 : }
175 :
176 2954 : if ( maAdjustmentGuideList.size() )
177 : {
178 450 : const OUString sType = "Type";
179 450 : if ( aGeoPropSet >>= aGeoPropSeq )
180 : {
181 450 : nCount = aGeoPropSeq.getLength();
182 4950 : for ( i = 0; i < nCount; i++ )
183 : {
184 4500 : const OUString sAdjustmentValues("AdjustmentValues");
185 4500 : if ( aGeoPropSeq[ i ].Name.equals( sAdjustmentValues ) )
186 : {
187 450 : uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq;
188 450 : if ( aGeoPropSeq[ i ].Value >>= aAdjustmentSeq )
189 : {
190 450 : int nIndex=0;
191 1050 : for (std::vector< CustomShapeGuide >::const_iterator aIter( maAdjustmentGuideList.begin() ), aEnd(maAdjustmentGuideList.end());
192 : aIter != aEnd; ++aIter)
193 : {
194 600 : if ( (*aIter).maName.getLength() > 3 )
195 : {
196 224 : sal_Int32 nAdjustmentIndex = (*aIter).maName.copy( 3 ).toInt32() - 1;
197 224 : if ( ( nAdjustmentIndex >= 0 ) && ( nAdjustmentIndex < aAdjustmentSeq.getLength() ) )
198 : {
199 224 : EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
200 224 : aAdjustmentVal.Value <<= (*aIter).maFormula.toInt32();
201 224 : aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
202 224 : aAdjustmentVal.Name = (*aIter).maName;
203 224 : aAdjustmentSeq[ nAdjustmentIndex ] = aAdjustmentVal;
204 : }
205 376 : } else if ( aAdjustmentSeq.getLength() > 0 ) {
206 376 : EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
207 :
208 376 : sal_Int32 nValue((*aIter).maFormula.toInt32());
209 :
210 : // #i124703# The ms control point coordinates are relative to the
211 : // object center in the range [-50000 .. 50000] while our customshapes
212 : // use a range from [0 .. 21600], so adapt the value as needed
213 376 : nValue = basegfx::fround((double(nValue) + 50000.0) * (21600.0 / 100000.0));
214 :
215 376 : aAdjustmentVal.Value <<= nValue;
216 376 : aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
217 376 : aAdjustmentVal.Name = (*aIter).maName;
218 376 : aAdjustmentSeq[ nIndex++ ] = aAdjustmentVal;
219 : }
220 : }
221 450 : aGeoPropSeq[ i ].Value <<= aAdjustmentSeq;
222 450 : xPropSet->setPropertyValue( sCustomShapeGeometry, Any( aGeoPropSeq ) );
223 450 : }
224 : }
225 4050 : else if ( aGeoPropSeq[ i ].Name.equals( sType ) )
226 : {
227 450 : if ( sConnectorShapeType.getLength() > 0 )
228 0 : aGeoPropSeq[ i ].Value <<= sConnectorShapeType;
229 : else
230 450 : aGeoPropSeq[ i ].Value <<= OUString( "ooxml-CustomShape" );
231 : }
232 4500 : }
233 450 : }
234 2954 : }
235 : }
236 : else
237 : {
238 : sal_uInt32 i;
239 726 : PropertyMap aPropertyMap;
240 726 : aPropertyMap.setProperty( PROP_Type, OUString( "ooxml-non-primitive" ));
241 726 : aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
242 726 : aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
243 : // Note 1: If Equations are defined - they are processed using internal div by 360 coordinates
244 : // while if they are not, standard ooxml coordinates are used.
245 : // This size specifically affects scaling.
246 : // Note 2: Width and Height are set to 0 to force scaling to 1.
247 726 : awt::Rectangle aViewBox( 0, 0, aSize.Width, aSize.Height );
248 726 : if( maGuideList.size() )
249 610 : aViewBox = awt::Rectangle( 0, 0, 0, 0 );
250 726 : aPropertyMap.setProperty( PROP_ViewBox, aViewBox);
251 :
252 1452 : Sequence< EnhancedCustomShapeAdjustmentValue > aAdjustmentValues( maAdjustmentGuideList.size() );
253 1322 : for ( i = 0; i < maAdjustmentGuideList.size(); i++ )
254 : {
255 596 : EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
256 596 : aAdjustmentVal.Value <<= maAdjustmentGuideList[ i ].maFormula.toInt32();
257 596 : aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
258 596 : aAdjustmentVal.Name = maAdjustmentGuideList[ i ].maName;
259 596 : aAdjustmentValues[ i ] = aAdjustmentVal;
260 596 : }
261 726 : aPropertyMap.setProperty( PROP_AdjustmentValues, aAdjustmentValues);
262 :
263 1452 : PropertyMap aPath;
264 :
265 1452 : Sequence< EnhancedCustomShapeSegment > aSegments( maSegments.size() );
266 6928 : for ( i = 0; i < maSegments.size(); i++ )
267 6202 : aSegments[ i ] = maSegments[ i ];
268 726 : aPath.setProperty( PROP_Segments, aSegments);
269 :
270 726 : if ( maTextRect.has() ) {
271 726 : Sequence< EnhancedCustomShapeTextFrame > aTextFrames(1);
272 726 : aTextFrames[0].TopLeft.First = maTextRect.get().l;
273 726 : aTextFrames[0].TopLeft.Second = maTextRect.get().t;
274 726 : aTextFrames[0].BottomRight.First = maTextRect.get().r;
275 726 : aTextFrames[0].BottomRight.Second = maTextRect.get().b;
276 726 : aPath.setProperty( PROP_TextFrames, aTextFrames);
277 : }
278 :
279 726 : sal_uInt32 j, k, nParameterPairs = 0;
280 1794 : for ( i = 0; i < maPath2DList.size(); i++ )
281 1068 : nParameterPairs += maPath2DList[ i ].parameter.size();
282 :
283 1452 : Sequence< EnhancedCustomShapeParameterPair > aParameterPairs( nParameterPairs );
284 1794 : for ( i = 0, k = 0; i < maPath2DList.size(); i++ )
285 11736 : for ( j = 0; j < maPath2DList[ i ].parameter.size(); j++ )
286 10668 : aParameterPairs[ k++ ] = maPath2DList[ i ].parameter[ j ];
287 726 : aPath.setProperty( PROP_Coordinates, aParameterPairs);
288 :
289 726 : if ( maPath2DList.size() )
290 : {
291 726 : bool bAllZero = true;
292 1368 : for ( i=0; i < maPath2DList.size(); i++ )
293 : {
294 948 : if ( maPath2DList[i].w || maPath2DList[i].h ) {
295 306 : bAllZero = false;
296 306 : break;
297 : }
298 : }
299 :
300 726 : if ( !bAllZero ) {
301 306 : Sequence< awt::Size > aSubViewSize( maPath2DList.size() );
302 732 : for ( i=0; i < maPath2DList.size(); i++ )
303 : {
304 426 : aSubViewSize[i].Width = static_cast< sal_Int32 >( maPath2DList[i].w );
305 426 : aSubViewSize[i].Height = static_cast< sal_Int32 >( maPath2DList[i].h );
306 : OSL_TRACE("set subpath %d size: %d x %d", i, maPath2DList[i].w, maPath2DList[i].h);
307 : }
308 306 : aPath.setProperty( PROP_SubViewSize, aSubViewSize);
309 : }
310 : }
311 :
312 1452 : Sequence< PropertyValue > aPathSequence = aPath.makePropertyValueSequence();
313 726 : aPropertyMap.setProperty( PROP_Path, aPathSequence);
314 :
315 1452 : Sequence< OUString > aEquations( maGuideList.size() );
316 12262 : for ( i = 0; i < maGuideList.size(); i++ )
317 11536 : aEquations[ i ] = maGuideList[ i ].maFormula;
318 726 : aPropertyMap.setProperty( PROP_Equations, aEquations);
319 :
320 1452 : Sequence< PropertyValues > aHandles( maAdjustHandleList.size() );
321 1208 : for ( i = 0; i < maAdjustHandleList.size(); i++ )
322 : {
323 482 : PropertyMap aHandle;
324 : // maAdjustmentHandle[ i ].gdRef1 ... maAdjustmentHandle[ i ].gdRef2 ... :(
325 : // gdRef1 && gdRef2 -> we do not offer such reference, so it is difficult
326 : // to determine the correct adjustment handle that should be updated with the adjustment
327 : // position. here is the solution: the adjustment value that is used within the position
328 : // has to be updated, in case the position is a formula the first usage of a
329 : // adjustment value is decisive
330 482 : if ( maAdjustHandleList[ i ].polar )
331 : {
332 46 : aHandle.setProperty( PROP_Position, maAdjustHandleList[ i ].pos);
333 46 : if ( maAdjustHandleList[ i ].min1.has() )
334 0 : aHandle.setProperty( PROP_RadiusRangeMinimum, maAdjustHandleList[ i ].min1.get());
335 46 : if ( maAdjustHandleList[ i ].max1.has() )
336 18 : aHandle.setProperty( PROP_RadiusRangeMaximum, maAdjustHandleList[ i ].max1.get());
337 :
338 : /* TODO: AngleMin & AngleMax
339 : if ( maAdjustHandleList[ i ].min2.has() )
340 : aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].min2.get());
341 : if ( maAdjustHandleList[ i ].max2.has() )
342 : aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].max2.get());
343 : */
344 : }
345 : else
346 : {
347 436 : aHandle.setProperty( PROP_Position, maAdjustHandleList[ i ].pos);
348 436 : if ( maAdjustHandleList[ i ].gdRef1.has() )
349 : {
350 : // TODO: PROP_RefX and PROP_RefY are not yet part of our file format,
351 : // so the handles will not work after save/reload
352 262 : sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef1.get() );
353 262 : if ( nIndex >= 0 )
354 262 : aHandle.setProperty( PROP_RefX, nIndex);
355 : }
356 436 : if ( maAdjustHandleList[ i ].gdRef2.has() )
357 : {
358 254 : sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef2.get() );
359 254 : if ( nIndex >= 0 )
360 254 : aHandle.setProperty( PROP_RefY, nIndex);
361 : }
362 436 : if ( maAdjustHandleList[ i ].min1.has() )
363 112 : aHandle.setProperty( PROP_RangeXMinimum, maAdjustHandleList[ i ].min1.get());
364 436 : if ( maAdjustHandleList[ i ].max1.has() )
365 262 : aHandle.setProperty( PROP_RangeXMaximum, maAdjustHandleList[ i ].max1.get());
366 436 : if ( maAdjustHandleList[ i ].min2.has() )
367 102 : aHandle.setProperty( PROP_RangeYMinimum, maAdjustHandleList[ i ].min2.get());
368 436 : if ( maAdjustHandleList[ i ].max2.has() )
369 254 : aHandle.setProperty( PROP_RangeYMaximum, maAdjustHandleList[ i ].max2.get());
370 : }
371 482 : aHandles[ i ] = aHandle.makePropertyValueSequence();
372 482 : }
373 726 : aPropertyMap.setProperty( PROP_Handles, aHandles);
374 :
375 : #ifdef DEBUG
376 : SAL_INFO("oox.cscode", "==cscode== begin");
377 : aPropertyMap.dumpCode();
378 : SAL_INFO("oox.cscode", "==cscode== end");
379 : SAL_INFO("oox.csdata", "==csdata== begin");
380 : aPropertyMap.dumpData();
381 : SAL_INFO("oox.csdata", "==csdata== end");
382 : #endif
383 : // converting the vector to a sequence
384 1452 : Sequence< PropertyValue > aSeq = aPropertyMap.makePropertyValueSequence();
385 1452 : PropertySet aPropSet( xPropSet );
386 1452 : aPropSet.setProperty( PROP_CustomShapeGeometry, aSeq );
387 : }
388 3680 : }
389 :
390 408 : } }
391 :
392 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|