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/drawingml/customshapeproperties.hxx" 25 #include "oox/helper/helper.hxx" 26 #include "oox/helper/propertymap.hxx" 27 #include "oox/helper/propertyset.hxx" 28 #include <com/sun/star/awt/Rectangle.hpp> 29 #include <com/sun/star/beans/XMultiPropertySet.hpp> 30 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 31 #include <com/sun/star/graphic/XGraphicTransformer.hpp> 32 #include <com/sun/star/drawing/XShape.hpp> 33 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> 34 35 using rtl::OUString; 36 using namespace ::oox::core; 37 using namespace ::com::sun::star; 38 using namespace ::com::sun::star::uno; 39 using namespace ::com::sun::star::beans; 40 using namespace ::com::sun::star::graphic; 41 using namespace ::com::sun::star::drawing; 42 43 namespace oox { namespace drawingml { 44 45 CustomShapeProperties::CustomShapeProperties() 46 : mbMirroredX ( sal_False ) 47 , mbMirroredY ( sal_False ) 48 , mnTextRotation(0) // #119920# Add missing extra text rotation 49 { 50 } 51 CustomShapeProperties::~CustomShapeProperties() 52 { 53 } 54 55 sal_Int32 CustomShapeProperties::SetCustomShapeGuideValue( std::vector< CustomShapeGuide >& rGuideList, const CustomShapeGuide& rGuide ) 56 { 57 sal_uInt32 nIndex = 0; 58 for( ; nIndex < rGuideList.size(); nIndex++ ) 59 { 60 if ( rGuideList[ nIndex ].maName == rGuide.maName ) 61 break; 62 } 63 if ( nIndex == rGuideList.size() ) 64 rGuideList.push_back( rGuide ); 65 return static_cast< sal_Int32 >( nIndex ); 66 } 67 68 // returns the index into the guidelist for a given formula name, 69 // if the return value is < 0 then the guide value could not be found 70 sal_Int32 CustomShapeProperties::GetCustomShapeGuideValue( const std::vector< CustomShapeGuide >& rGuideList, const rtl::OUString& rFormulaName ) 71 { 72 sal_Int32 nIndex = 0; 73 for( ; nIndex < static_cast< sal_Int32 >( rGuideList.size() ); nIndex++ ) 74 { 75 if ( rGuideList[ nIndex ].maName == rFormulaName ) 76 break; 77 } 78 if ( nIndex == static_cast< sal_Int32 >( rGuideList.size() ) ) 79 nIndex = -1; 80 return nIndex; 81 } 82 83 void CustomShapeProperties::apply( const CustomShapePropertiesPtr& /* rSourceCustomShapeProperties */ ) 84 { 85 // not sure if this needs to be implemented 86 } 87 88 bool setOrCreatePropertyValue( 89 uno::Sequence< beans::PropertyValue >& rPropSeq, 90 const OUString& rName, 91 const uno::Any& rAny) 92 { 93 const sal_Int32 nCount(rPropSeq.getLength()); 94 95 for(sal_Int32 a(0); a < nCount; a++) 96 { 97 beans::PropertyValue& rEntry = rPropSeq[a]; 98 99 if(rEntry.Name.equals(rName)) 100 { 101 rEntry.Value = rAny; 102 return false; 103 } 104 } 105 106 beans::PropertyValue aNewValue; 107 108 aNewValue.Name = rName; 109 aNewValue.Value = rAny; 110 111 rPropSeq.realloc(nCount + 1); 112 rPropSeq[nCount] = aNewValue; 113 114 return true; 115 } 116 117 void CustomShapeProperties::pushToPropSet( const ::oox::core::FilterBase& /* rFilterBase */, 118 const Reference < XPropertySet >& xPropSet, const Reference < XShape > & xShape ) const 119 { 120 if ( maShapePresetType.getLength() ) 121 { 122 //const uno::Reference < drawing::XShape > xShape( xPropSet, UNO_QUERY ); 123 Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY ); 124 const OUString sCustomShapeGeometry( RTL_CONSTASCII_USTRINGPARAM( "CustomShapeGeometry" ) ); 125 uno::Sequence< beans::PropertyValue > aGeoPropSeq; 126 uno::Any aGeoPropSet; 127 bool bValuesAdded(false); 128 129 if( xDefaulter.is() ) 130 { 131 xDefaulter->createCustomShapeDefaults( maShapePresetType ); 132 } 133 134 if(mbMirroredX || mbMirroredY || mnTextRotation) 135 { 136 // #121371# set these values, but do *not* set a completely new 137 // "CustomShapeGeometry", this would reset the evtl. already created 138 // "Type" entry 139 aGeoPropSet = xPropSet->getPropertyValue(sCustomShapeGeometry); 140 141 if(aGeoPropSet >>= aGeoPropSeq) 142 { 143 uno::Any aAny; 144 145 if(mbMirroredX) // TTTT: remove again after aw080, make it part of object transformation 146 { 147 const rtl::OUString sMirroredX(RTL_CONSTASCII_USTRINGPARAM("MirroredX")); 148 aAny <<= mbMirroredX; 149 bValuesAdded = setOrCreatePropertyValue(aGeoPropSeq, sMirroredX, aAny); 150 } 151 152 if(mbMirroredY) // TTTT: remove again after aw080, make it part of object transformation 153 { 154 const rtl::OUString sMirroredY(RTL_CONSTASCII_USTRINGPARAM("MirroredY")); 155 aAny <<= mbMirroredY; 156 bValuesAdded = setOrCreatePropertyValue(aGeoPropSeq, sMirroredY, aAny); 157 } 158 159 if(mnTextRotation) 160 { 161 const rtl::OUString sTextRotateAngle(RTL_CONSTASCII_USTRINGPARAM("TextRotateAngle")); 162 aAny <<= (double)mnTextRotation; 163 bValuesAdded = setOrCreatePropertyValue(aGeoPropSeq, sTextRotateAngle, aAny); 164 } 165 } 166 } 167 168 if ( maAdjustmentGuideList.size() ) 169 { 170 if(!aGeoPropSeq.getLength()) 171 { 172 aGeoPropSet = xPropSet->getPropertyValue( sCustomShapeGeometry ); 173 aGeoPropSet >>= aGeoPropSeq; 174 } 175 176 sal_Int32 i, nCount = aGeoPropSeq.getLength(); 177 178 for ( i = 0; i < nCount; i++ ) 179 { 180 const rtl::OUString sAdjustmentValues( RTL_CONSTASCII_USTRINGPARAM( "AdjustmentValues" ) ); 181 const OUString sType = CREATE_OUSTRING( "Type" ); 182 183 if ( aGeoPropSeq[ i ].Name.equals( sAdjustmentValues ) ) 184 { 185 uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq; 186 if ( aGeoPropSeq[ i ].Value >>= aAdjustmentSeq ) 187 { 188 std::vector< CustomShapeGuide >::const_iterator aIter( maAdjustmentGuideList.begin() ); 189 while( aIter != maAdjustmentGuideList.end() ) 190 { 191 if ( (*aIter).maName.getLength() > 3 ) 192 { 193 sal_Int32 nAdjustmentIndex = (*aIter).maName.copy( 3 ).toInt32() - 1; 194 if ( ( nAdjustmentIndex >= 0 ) && ( nAdjustmentIndex < aAdjustmentSeq.getLength() ) ) 195 { 196 EnhancedCustomShapeAdjustmentValue aAdjustmentVal; 197 aAdjustmentVal.Value <<= (*aIter).maFormula.toInt32(); 198 aAdjustmentVal.State = PropertyState_DIRECT_VALUE; 199 aAdjustmentSeq[ nAdjustmentIndex ] = aAdjustmentVal; 200 } 201 } 202 aIter++; 203 } 204 aGeoPropSeq[ i ].Value <<= aAdjustmentSeq; 205 xPropSet->setPropertyValue( sCustomShapeGeometry, Any( aGeoPropSeq ) ); 206 } 207 } 208 else if ( aGeoPropSeq[ i ].Name.equals( sType ) ) 209 { 210 aGeoPropSeq[ i ].Value <<= maShapePresetType; 211 } 212 } 213 } 214 215 if(bValuesAdded) 216 { 217 aGeoPropSet <<= aGeoPropSeq; 218 xPropSet->setPropertyValue(sCustomShapeGeometry, aGeoPropSet); 219 } 220 } 221 else 222 { 223 sal_uInt32 i; 224 PropertyMap aPropertyMap; 225 aPropertyMap[ PROP_Type ] <<= CREATE_OUSTRING( "non-primitive" ); 226 aPropertyMap[ PROP_MirroredX ] <<= Any( mbMirroredX ); 227 aPropertyMap[ PROP_MirroredY ] <<= Any( mbMirroredY ); 228 229 if(mnTextRotation) 230 { 231 aPropertyMap[ PROP_TextRotation ] <<= Any(mnTextRotation); 232 } 233 234 awt::Size aSize( xShape->getSize() ); 235 awt::Rectangle aViewBox( 0, 0, aSize.Width * 360, aSize.Height * 360 ); 236 if ( maPath2DList.size() ) 237 { // TODO: each polygon may have its own size, but I think it is rather been used 238 // so we are only taking care of the first 239 if ( maPath2DList[ 0 ].w ) 240 aViewBox.Width = static_cast< sal_Int32 >( maPath2DList[ 0 ].w ); 241 if ( maPath2DList[ 0 ].h ) 242 aViewBox.Height = static_cast< sal_Int32 >( maPath2DList[ 0 ].h ); 243 } 244 aPropertyMap[ PROP_ViewBox ] <<= aViewBox; 245 246 Sequence< EnhancedCustomShapeAdjustmentValue > aAdjustmentValues( maAdjustmentGuideList.size() ); 247 for ( i = 0; i < maAdjustmentGuideList.size(); i++ ) 248 { 249 EnhancedCustomShapeAdjustmentValue aAdjustmentVal; 250 aAdjustmentVal.Value <<= maAdjustmentGuideList[ i ].maFormula.toInt32(); 251 aAdjustmentVal.State = PropertyState_DIRECT_VALUE; 252 aAdjustmentValues[ i ] = aAdjustmentVal; 253 } 254 aPropertyMap[ PROP_AdjustmentValues ] <<= aAdjustmentValues; 255 256 Sequence< rtl::OUString > aEquations( maGuideList.size() ); 257 for ( i = 0; i < maGuideList.size(); i++ ) 258 aEquations[ i ] = maGuideList[ i ].maFormula; 259 aPropertyMap[ PROP_Equations ] <<= aEquations; 260 261 PropertyMap aPath; 262 Sequence< EnhancedCustomShapeSegment > aSegments( maSegments.size() ); 263 for ( i = 0; i < maSegments.size(); i++ ) 264 aSegments[ i ] = maSegments[ i ]; 265 aPath[ PROP_Segments ] <<= aSegments; 266 sal_uInt32 j, k, nParameterPairs = 0; 267 for ( i = 0; i < maPath2DList.size(); i++ ) 268 nParameterPairs += maPath2DList[ i ].parameter.size(); 269 Sequence< EnhancedCustomShapeParameterPair > aParameterPairs( nParameterPairs ); 270 for ( i = 0, k = 0; i < maPath2DList.size(); i++ ) 271 for ( j = 0; j < maPath2DList[ i ].parameter.size(); j++ ) 272 aParameterPairs[ k++ ] = maPath2DList[ i ].parameter[ j ]; 273 aPath[ PROP_Coordinates ] <<= aParameterPairs; 274 Sequence< PropertyValue > aPathSequence = aPath.makePropertyValueSequence(); 275 aPropertyMap[ PROP_Path ] <<= aPathSequence; 276 277 Sequence< PropertyValues > aHandles( maAdjustHandleList.size() ); 278 for ( i = 0; i < maAdjustHandleList.size(); i++ ) 279 { 280 PropertyMap aHandle; 281 // maAdjustmentHandle[ i ].gdRef1 ... maAdjustmentHandle[ i ].gdRef2 ... :( 282 // gdRef1 && gdRef2 -> we do not offer such reference, so it is difficult 283 // to determine the correct adjustment handle that should be updated with the adjustment 284 // position. here is the solution: the adjustment value that is used within the position 285 // has to be updated, in case the position is a formula the first usage of a 286 // adjument value is decisive 287 if ( maAdjustHandleList[ i ].polar ) 288 { 289 aHandle[ PROP_Position ] <<= maAdjustHandleList[ i ].pos; 290 if ( maAdjustHandleList[ i ].min1.has() ) 291 aHandle[ PROP_RadiusRangeMinimum ] <<= maAdjustHandleList[ i ].min1.get(); 292 if ( maAdjustHandleList[ i ].max1.has() ) 293 aHandle[ PROP_RadiusRangeMaximum ] <<= maAdjustHandleList[ i ].max1.get(); 294 295 /* TODO: AngleMin & AngleMax 296 if ( maAdjustHandleList[ i ].min2.has() ) 297 aHandle[ PROP_ ] = maAdjustHandleList[ i ].min2.get(); 298 if ( maAdjustHandleList[ i ].max2.has() ) 299 aHandle[ PROP_ ] = maAdjustHandleList[ i ].max2.get(); 300 */ 301 } 302 else 303 { 304 aHandle[ PROP_Position ] <<= maAdjustHandleList[ i ].pos; 305 if ( maAdjustHandleList[ i ].gdRef1.has() ) 306 { 307 // TODO: PROP_RefX and PROP_RefY are not yet part of our file format, 308 // so the handles will not work after save/reload 309 sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef1.get() ); 310 if ( nIndex >= 0 ) 311 aHandle[ PROP_RefX ] <<= nIndex; 312 } 313 if ( maAdjustHandleList[ i ].gdRef2.has() ) 314 { 315 sal_Int32 nIndex = GetCustomShapeGuideValue( maAdjustmentGuideList, maAdjustHandleList[ i ].gdRef2.get() ); 316 if ( nIndex >= 0 ) 317 aHandle[ PROP_RefY ] <<= nIndex; 318 } 319 if ( maAdjustHandleList[ i ].min1.has() ) 320 aHandle[ PROP_RangeXMinimum ] <<= maAdjustHandleList[ i ].min1.get(); 321 if ( maAdjustHandleList[ i ].max1.has() ) 322 aHandle[ PROP_RangeXMaximum ] <<= maAdjustHandleList[ i ].max1.get(); 323 if ( maAdjustHandleList[ i ].min2.has() ) 324 aHandle[ PROP_RangeYMinimum ] <<= maAdjustHandleList[ i ].min2.get(); 325 if ( maAdjustHandleList[ i ].max2.has() ) 326 aHandle[ PROP_RangeYMaximum ] <<= maAdjustHandleList[ i ].max2.get(); 327 } 328 aHandles[ i ] = aHandle.makePropertyValueSequence(); 329 } 330 aPropertyMap[ PROP_Handles ] <<= aHandles; 331 332 // converting the vector to a sequence 333 Sequence< PropertyValue > aSeq = aPropertyMap.makePropertyValueSequence(); 334 PropertySet aPropSet( xPropSet ); 335 aPropSet.setProperty( PROP_CustomShapeGeometry, aSeq ); 336 } 337 } 338 339 double CustomShapeProperties::getValue( const std::vector< CustomShapeGuide >& rGuideList, sal_uInt32 nIndex ) const 340 { 341 double fRet = 0.0; 342 if ( nIndex < rGuideList.size() ) 343 { 344 345 } 346 return fRet; 347 } 348 349 } } 350