1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmloff.hxx" 30 31 #include "SchXMLTools.hxx" 32 33 /* 34 #include <tools/debug.hxx> 35 */ 36 #include <rtl/ustrbuf.hxx> 37 #include <comphelper/InlineContainer.hxx> 38 // header for class SvXMLUnitConverter 39 #include <xmloff/xmluconv.hxx> 40 // header for struct SvXMLEnumMapEntry 41 #include <xmloff/xmlement.hxx> 42 // header for define __FAR_DATA 43 #include <tools/solar.h> 44 45 // header for class SvXMLImportPropertyMapper 46 #include <xmloff/xmlimppr.hxx> 47 // header for class XMLPropStyleContext 48 #include <xmloff/prstylei.hxx> 49 // header for class XMLPropertySetMapper 50 #include <xmloff/xmlprmap.hxx> 51 #include <xmloff/xmlexp.hxx> 52 #include "xmloff/xmlnmspe.hxx" 53 #include <xmloff/xmlmetai.hxx> 54 55 #include <com/sun/star/beans/PropertyAttribute.hpp> 56 #include <com/sun/star/uno/XComponentContext.hpp> 57 #include <com/sun/star/chart2/data/XDataProvider.hpp> 58 #include <com/sun/star/chart2/data/XDataReceiver.hpp> 59 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> 60 #include <com/sun/star/chart2/XChartDocument.hpp> 61 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> 62 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp> 63 #include <com/sun/star/container/XChild.hpp> 64 #include <com/sun/star/document/XDocumentProperties.hpp> 65 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> 66 #include <com/sun/star/lang/XServiceName.hpp> 67 68 #include <comphelper/processfactory.hxx> 69 70 using namespace com::sun::star; 71 using namespace ::xmloff::token; 72 73 using ::rtl::OUString; 74 using ::rtl::OUStringBuffer; 75 using ::com::sun::star::uno::Reference; 76 using ::com::sun::star::uno::Sequence; 77 78 namespace 79 { 80 Reference< uno::XComponentContext > lcl_getComponentContext() 81 { 82 Reference< uno::XComponentContext > xContext; 83 try 84 { 85 Reference< beans::XPropertySet > xFactProp( comphelper::getProcessServiceFactory(), uno::UNO_QUERY ); 86 if( xFactProp.is()) 87 xFactProp->getPropertyValue(OUString::createFromAscii("DefaultContext")) >>= xContext; 88 } 89 catch( uno::Exception& ) 90 {} 91 92 return xContext; 93 } 94 95 rtl::OUString lcl_getGeneratorFromModel( const uno::Reference< frame::XModel >& xChartModel ) 96 { 97 ::rtl::OUString aGenerator; 98 uno::Reference< document::XDocumentPropertiesSupplier> xChartDocumentPropertiesSupplier( xChartModel, uno::UNO_QUERY ); 99 if( xChartDocumentPropertiesSupplier.is() ) 100 { 101 uno::Reference< document::XDocumentProperties > xChartDocumentProperties( 102 xChartDocumentPropertiesSupplier->getDocumentProperties()); 103 if( xChartDocumentProperties.is() ) 104 aGenerator = xChartDocumentProperties->getGenerator(); 105 } 106 return aGenerator; 107 } 108 109 rtl::OUString lcl_getGeneratorFromModelOrItsParent( const uno::Reference< frame::XModel >& xChartModel ) 110 { 111 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); 112 if( !aGenerator.getLength() ) //try to get the missing info from the parent document 113 { 114 uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); 115 if( xChild.is() ) 116 aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) ); 117 } 118 return aGenerator; 119 } 120 121 sal_Int32 lcl_getBuildIDFromGenerator( const ::rtl::OUString& rGenerator ) 122 { 123 //returns -1 if nothing found 124 sal_Int32 nBuildId = -1; 125 const OUString sBuildCompare( RTL_CONSTASCII_USTRINGPARAM( "$Build-" ) ); 126 sal_Int32 nEnd = -1; 127 sal_Int32 nBegin = rGenerator.indexOf( sBuildCompare, nEnd ); 128 if( nBegin != -1 ) 129 { 130 OUString sBuildId( rGenerator.copy( nBegin + sBuildCompare.getLength() ) ); 131 nBuildId = sBuildId.toInt32(); 132 } 133 return nBuildId; 134 } 135 136 OUString lcl_ConvertRange( const ::rtl::OUString & rRange, const Reference< chart2::data::XDataProvider >& xDataProvider ) 137 { 138 OUString aResult = rRange; 139 Reference< chart2::data::XRangeXMLConversion > xRangeConversion( xDataProvider, uno::UNO_QUERY ); 140 if( xRangeConversion.is()) 141 aResult = xRangeConversion->convertRangeFromXML( rRange ); 142 return aResult; 143 } 144 145 Reference< chart2::data::XDataSequence > lcl_createNewSequenceFromCachedXMLRange( const Reference< chart2::data::XDataSequence >& xSeq, const Reference< chart2::data::XDataProvider >& xDataProvider ) 146 { 147 Reference< chart2::data::XDataSequence > xRet; 148 OUString aRange; 149 if( xSeq.is() && SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) ) 150 { 151 xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( 152 lcl_ConvertRange( aRange, xDataProvider )) ); 153 SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), 154 Reference< beans::XPropertySet >( xRet, uno::UNO_QUERY )); 155 } 156 return xRet; 157 } 158 159 } // anonymous namespace 160 161 // ---------------------------------------- 162 163 namespace SchXMLTools 164 { 165 166 static __FAR_DATA SvXMLEnumMapEntry aXMLChartClassMap[] = 167 { 168 { XML_LINE, XML_CHART_CLASS_LINE }, 169 { XML_AREA, XML_CHART_CLASS_AREA }, 170 { XML_CIRCLE, XML_CHART_CLASS_CIRCLE }, 171 { XML_RING, XML_CHART_CLASS_RING }, 172 { XML_SCATTER, XML_CHART_CLASS_SCATTER }, 173 { XML_RADAR, XML_CHART_CLASS_RADAR }, 174 { XML_FILLED_RADAR, XML_CHART_CLASS_FILLED_RADAR }, 175 { XML_BAR, XML_CHART_CLASS_BAR }, 176 { XML_STOCK, XML_CHART_CLASS_STOCK }, 177 { XML_BUBBLE, XML_CHART_CLASS_BUBBLE }, 178 { XML_SURFACE, XML_CHART_CLASS_BAR }, //@todo change this if a surface chart is available 179 { XML_ADD_IN, XML_CHART_CLASS_ADDIN }, 180 { XML_TOKEN_INVALID, XML_CHART_CLASS_UNKNOWN } 181 }; 182 183 SchXMLChartTypeEnum GetChartTypeEnum( const OUString& rClassName ) 184 { 185 sal_uInt16 nEnumVal = XML_CHART_CLASS_UNKNOWN; 186 if( !SvXMLUnitConverter::convertEnum( 187 nEnumVal, rClassName, aXMLChartClassMap ) ) 188 nEnumVal = XML_CHART_CLASS_UNKNOWN; 189 return SchXMLChartTypeEnum(nEnumVal); 190 } 191 192 typedef ::comphelper::MakeMap< ::rtl::OUString, ::rtl::OUString > tMakeStringStringMap; 193 //static 194 const tMakeStringStringMap& lcl_getChartTypeNameMap() 195 { 196 //shape property -- chart model object property 197 static tMakeStringStringMap g_aChartTypeNameMap = 198 tMakeStringStringMap 199 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.LineDiagram" ) 200 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.LineChartType" ) ) 201 202 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.AreaDiagram" ) 203 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.AreaChartType" ) ) 204 205 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.BarDiagram" ) 206 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.ColumnChartType" ) ) 207 208 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.PieDiagram" ) 209 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.PieChartType" ) ) 210 211 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.DonutDiagram" ) 212 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.DonutChartType" ) ) 213 214 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.XYDiagram" ) 215 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.ScatterChartType" ) ) 216 217 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.NetDiagram" ) 218 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.NetChartType" ) ) 219 220 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.FilledNetDiagram" ) 221 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.FilledNetChartType" ) ) 222 223 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.StockDiagram" ) 224 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.CandleStickChartType" ) ) 225 226 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.BubbleDiagram" ) 227 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.BubbleChartType" ) ) 228 229 ; 230 return g_aChartTypeNameMap; 231 } 232 233 234 OUString GetNewChartTypeName( const OUString & rOldChartTypeName ) 235 { 236 OUString aNew(rOldChartTypeName); 237 238 const tMakeStringStringMap& rMap = lcl_getChartTypeNameMap(); 239 tMakeStringStringMap::const_iterator aIt( rMap.find( rOldChartTypeName )); 240 if( aIt != rMap.end()) 241 { 242 aNew = aIt->second; 243 } 244 return aNew; 245 } 246 247 OUString GetChartTypeByClassName( 248 const OUString & rClassName, bool bUseOldNames ) 249 { 250 OUStringBuffer aResultBuffer; 251 bool bInternalType = false; 252 253 if( bUseOldNames ) 254 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart.")); 255 else 256 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2.")); 257 258 bInternalType = true; 259 260 if( IsXMLToken( rClassName, XML_LINE )) 261 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Line")); 262 else if( IsXMLToken( rClassName, XML_AREA )) 263 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Area")); 264 else if( IsXMLToken( rClassName, XML_BAR )) 265 { 266 if( bUseOldNames ) 267 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Bar")); 268 else 269 { 270 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Column")); 271 // @todo: might be Bar 272 } 273 } 274 else if( IsXMLToken( rClassName, XML_CIRCLE )) 275 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Pie")); 276 else if( IsXMLToken( rClassName, XML_RING )) 277 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Donut")); 278 else if( IsXMLToken( rClassName, XML_SCATTER )) 279 { 280 if( bUseOldNames ) 281 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("XY")); 282 else 283 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Scatter")); 284 } 285 286 else if( IsXMLToken( rClassName, XML_BUBBLE )) 287 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Bubble")); 288 else if( IsXMLToken( rClassName, XML_RADAR )) 289 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Net")); 290 else if( IsXMLToken( rClassName, XML_FILLED_RADAR )) 291 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("FilledNet")); 292 else if( IsXMLToken( rClassName, XML_STOCK )) 293 { 294 if( bUseOldNames ) 295 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Stock")); 296 else 297 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("CandleStick")); 298 } 299 else if( IsXMLToken( rClassName, XML_SURFACE )) 300 { 301 //@todo change this if a surface chart is available 302 if( bUseOldNames ) 303 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Bar")); 304 else 305 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Column")); 306 } 307 else 308 bInternalType = false; 309 310 if( ! bInternalType ) 311 return OUString(); 312 313 if( bUseOldNames ) 314 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Diagram")); 315 else 316 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("ChartType")); 317 318 return aResultBuffer.makeStringAndClear(); 319 320 } 321 322 XMLTokenEnum getTokenByChartType( 323 const OUString & rChartTypeService, bool bUseOldNames ) 324 { 325 XMLTokenEnum eResult = XML_TOKEN_INVALID; 326 OUString aPrefix, aPostfix; 327 328 if( bUseOldNames ) 329 { 330 aPrefix = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart.")); 331 aPostfix = OUString( RTL_CONSTASCII_USTRINGPARAM("Diagram")); 332 } 333 else 334 { 335 aPrefix = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2.")); 336 aPostfix = OUString( RTL_CONSTASCII_USTRINGPARAM("ChartType")); 337 } 338 339 if( rChartTypeService.match( aPrefix )) 340 { 341 sal_Int32 nSkip = aPrefix.getLength(); 342 OSL_ASSERT( rChartTypeService.getLength() >= nSkip ); 343 sal_Int32 nTypeLength = rChartTypeService.getLength() - nSkip - aPostfix.getLength(); 344 // if postfix matches and leaves a non-empty type 345 if( nTypeLength > 0 && rChartTypeService.match( aPostfix, nSkip + nTypeLength )) 346 { 347 OUString aServiceName( rChartTypeService.copy( nSkip, nTypeLength )); 348 349 if( aServiceName.equalsAscii("Line")) 350 eResult = XML_LINE; 351 else if( aServiceName.equalsAscii("Area")) 352 eResult = XML_AREA; 353 else if( aServiceName.equalsAscii("Bar") || 354 (!bUseOldNames && aServiceName.equalsAscii("Column"))) 355 eResult = XML_BAR; 356 else if( aServiceName.equalsAscii("Pie")) 357 eResult = XML_CIRCLE; 358 else if( aServiceName.equalsAscii("Donut")) 359 eResult = XML_RING; 360 else if( (bUseOldNames && aServiceName.equalsAscii("XY")) || 361 (!bUseOldNames && aServiceName.equalsAscii("Scatter"))) 362 eResult = XML_SCATTER; 363 else if( aServiceName.equalsAscii("Bubble")) 364 eResult = XML_BUBBLE; 365 else if( aServiceName.equalsAscii("Net")) 366 eResult = XML_RADAR; 367 else if( aServiceName.equalsAscii("FilledNet")) 368 eResult = XML_FILLED_RADAR; 369 else if( (bUseOldNames && aServiceName.equalsAscii("Stock")) || 370 (!bUseOldNames && aServiceName.equalsAscii("CandleStick"))) 371 eResult = XML_STOCK; 372 } 373 } 374 375 if( eResult == XML_TOKEN_INVALID && rChartTypeService.getLength() > 0 ) 376 eResult = XML_ADD_IN; 377 378 return eResult; 379 } 380 381 Reference< chart2::data::XLabeledDataSequence > GetNewLabeledDataSequence() 382 { 383 Reference< chart2::data::XLabeledDataSequence > xResult; 384 Reference< uno::XComponentContext > xContext( lcl_getComponentContext()); 385 if( xContext.is() ) 386 xResult.set( 387 xContext->getServiceManager()->createInstanceWithContext( 388 OUString::createFromAscii("com.sun.star.chart2.data.LabeledDataSequence"), 389 xContext ), uno::UNO_QUERY_THROW ); 390 return xResult; 391 } 392 393 Reference< chart2::data::XDataSequence > CreateDataSequence( 394 const OUString & rRange, 395 const Reference< chart2::XChartDocument >& xChartDoc ) 396 { 397 Reference< chart2::data::XDataSequence > xRet; 398 399 if( !xChartDoc.is() ) 400 { 401 DBG_ERROR( "need a chart document" ); 402 return xRet; 403 } 404 405 Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); 406 if( !xDataProvider.is() ) 407 { 408 DBG_ERROR( "need a data provider" ); 409 return xRet; 410 } 411 412 try 413 { 414 xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider ))); 415 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); 416 } 417 catch( const lang::IllegalArgumentException & ) 418 { 419 DBG_ERROR( "could not create data sequence" ); 420 } 421 422 if( !xRet.is() && !xChartDoc->hasInternalDataProvider() && rRange.getLength() ) 423 { 424 //#i103911# switch to internal data in case the parent cannot provide the requested data 425 xChartDoc->createInternalDataProvider( sal_True /* bCloneExistingData */ ); 426 xDataProvider = xChartDoc->getDataProvider(); 427 try 428 { 429 xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider ))); 430 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); 431 } 432 catch( const lang::IllegalArgumentException & ) 433 { 434 DBG_ERROR( "could not create data sequence" ); 435 } 436 } 437 return xRet; 438 } 439 440 void CreateCategories( 441 const uno::Reference< chart2::data::XDataProvider > & xDataProvider, 442 const uno::Reference< chart2::XChartDocument > & xNewDoc, 443 const OUString & rRangeAddress, 444 sal_Int32 nCooSysIndex, 445 sal_Int32 nDimensionIndex, 446 tSchXMLLSequencesPerIndex * pLSequencesPerIndex ) 447 { 448 try 449 { 450 if( xNewDoc.is() && rRangeAddress.getLength()) 451 { 452 if( xDataProvider.is()) 453 { 454 uno::Reference< chart2::XDiagram > xDia( xNewDoc->getFirstDiagram()); 455 if( !xDia.is()) 456 return; 457 458 uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW ); 459 uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > 460 aCooSysSeq( xCooSysCnt->getCoordinateSystems()); 461 if( nCooSysIndex < aCooSysSeq.getLength()) 462 { 463 uno::Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] ); 464 OSL_ASSERT( xCooSys.is()); 465 if( nDimensionIndex < xCooSys->getDimension() ) 466 { 467 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); 468 for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI) 469 { 470 uno::Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nI )); 471 if( xAxis.is() ) 472 { 473 chart2::ScaleData aData( xAxis->getScaleData()); 474 uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( 475 GetNewLabeledDataSequence()); 476 try 477 { 478 OUString aConvertedRange( rRangeAddress ); 479 bool bRangeConverted = false; 480 if( ! (xNewDoc->hasInternalDataProvider() && 481 aConvertedRange.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("categories")))) 482 { 483 Reference< chart2::data::XRangeXMLConversion > xXMLConv( xDataProvider, uno::UNO_QUERY ); 484 if( xXMLConv.is()) 485 { 486 aConvertedRange = xXMLConv->convertRangeFromXML( rRangeAddress ); 487 bRangeConverted = true; 488 } 489 } 490 Reference< chart2::data::XDataSequence > xSeq( 491 xDataProvider->createDataSequenceByRangeRepresentation( aConvertedRange )); 492 xLabeledSeq->setValues( xSeq ); 493 if( bRangeConverted ) 494 setXMLRangePropertyAtDataSequence( xSeq, rRangeAddress ); 495 } 496 catch( const lang::IllegalArgumentException & ex ) 497 { 498 (void)ex; // avoid warning for pro build 499 OSL_ENSURE( false, ::rtl::OUStringToOString( 500 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IllegalArgumentException caught, Message: " )) + 501 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr()); 502 } 503 aData.Categories.set( xLabeledSeq ); 504 if( pLSequencesPerIndex ) 505 { 506 // register for setting local data if external data provider is not present 507 pLSequencesPerIndex->insert( 508 tSchXMLLSequencesPerIndex::value_type( 509 tSchXMLIndexWithPart( SCH_XML_CATEGORIES_INDEX, SCH_XML_PART_VALUES ), xLabeledSeq )); 510 } 511 xAxis->setScaleData( aData ); 512 } 513 } 514 } 515 } 516 } 517 } 518 } 519 catch( uno::Exception & ) 520 { 521 OSL_ENSURE( false, "Exception caught while creating Categories" ); 522 } 523 } 524 525 526 uno::Any getPropertyFromContext( const rtl::OUString& rPropertyName, const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) 527 { 528 uno::Any aRet; 529 if( !pPropStyleContext || !pStylesCtxt ) 530 return aRet; 531 const ::std::vector< XMLPropertyState >& rProperties = pPropStyleContext->GetProperties(); 532 const UniReference< XMLPropertySetMapper >& rMapper = pStylesCtxt->GetImportPropertyMapper( pPropStyleContext->GetFamily()/*XML_STYLE_FAMILY_SCH_CHART_ID*/ )->getPropertySetMapper(); 533 ::std::vector< XMLPropertyState >::const_iterator aEnd( rProperties.end() ); 534 ::std::vector< XMLPropertyState >::const_iterator aPropIter( rProperties.begin() ); 535 for( aPropIter = rProperties.begin(); aPropIter != aEnd; ++aPropIter ) 536 { 537 sal_Int32 nIdx = aPropIter->mnIndex; 538 if( nIdx == -1 ) 539 continue; 540 OUString aPropName = rMapper->GetEntryAPIName( nIdx ); 541 if(rPropertyName.equals(aPropName)) 542 return aPropIter->maValue; 543 } 544 return aRet; 545 } 546 547 void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs ) 548 { 549 SvXMLElementExport aPara( rExport, XML_NAMESPACE_TEXT, 550 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_P ), 551 sal_True, sal_False ); 552 553 if( bConvertTabsLFs ) 554 { 555 sal_Int32 nStartPos = 0; 556 sal_Int32 nEndPos = rText.getLength(); 557 sal_Unicode cChar; 558 559 for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ ) 560 { 561 cChar = rText[ nPos ]; 562 switch( cChar ) 563 { 564 case 0x0009: // tabulator 565 { 566 if( nPos > nStartPos ) 567 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) ); 568 nStartPos = nPos + 1; 569 570 SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT, 571 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_TAB_STOP ), 572 sal_False, sal_False ); 573 } 574 break; 575 576 case 0x000A: // linefeed 577 { 578 if( nPos > nStartPos ) 579 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) ); 580 nStartPos = nPos + 1; 581 582 SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT, 583 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK ), 584 sal_False, sal_False ); 585 } 586 break; 587 } 588 } 589 if( nEndPos > nStartPos ) 590 { 591 if( nStartPos == 0 ) 592 rExport.GetDocHandler()->characters( rText ); 593 else 594 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nEndPos - nStartPos)) ); 595 } 596 } 597 else // do not convert tabs and linefeeds (eg for numbers coming from unit converter) 598 { 599 rExport.GetDocHandler()->characters( rText ); 600 } 601 } 602 603 void exportRangeToSomewhere( SvXMLExport& rExport, const ::rtl::OUString& rValue ) 604 { 605 //with issue #i366# and CWS chart20 ranges for error bars were introduced 606 //to keep them during copy paste from calc to impress for example it 607 //was necessary to introduce a mapping between the used ranges within calc and the data written to the local table 608 //this is why we write this ranges here 609 610 //#i113950# first the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore within ODF 1.2 611 //as an alternative the range info is now saved into the description at an empty group element (not very nice, but ODF conform) 612 613 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() ); 614 if( nCurrentODFVersion == SvtSaveOptions::ODFVER_010 || nCurrentODFVersion == SvtSaveOptions::ODFVER_011 ) 615 return;//svg:desc is not allowed at draw:g in ODF1.0; but as the ranges for error bars are anyhow not allowed within ODF1.0 nor ODF1.1 we do not need the information 616 617 SvXMLElementExport aEmptyShapeGroup( rExport, XML_NAMESPACE_DRAW, 618 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_G ), 619 sal_True, sal_False ); 620 SvXMLElementExport aDescription( rExport, XML_NAMESPACE_SVG, 621 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DESC ), 622 sal_True, sal_False ); 623 rExport.GetDocHandler()->characters( rValue ); 624 } 625 626 Reference< chart2::XRegressionCurve > getRegressionCurve( 627 const Reference< chart2::XDataSeries > & xDataSeries ) 628 { 629 Reference< chart2::XRegressionCurve > xResult; 630 631 Reference< chart2::XRegressionCurveContainer > xRegCurveCnt( xDataSeries, uno::UNO_QUERY ); 632 if( xRegCurveCnt.is()) 633 { 634 // find equation properties of first regression curve 635 Sequence< Reference< chart2::XRegressionCurve > > aCurveSeq( 636 xRegCurveCnt->getRegressionCurves() ); 637 for( sal_Int32 nI=0; nI<aCurveSeq.getLength(); ++nI ) 638 { 639 // skip mean-value line 640 Reference< lang::XServiceName > xServiceName( aCurveSeq[nI], uno::UNO_QUERY ); 641 if( xServiceName.is()) 642 { 643 OUString aServiceName( xServiceName->getServiceName()); 644 if( aServiceName.equalsAsciiL( 645 RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.MeanValueRegressionCurve" ))) 646 continue; 647 } 648 // take first non-empty curve 649 if( aCurveSeq[nI].is()) 650 { 651 xResult.set( aCurveSeq[nI] ); 652 break; 653 } 654 } 655 } 656 return xResult; 657 } 658 659 void setXMLRangePropertyAtDataSequence( 660 const Reference< chart2::data::XDataSequence > & xDataSequence, 661 const OUString & rXMLRange ) 662 { 663 if( !xDataSequence.is()) 664 return; 665 try 666 { 667 const OUString aXMLRangePropName( RTL_CONSTASCII_USTRINGPARAM( "CachedXMLRange" )); 668 Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); 669 Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); 670 if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName )) 671 xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange )); 672 } 673 catch( const uno::Exception & ex ) 674 { 675 (void)ex; // avoid warning for pro build 676 OSL_ENSURE( false, ::rtl::OUStringToOString( 677 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught, Message: " )) + 678 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr()); 679 } 680 } 681 682 bool getXMLRangePropertyFromDataSequence( 683 const Reference< chart2::data::XDataSequence > & xDataSequence, 684 OUString & rOutXMLRange, 685 bool bClearProp /* = false */) 686 { 687 bool bResult = false; 688 if( xDataSequence.is()) 689 { 690 try 691 { 692 const OUString aXMLRangePropName( RTL_CONSTASCII_USTRINGPARAM( "CachedXMLRange" )); 693 Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); 694 Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); 695 bResult = 696 ( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ) && 697 ( xProp->getPropertyValue( aXMLRangePropName ) >>= rOutXMLRange ) && 698 rOutXMLRange.getLength()); 699 // clear the property after usage 700 if( bClearProp && bResult ) 701 xProp->setPropertyValue( aXMLRangePropName, uno::Any( OUString())); 702 } 703 catch( const uno::Exception & ex ) 704 { 705 (void)ex; // avoid warning for pro build 706 OSL_ENSURE( false, ::rtl::OUStringToOString( 707 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught, Message: " )) + 708 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr()); 709 } 710 } 711 return bResult; 712 } 713 714 void copyProperties( 715 const Reference< beans::XPropertySet > & xSource, 716 const Reference< beans::XPropertySet > & xDestination ) 717 { 718 if( ! (xSource.is() && xDestination.is()) ) 719 return; 720 721 try 722 { 723 Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_QUERY_THROW ); 724 Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_QUERY_THROW ); 725 Sequence< beans::Property > aProperties( xSrcInfo->getProperties()); 726 const sal_Int32 nLength = aProperties.getLength(); 727 for( sal_Int32 i = 0; i < nLength; ++i ) 728 { 729 OUString aName( aProperties[i].Name); 730 if( xDestInfo->hasPropertyByName( aName )) 731 { 732 beans::Property aProp( xDestInfo->getPropertyByName( aName )); 733 if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 ) 734 xDestination->setPropertyValue( 735 aName, xSource->getPropertyValue( aName )); 736 } 737 } 738 } 739 catch( const uno::Exception & ) 740 { 741 OSL_ENSURE( false, "Copying property sets failed!" ); 742 } 743 } 744 745 bool switchBackToDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc, const tSchXMLLSequencesPerIndex & rLSequencesPerIndex ) 746 { 747 //return whether the switch is successful 748 if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() ) 749 return false; 750 Reference< chart2::data::XDataProvider > xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc ) ); 751 if( !xDataProviderFromParent.is() ) 752 return false; 753 uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY ); 754 if( !xDataReceiver.is() ) 755 return false; 756 757 xDataReceiver->attachDataProvider( xDataProviderFromParent ); 758 759 for( tSchXMLLSequencesPerIndex::const_iterator aLSeqIt( rLSequencesPerIndex.begin() ); 760 aLSeqIt != rLSequencesPerIndex.end(); ++aLSeqIt ) 761 { 762 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( aLSeqIt->second ); 763 if( !xLabeledSeq.is() ) 764 continue; 765 Reference< chart2::data::XDataSequence > xNewSeq; 766 xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getValues(), xDataProviderFromParent ); 767 if( xNewSeq.is() ) 768 xLabeledSeq->setValues( xNewSeq ); 769 xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getLabel(), xDataProviderFromParent ); 770 if( xNewSeq.is() ) 771 xLabeledSeq->setLabel( xNewSeq ); 772 } 773 return true; 774 } 775 776 void setBuildIDAtImportInfo( uno::Reference< frame::XModel > xModel, Reference< beans::XPropertySet > xImportInfo ) 777 { 778 ::rtl::OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel) ); 779 if( aGenerator.getLength() ) 780 SvXMLMetaDocumentContext::setBuildId( aGenerator, xImportInfo ); 781 } 782 783 bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference< frame::XModel >& xChartModel ) 784 { 785 bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ); 786 if( !bResult ) 787 { 788 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); 789 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/3") ) ) != -1 ) 790 { 791 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/300m") ) ) != -1 ) 792 { 793 sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) ); 794 if( nBuilId>0 && nBuilId<9491 ) //9491 is build id of dev300m76 795 bResult= true; 796 } 797 else if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/310m") ) ) != -1 ) 798 bResult= true; 799 else if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/320m") ) ) != -1 ) 800 bResult= true; 801 } 802 } 803 return bResult; 804 } 805 806 bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference< frame::XModel >& xChartModel ) 807 { 808 bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ); 809 if( !bResult ) 810 { 811 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); 812 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/680m") ) ) != -1 ) 813 bResult= true; 814 } 815 return bResult; 816 } 817 818 bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference< frame::XModel >& xChartModel ) 819 { 820 if( isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ) ) 821 return true; 822 823 if( isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ) ) 824 { 825 sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) ); 826 if( nBuilId>0 && nBuilId<=9238 ) //9238 is build id of OpenOffice.org 2.3.1 827 return true; 828 } 829 return false; 830 } 831 832 bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference< frame::XModel >& xChartModel ) 833 { 834 bool bResult = false; 835 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); 836 //if there is a meta stream at the chart object it was not written with an older OpenOffice version < 2.3 837 if( !aGenerator.getLength() ) 838 { 839 //if there is no meta stream at the chart object we need to check whether the parent document is OpenOffice at all 840 uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); 841 if( xChild.is() ) 842 { 843 aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) ); 844 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project") ) ) != -1 ) 845 { 846 //the chart application has not created files without a meta stream since OOo 2.3 (OOo 2.3 has written a metastream already) 847 //only the report builder extension has created some files with OOo 3.1 that do not have a meta stream 848 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/31") ) ) != -1 ) 849 bResult = false;//#i100102# probably generated with OOo 3.1 by the report designer 850 else 851 bResult= true; //in this case the OLE chart was created by an older version, as OLE objects are sometimes stream copied the version can differ from the parents version, so the parents version is not a reliable indicator 852 } 853 else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel) ) 854 bResult= true; 855 } 856 } 857 return bResult; 858 } 859 860 bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& xChartModel) 861 { 862 bool bResult = false; 863 ::rtl::OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xChartModel) ); 864 if( ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org 1") ) ) == 0 ) 865 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarOffice 6") ) ) == 0 ) 866 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarOffice 7") ) ) == 0 ) 867 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarSuite 6") ) ) == 0 ) 868 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarSuite 7") ) ) == 0 ) 869 ) 870 bResult= true; 871 return bResult; 872 } 873 874 Reference< chart2::data::XDataProvider > getDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc ) 875 { 876 Reference< chart2::data::XDataProvider > xRet; 877 uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY ); 878 if( xChild.is() ) 879 { 880 Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY ); 881 if( xFact.is() ) 882 { 883 const OUString aDataProviderServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2.data.DataProvider")); 884 const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames()); 885 const OUString * pBegin = aServiceNames.getConstArray(); 886 const OUString * pEnd = pBegin + aServiceNames.getLength(); 887 if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd ) 888 { 889 xRet = Reference< chart2::data::XDataProvider >( 890 xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY ); 891 } 892 } 893 } 894 return xRet; 895 } 896 897 } // namespace SchXMLTools 898