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 "SchXMLChartContext.hxx" 32 #include "SchXMLImport.hxx" 33 #include "SchXMLLegendContext.hxx" 34 #include "SchXMLPlotAreaContext.hxx" 35 #include "SchXMLParagraphContext.hxx" 36 #include "SchXMLTableContext.hxx" 37 #include "SchXMLSeriesHelper.hxx" 38 #include "SchXMLSeries2Context.hxx" 39 #include "SchXMLTools.hxx" 40 #include <comphelper/mediadescriptor.hxx> 41 #include <tools/debug.hxx> 42 // header for class ByteString 43 #include <tools/string.hxx> 44 #include "xmloff/xmlnmspe.hxx" 45 #include <xmloff/xmlement.hxx> 46 #include <xmloff/xmltoken.hxx> 47 #include <xmloff/nmspmap.hxx> 48 #include <xmloff/xmluconv.hxx> 49 #include <xmloff/xmlstyle.hxx> 50 #include <xmloff/prstylei.hxx> 51 52 #include "vector" 53 #include <com/sun/star/chart/XChartDocument.hpp> 54 #include <com/sun/star/chart/XDiagram.hpp> 55 #include <com/sun/star/xml/sax/XAttributeList.hpp> 56 #include <com/sun/star/util/XStringMapping.hpp> 57 #include <com/sun/star/drawing/XDrawPageSupplier.hpp> 58 #include <com/sun/star/drawing/XDrawPage.hpp> 59 #include <com/sun/star/chart/ChartDataRowSource.hpp> 60 #include <com/sun/star/awt/PosSize.hpp> 61 #include <com/sun/star/embed/Aspects.hpp> 62 #include <com/sun/star/embed/XVisualObject.hpp> 63 64 #include <com/sun/star/chart2/XChartDocument.hpp> 65 #include <com/sun/star/chart2/data/XDataSink.hpp> 66 #include <com/sun/star/chart2/XDataSeriesContainer.hpp> 67 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> 68 #include <com/sun/star/chart2/XChartTypeContainer.hpp> 69 #include <com/sun/star/chart2/XTitled.hpp> 70 71 using namespace com::sun::star; 72 using namespace ::xmloff::token; 73 using ::rtl::OUString; 74 using com::sun::star::uno::Reference; 75 using namespace ::SchXMLTools; 76 77 namespace 78 { 79 80 void lcl_setRoleAtLabeledSequence( 81 const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq, 82 const ::rtl::OUString &rRole ) 83 { 84 // set role of sequence 85 uno::Reference< chart2::data::XDataSequence > xValues( xLSeq->getValues()); 86 if( xValues.is()) 87 { 88 uno::Reference< beans::XPropertySet > xProp( xValues, uno::UNO_QUERY ); 89 if( xProp.is()) 90 xProp->setPropertyValue(OUString::createFromAscii("Role"), uno::makeAny( rRole )); 91 } 92 } 93 94 void lcl_MoveDataToCandleStickSeries( 95 const uno::Reference< chart2::data::XDataSource > & xDataSource, 96 const uno::Reference< chart2::XDataSeries > & xDestination, 97 const OUString & rRole ) 98 { 99 try 100 { 101 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq( 102 xDataSource->getDataSequences()); 103 if( aLabeledSeq.getLength()) 104 { 105 lcl_setRoleAtLabeledSequence( aLabeledSeq[0], rRole ); 106 107 // add to data series 108 uno::Reference< chart2::data::XDataSource > xSource( xDestination, uno::UNO_QUERY_THROW ); 109 // @todo: realloc only once outside this function 110 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xSource->getDataSequences()); 111 aData.realloc( aData.getLength() + 1); 112 aData[ aData.getLength() - 1 ] = aLabeledSeq[0]; 113 uno::Reference< chart2::data::XDataSink > xSink( xDestination, uno::UNO_QUERY_THROW ); 114 xSink->setData( aData ); 115 } 116 } 117 catch( uno::Exception & ) 118 { 119 OSL_ENSURE( false, "Exception caught while moving data to candlestick series" ); 120 } 121 } 122 123 void lcl_setRoleAtFirstSequence( 124 const uno::Reference< chart2::XDataSeries > & xSeries, 125 const ::rtl::OUString & rRole ) 126 { 127 uno::Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); 128 if( xSource.is()) 129 { 130 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); 131 if( aSeq.getLength()) 132 lcl_setRoleAtLabeledSequence( aSeq[0], rRole ); 133 } 134 } 135 136 void lcl_removeEmptyChartTypeGroups( const uno::Reference< chart2::XChartDocument > & xDoc ) 137 { 138 if( ! xDoc.is()) 139 return; 140 141 uno::Reference< chart2::XDiagram > xDia( xDoc->getFirstDiagram()); 142 if( ! xDia.is()) 143 return; 144 145 try 146 { 147 // count all charttype groups to be able to leave at least one 148 sal_Int32 nRemainingGroups = 0; 149 uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW ); 150 uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > 151 aCooSysSeq( xCooSysCnt->getCoordinateSystems()); 152 for( sal_Int32 nI = aCooSysSeq.getLength(); nI--; ) 153 { 154 uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW ); 155 nRemainingGroups += xCTCnt->getChartTypes().getLength(); 156 } 157 158 // delete all empty groups, but leave at least group (empty or not) 159 for( sal_Int32 nI = aCooSysSeq.getLength(); nI-- && (nRemainingGroups > 1); ) 160 { 161 uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW ); 162 uno::Sequence< uno::Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes()); 163 for( sal_Int32 nJ=aCTSeq.getLength(); nJ-- && (nRemainingGroups > 1); ) 164 { 165 uno::Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nJ], uno::UNO_QUERY_THROW ); 166 if( xDSCnt->getDataSeries().getLength() == 0 ) 167 { 168 // note: iterator stays valid as we have a local sequence 169 xCTCnt->removeChartType( aCTSeq[nJ] ); 170 --nRemainingGroups; 171 } 172 } 173 } 174 } 175 catch( uno::Exception & ex ) 176 { 177 String aStr( ex.Message ); 178 ByteString aBStr( aStr, RTL_TEXTENCODING_ASCII_US ); 179 DBG_ERROR1( "Exception caught while removing empty chart types: %s", aBStr.GetBuffer()); 180 } 181 } 182 183 uno::Sequence< sal_Int32 > lcl_getNumberSequenceFromString( const ::rtl::OUString& rStr, bool bAddOneToEachOldIndex ) 184 { 185 const sal_Unicode aSpace( ' ' ); 186 187 // count number of entries 188 ::std::vector< sal_Int32 > aVec; 189 sal_Int32 nLastPos = 0; 190 sal_Int32 nPos = 0; 191 while( nPos != -1 ) 192 { 193 nPos = rStr.indexOf( aSpace, nLastPos ); 194 if( nPos > nLastPos ) 195 { 196 aVec.push_back( rStr.copy( nLastPos, (nPos - nLastPos) ).toInt32() ); 197 } 198 if( nPos != -1 ) 199 nLastPos = nPos + 1; 200 } 201 // last entry 202 if( nLastPos != 0 && 203 rStr.getLength() > nLastPos ) 204 { 205 aVec.push_back( rStr.copy( nLastPos, (rStr.getLength() - nLastPos) ).toInt32() ); 206 } 207 208 const sal_Int32 nVecSize = aVec.size(); 209 uno::Sequence< sal_Int32 > aSeq( nVecSize ); 210 211 if(!bAddOneToEachOldIndex) 212 { 213 sal_Int32* pSeqArr = aSeq.getArray(); 214 for( nPos = 0; nPos < nVecSize; ++nPos ) 215 { 216 pSeqArr[ nPos ] = aVec[ nPos ]; 217 } 218 } 219 else if( bAddOneToEachOldIndex ) 220 { 221 aSeq.realloc( nVecSize+1 ); 222 aSeq[0]=0; 223 224 sal_Int32* pSeqArr = aSeq.getArray(); 225 for( nPos = 0; nPos < nVecSize; ++nPos ) 226 { 227 pSeqArr[ nPos+1 ] = aVec[ nPos ]+1; 228 } 229 } 230 231 return aSeq; 232 } 233 234 } // anonymous namespace 235 236 // ---------------------------------------- 237 238 SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper, 239 SvXMLImport& rImport, const rtl::OUString& rLocalName ) : 240 SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), 241 mrImportHelper( rImpHelper ), 242 m_bHasRangeAtPlotArea( false ), 243 m_bHasTableElement( false ), 244 mbAllRangeAddressesAvailable( sal_True ), 245 mbColHasLabels( sal_False ), 246 mbRowHasLabels( sal_False ), 247 meDataRowSource( chart::ChartDataRowSource_COLUMNS ), 248 mbIsStockChart( false ) 249 { 250 } 251 252 SchXMLChartContext::~SchXMLChartContext() 253 {} 254 255 void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) 256 { 257 // parse attributes 258 sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; 259 const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap(); 260 261 uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY); 262 DBG_ASSERT(xVisualObject.is(),"need xVisualObject for page size"); 263 if( xVisualObject.is() ) 264 maChartSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); //#i103460# take the size given from the parent frame as default 265 266 // this flag is necessarry for pie charts in the core 267 sal_Bool bSetSwitchData = sal_False; 268 269 ::rtl::OUString sAutoStyleName; 270 ::rtl::OUString aOldChartTypeName; 271 bool bHasAddin = false; 272 273 for( sal_Int16 i = 0; i < nAttrCount; i++ ) 274 { 275 rtl::OUString sAttrName = xAttrList->getNameByIndex( i ); 276 rtl::OUString aLocalName; 277 rtl::OUString aValue = xAttrList->getValueByIndex( i ); 278 sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); 279 280 switch( rAttrTokenMap.Get( nPrefix, aLocalName )) 281 { 282 case XML_TOK_CHART_HREF: 283 m_aXLinkHRefAttributeToIndicateDataProvider = aValue; 284 break; 285 286 case XML_TOK_CHART_CLASS: 287 { 288 rtl::OUString sClassName; 289 sal_uInt16 nClassPrefix = 290 GetImport().GetNamespaceMap().GetKeyByAttrName( 291 aValue, &sClassName ); 292 if( XML_NAMESPACE_CHART == nClassPrefix ) 293 { 294 SchXMLChartTypeEnum eChartTypeEnum = SchXMLTools::GetChartTypeEnum( sClassName ); 295 if( eChartTypeEnum != XML_CHART_CLASS_UNKNOWN ) 296 { 297 aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( sClassName, true /* bUseOldNames */ ); 298 maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( sClassName, false /* bUseOldNames */ ); 299 switch( eChartTypeEnum ) 300 { 301 case XML_CHART_CLASS_CIRCLE: 302 bSetSwitchData = sal_True; 303 break; 304 case XML_CHART_CLASS_STOCK: 305 mbIsStockChart = true; 306 break; 307 default: 308 break; 309 } 310 } 311 } 312 else if( XML_NAMESPACE_OOO == nClassPrefix ) 313 { 314 // service is taken from add-in-name attribute 315 bHasAddin = true; 316 317 aOldChartTypeName = sClassName; 318 maChartTypeServiceName = sClassName; 319 } 320 } 321 break; 322 323 case XML_TOK_CHART_WIDTH: 324 GetImport().GetMM100UnitConverter().convertMeasure( maChartSize.Width, aValue ); 325 break; 326 327 case XML_TOK_CHART_HEIGHT: 328 GetImport().GetMM100UnitConverter().convertMeasure( maChartSize.Height, aValue ); 329 break; 330 331 case XML_TOK_CHART_STYLE_NAME: 332 sAutoStyleName = aValue; 333 break; 334 335 case XML_TOK_CHART_COL_MAPPING: 336 msColTrans = aValue; 337 break; 338 case XML_TOK_CHART_ROW_MAPPING: 339 msRowTrans = aValue; 340 break; 341 } 342 } 343 344 if( aOldChartTypeName.getLength()<= 0 ) 345 { 346 DBG_ERROR( "need a charttype to create a diagram" ); 347 //set a fallback value: 348 ::rtl::OUString aChartClass_Bar( GetXMLToken(XML_BAR ) ); 349 aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, true /* bUseOldNames */ ); 350 maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, false /* bUseOldNames */ ); 351 } 352 353 // Set the size of the draw page. 354 if( xVisualObject.is() ) 355 xVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, maChartSize ); 356 357 InitChart( aOldChartTypeName, bSetSwitchData); 358 359 if( bHasAddin ) 360 { 361 //correct charttype serveice name when having an addin 362 //and don't refresh addin during load 363 uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); 364 if( xDocProp.is() ) 365 { 366 try 367 { 368 xDocProp->getPropertyValue( ::rtl::OUString::createFromAscii("BaseDiagram")) >>= aOldChartTypeName; 369 maChartTypeServiceName = SchXMLTools::GetNewChartTypeName( aOldChartTypeName ); 370 xDocProp->setPropertyValue( rtl::OUString::createFromAscii( "RefreshAddInAllowed" ) , uno::makeAny( sal_False) ); 371 } 372 catch( uno::Exception & ) 373 { 374 DBG_ERROR( "Exception during import SchXMLChartContext::StartElement" ); 375 } 376 } 377 } 378 379 // set auto-styles for Area 380 uno::Reference< beans::XPropertySet > xProp( mrImportHelper.GetChartDocument()->getArea(), uno::UNO_QUERY ); 381 if( xProp.is()) 382 { 383 const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); 384 if( pStylesCtxt ) 385 { 386 const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( 387 mrImportHelper.GetChartFamilyID(), sAutoStyleName ); 388 389 if( pStyle && pStyle->ISA( XMLPropStyleContext )) 390 (( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp ); 391 } 392 } 393 } 394 395 namespace 396 { 397 398 struct NewDonutSeries 399 { 400 ::com::sun::star::uno::Reference< 401 ::com::sun::star::chart2::XDataSeries > m_xSeries; 402 ::rtl::OUString msStyleName; 403 sal_Int32 mnAttachedAxis; 404 405 ::std::vector< ::rtl::OUString > m_aSeriesStyles; 406 ::std::vector< ::rtl::OUString > m_aPointStyles; 407 408 NewDonutSeries( const ::com::sun::star::uno::Reference< 409 ::com::sun::star::chart2::XDataSeries >& xSeries, sal_Int32 nPointCount ) 410 : m_xSeries( xSeries ) 411 , mnAttachedAxis( 1 ) 412 { 413 m_aPointStyles.resize(nPointCount); 414 m_aSeriesStyles.resize(nPointCount); 415 } 416 417 void setSeriesStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex ) 418 { 419 DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()),"donut point <-> series count mismatch"); 420 if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) ) 421 m_aSeriesStyles[nPointIndex]=rStyleName; 422 } 423 424 void setPointStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex ) 425 { 426 DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()),"donut point <-> series count mismatch"); 427 if( nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()) ) 428 m_aPointStyles[nPointIndex]=rStyleName; 429 } 430 431 ::std::list< DataRowPointStyle > creatStyleList() 432 { 433 ::std::list< DataRowPointStyle > aRet; 434 435 DataRowPointStyle aSeriesStyle( DataRowPointStyle::DATA_SERIES 436 , m_xSeries, -1, 1, msStyleName, mnAttachedAxis ); 437 aRet.push_back( aSeriesStyle ); 438 439 sal_Int32 nPointIndex=0; 440 ::std::vector< ::rtl::OUString >::iterator aPointIt( m_aPointStyles.begin() ); 441 ::std::vector< ::rtl::OUString >::iterator aPointEnd( m_aPointStyles.end() ); 442 while( aPointIt != aPointEnd ) 443 { 444 DataRowPointStyle aPointStyle( DataRowPointStyle::DATA_POINT 445 , m_xSeries, nPointIndex, 1, *aPointIt, mnAttachedAxis ); 446 if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) ) 447 { 448 aPointStyle.msSeriesStyleNameForDonuts = m_aSeriesStyles[nPointIndex]; 449 } 450 if( aPointStyle.msSeriesStyleNameForDonuts.getLength() 451 || aPointStyle.msStyleName.getLength() ) 452 aRet.push_back( aPointStyle ); 453 ++aPointIt; 454 ++nPointIndex; 455 } 456 457 return aRet; 458 } 459 }; 460 461 void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::list< DataRowPointStyle >& rStyleList 462 , const ::std::map< ::com::sun::star::uno::Reference< 463 ::com::sun::star::chart2::XDataSeries> , sal_Int32 >& rSeriesMap ) 464 { 465 ::std::list< DataRowPointStyle >::iterator aIt(rStyleList.begin()); 466 ::std::list< DataRowPointStyle >::iterator aEnd(rStyleList.end()); 467 468 //detect old series count 469 //and add old series to aSeriesMap 470 ::std::map< ::com::sun::star::uno::Reference< 471 ::com::sun::star::chart2::XDataSeries >, sal_Int32 > aSeriesMap(rSeriesMap); 472 sal_Int32 nOldSeriesCount = 0; 473 { 474 sal_Int32 nMaxOldSeriesIndex = 0; 475 sal_Int32 nOldSeriesIndex = 0; 476 for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) 477 { 478 DataRowPointStyle aStyle(*aIt); 479 if(aStyle.meType == DataRowPointStyle::DATA_SERIES && 480 aStyle.m_xSeries.is() ) 481 { 482 nMaxOldSeriesIndex = nOldSeriesIndex; 483 484 if( aSeriesMap.end() == aSeriesMap.find(aStyle.m_xSeries) ) 485 aSeriesMap[aStyle.m_xSeries] = nOldSeriesIndex; 486 487 nOldSeriesIndex++; 488 } 489 } 490 nOldSeriesCount = nMaxOldSeriesIndex+1; 491 } 492 /* 493 sal_Int32 nOldSeriesCount = 0; 494 { 495 sal_Int32 nMaxOldSeriesIndex = 0; 496 sal_Int32 nOldSeriesIndex = 0; 497 for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) 498 { 499 DataRowPointStyle aStyle(*aIt); 500 if(aStyle.meType == DataRowPointStyle::DATA_SERIES ) 501 { 502 nMaxOldSeriesIndex = nOldSeriesIndex; 503 nOldSeriesIndex++; 504 } 505 } 506 nOldSeriesCount = nMaxOldSeriesIndex+1; 507 } 508 */ 509 510 511 //initialize new series styles 512 ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapIt( aSeriesMap.begin() ); 513 ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapEnd( aSeriesMap.end() ); 514 515 //sort by index 516 ::std::vector< NewDonutSeries > aNewSeriesVector; 517 { 518 ::std::map< sal_Int32, Reference< chart2::XDataSeries > > aIndexSeriesMap; 519 for( ; aSeriesMapIt != aSeriesMapEnd; ++aSeriesMapIt ) 520 aIndexSeriesMap[aSeriesMapIt->second] = aSeriesMapIt->first; 521 522 ::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexIt( aIndexSeriesMap.begin() ); 523 ::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexEnd( aIndexSeriesMap.end() ); 524 525 for( ; aIndexIt != aIndexEnd; ++aIndexIt ) 526 aNewSeriesVector.push_back( NewDonutSeries(aIndexIt->second,nOldSeriesCount) ); 527 } 528 529 //overwrite attached axis information according to old series styles 530 for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) 531 { 532 DataRowPointStyle aStyle(*aIt); 533 if(aStyle.meType == DataRowPointStyle::DATA_SERIES ) 534 { 535 aSeriesMapIt = aSeriesMap.find( aStyle.m_xSeries ); 536 if( aSeriesMapIt != aSeriesMapEnd && aSeriesMapIt->second < static_cast<sal_Int32>(aNewSeriesVector.size()) ) 537 aNewSeriesVector[aSeriesMapIt->second].mnAttachedAxis = aStyle.mnAttachedAxis; 538 } 539 } 540 541 //overwrite new series style names with old series style name information 542 for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) 543 { 544 DataRowPointStyle aStyle(*aIt); 545 if( aStyle.meType == DataRowPointStyle::DATA_SERIES ) 546 { 547 aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); 548 if( aSeriesMapEnd != aSeriesMapIt ) 549 { 550 sal_Int32 nNewPointIndex = aSeriesMapIt->second; 551 552 ::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() ); 553 ::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() ); 554 555 for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt) 556 aNewSeriesIt->setSeriesStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); 557 } 558 } 559 } 560 561 //overwrite new series style names with point style name information 562 for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) 563 { 564 DataRowPointStyle aStyle(*aIt); 565 if( aStyle.meType == DataRowPointStyle::DATA_POINT ) 566 { 567 aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); 568 if( aSeriesMapEnd != aSeriesMapIt ) 569 { 570 sal_Int32 nNewPointIndex = aSeriesMapIt->second; 571 sal_Int32 nNewSeriesIndex = aStyle.m_nPointIndex; 572 sal_Int32 nRepeatCount = aStyle.m_nPointRepeat; 573 574 while( nRepeatCount && (nNewSeriesIndex>=0) && (nNewSeriesIndex< static_cast<sal_Int32>(aNewSeriesVector.size()) ) ) 575 { 576 NewDonutSeries& rNewSeries( aNewSeriesVector[nNewSeriesIndex] ); 577 rNewSeries.setPointStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); 578 579 nRepeatCount--; 580 nNewSeriesIndex++; 581 } 582 } 583 } 584 } 585 586 //put information from aNewSeriesVector to output parameter rStyleList 587 rStyleList.clear(); 588 589 ::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() ); 590 ::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() ); 591 for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt) 592 { 593 ::std::list< DataRowPointStyle > aList( aNewSeriesIt->creatStyleList() ); 594 rStyleList.insert(rStyleList.end(),aList.begin(),aList.end()); 595 } 596 } 597 598 bool lcl_SpecialHandlingForDonutChartNeeded( 599 const ::rtl::OUString & rServiceName, 600 const SvXMLImport & rImport ) 601 { 602 bool bResult = false; 603 if( rServiceName.equalsAsciiL( 604 RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.DonutChartType" ))) 605 { 606 bResult = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport.GetModel() ); 607 } 608 return bResult; 609 } 610 611 } // anonymous namespace 612 613 614 void lcl_ApplyDataFromRectangularRangeToDiagram( 615 const uno::Reference< chart2::XChartDocument >& xNewDoc 616 , const rtl::OUString& rRectangularRange 617 , ::com::sun::star::chart::ChartDataRowSource eDataRowSource 618 , bool bRowHasLabels, bool bColHasLabels 619 , bool bSwitchOnLabelsAndCategoriesForOwnData 620 , const rtl::OUString& sColTrans 621 , const rtl::OUString& sRowTrans ) 622 { 623 if( !xNewDoc.is() ) 624 return; 625 626 uno::Reference< chart2::XDiagram > xNewDia( xNewDoc->getFirstDiagram()); 627 uno::Reference< chart2::data::XDataProvider > xDataProvider( xNewDoc->getDataProvider() ); 628 if( !xNewDia.is() || !xDataProvider.is() ) 629 return; 630 631 sal_Bool bFirstCellAsLabel = 632 (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bRowHasLabels : bColHasLabels; 633 sal_Bool bHasCateories = 634 (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bColHasLabels : bRowHasLabels; 635 636 if( bSwitchOnLabelsAndCategoriesForOwnData ) 637 { 638 bFirstCellAsLabel = true; 639 bHasCateories = true; 640 } 641 642 uno::Sequence< beans::PropertyValue > aArgs( 3 ); 643 aArgs[0] = beans::PropertyValue( 644 ::rtl::OUString::createFromAscii("CellRangeRepresentation"), 645 -1, uno::makeAny( rRectangularRange ), 646 beans::PropertyState_DIRECT_VALUE ); 647 aArgs[1] = beans::PropertyValue( 648 ::rtl::OUString::createFromAscii("DataRowSource"), 649 -1, uno::makeAny( eDataRowSource ), 650 beans::PropertyState_DIRECT_VALUE ); 651 aArgs[2] = beans::PropertyValue( 652 ::rtl::OUString::createFromAscii("FirstCellAsLabel"), 653 -1, uno::makeAny( bFirstCellAsLabel ), 654 beans::PropertyState_DIRECT_VALUE ); 655 656 if( sColTrans.getLength() || sRowTrans.getLength() ) 657 { 658 aArgs.realloc( aArgs.getLength() + 1 ); 659 aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue( 660 ::rtl::OUString::createFromAscii("SequenceMapping"), 661 -1, uno::makeAny( sColTrans.getLength() 662 ? lcl_getNumberSequenceFromString( sColTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) 663 : lcl_getNumberSequenceFromString( sRowTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) ), 664 beans::PropertyState_DIRECT_VALUE ); 665 } 666 667 //work around wrong writer ranges ( see Issue 58464 ) 668 { 669 rtl::OUString aChartOleObjectName; 670 uno::Reference< frame::XModel > xModel(xNewDoc, uno::UNO_QUERY ); 671 if( xModel.is() ) 672 { 673 comphelper::MediaDescriptor aMediaDescriptor( xModel->getArgs() ); 674 675 comphelper::MediaDescriptor::const_iterator aIt( 676 aMediaDescriptor.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HierarchicalDocumentName" )))); 677 if( aIt != aMediaDescriptor.end() ) 678 { 679 aChartOleObjectName = (*aIt).second.get< ::rtl::OUString >(); 680 } 681 } 682 if( aChartOleObjectName.getLength() ) 683 { 684 aArgs.realloc( aArgs.getLength() + 1 ); 685 aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue( 686 ::rtl::OUString::createFromAscii("ChartOleObjectName"), 687 -1, uno::makeAny( aChartOleObjectName ), 688 beans::PropertyState_DIRECT_VALUE ); 689 } 690 } 691 692 693 uno::Reference< chart2::data::XDataSource > xDataSource( 694 xDataProvider->createDataSource( aArgs )); 695 696 aArgs.realloc( aArgs.getLength() + 2 ); 697 aArgs[ aArgs.getLength() - 2 ] = beans::PropertyValue( 698 ::rtl::OUString::createFromAscii("HasCategories"), 699 -1, uno::makeAny( bHasCateories ), 700 beans::PropertyState_DIRECT_VALUE ); 701 aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue( 702 ::rtl::OUString::createFromAscii("UseCategoriesAsX"), 703 -1, uno::makeAny( sal_False ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui) 704 beans::PropertyState_DIRECT_VALUE ); 705 706 xNewDia->setDiagramData( xDataSource, aArgs ); 707 } 708 709 void SchXMLChartContext::EndElement() 710 { 711 uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); 712 uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); 713 uno::Reference< chart2::XChartDocument > xNewDoc( xDoc, uno::UNO_QUERY ); 714 715 if( xProp.is()) 716 { 717 if( maMainTitle.getLength()) 718 { 719 uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY ); 720 if( xTitleProp.is()) 721 { 722 try 723 { 724 uno::Any aAny; 725 aAny <<= maMainTitle; 726 xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny ); 727 } 728 catch( beans::UnknownPropertyException ) 729 { 730 DBG_ERROR( "Property String for Title not available" ); 731 } 732 } 733 } 734 if( maSubTitle.getLength()) 735 { 736 uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY ); 737 if( xTitleProp.is()) 738 { 739 try 740 { 741 uno::Any aAny; 742 aAny <<= maSubTitle; 743 xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny ); 744 } 745 catch( beans::UnknownPropertyException ) 746 { 747 DBG_ERROR( "Property String for Title not available" ); 748 } 749 } 750 } 751 } 752 753 // cleanup: remove empty chart type groups 754 lcl_removeEmptyChartTypeGroups( xNewDoc ); 755 756 // set stack mode before a potential chart type detection (in case we have a rectangular range) 757 uno::Reference< chart::XDiagram > xDiagram( xDoc->getDiagram() ); 758 uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY ); 759 if( xDiaProp.is()) 760 { 761 if( maSeriesDefaultsAndStyles.maStackedDefault.hasValue()) 762 xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Stacked")),maSeriesDefaultsAndStyles.maStackedDefault); 763 if( maSeriesDefaultsAndStyles.maPercentDefault.hasValue()) 764 xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Percent")),maSeriesDefaultsAndStyles.maPercentDefault); 765 if( maSeriesDefaultsAndStyles.maDeepDefault.hasValue()) 766 xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Deep")),maSeriesDefaultsAndStyles.maDeepDefault); 767 if( maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault.hasValue()) 768 xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StackedBarsConnected")),maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault); 769 } 770 771 //the OOo 2.0 implementation and older has a bug with donuts 772 bool bSpecialHandlingForDonutChart = lcl_SpecialHandlingForDonutChartNeeded( 773 maChartTypeServiceName, GetImport()); 774 775 // apply data 776 if(!xNewDoc.is()) 777 return; 778 779 bool bHasOwnData = false; 780 if( m_aXLinkHRefAttributeToIndicateDataProvider.equalsAscii( "." ) ) //data comes from the chart itself 781 bHasOwnData = true; 782 else if( m_aXLinkHRefAttributeToIndicateDataProvider.equalsAscii( ".." ) ) //data comes from the parent application 783 bHasOwnData = false; 784 else if( m_aXLinkHRefAttributeToIndicateDataProvider.getLength() ) //not supported so far to get the data by sibling objects -> fall back to chart itself if data are available 785 bHasOwnData = m_bHasTableElement; 786 else 787 bHasOwnData = !m_bHasRangeAtPlotArea; 788 789 if( xNewDoc->hasInternalDataProvider()) 790 { 791 if( !m_bHasTableElement && !m_aXLinkHRefAttributeToIndicateDataProvider.equalsAscii( "." ) ) 792 { 793 //#i103147# ODF, workaround broken files with a missing table:cell-range-address at the plot-area 794 bool bSwitchSuccessful = SchXMLTools::switchBackToDataProviderFromParent( xNewDoc, maLSequencesPerIndex ); 795 bHasOwnData = !bSwitchSuccessful; 796 } 797 else 798 bHasOwnData = true;//e.g. in case of copy->paste from calc to impress 799 } 800 else if( bHasOwnData ) 801 { 802 xNewDoc->createInternalDataProvider( sal_False /* bCloneExistingData */ ); 803 } 804 if( bHasOwnData ) 805 msChartAddress = ::rtl::OUString::createFromAscii("all"); 806 807 bool bSwitchRangesFromOuterToInternalIfNecessary = false; 808 if( !bHasOwnData && mbAllRangeAddressesAvailable ) 809 { 810 // special handling for stock chart (merge series together) 811 if( mbIsStockChart ) 812 MergeSeriesForStockChart(); 813 } 814 else if( msChartAddress.getLength() ) 815 { 816 //own data or only rectangular range available 817 818 if( xNewDoc->hasInternalDataProvider() ) 819 SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); 820 821 bool bOlderThan2_3 = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( Reference< frame::XModel >( xNewDoc, uno::UNO_QUERY )); 822 bool bOldFileWithOwnDataFromRows = (bOlderThan2_3 && bHasOwnData && (meDataRowSource==chart::ChartDataRowSource_ROWS)); // in this case there are range addresses that are simply wrong. 823 824 if( mbAllRangeAddressesAvailable && !bSpecialHandlingForDonutChart && !mbIsStockChart && 825 !bOldFileWithOwnDataFromRows ) 826 { 827 //bHasOwnData is true in this case! 828 //e.g. for normal files with own data or also in case of copy paste scenario (e.g. calc to impress) 829 bSwitchRangesFromOuterToInternalIfNecessary = true; 830 } 831 else 832 { 833 //apply data from rectangular range 834 835 // create datasource from data provider with rectangular range parameters and change the diagram setDiagramData 836 try 837 { 838 if( bOlderThan2_3 && xDiaProp.is() )//for older charts the hidden cells were removed by calc on the fly 839 xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IncludeHiddenCells")),uno::makeAny(false)); 840 841 // note: mbRowHasLabels means the first row contains labels, that means we have "column-descriptions", 842 // (analogously mbColHasLabels means we have "row-descriptions") 843 lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); 844 } 845 catch( uno::Exception & ) 846 { 847 //try to fallback to internal data 848 DBG_ERROR( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" ); 849 if(!bHasOwnData) 850 { 851 bHasOwnData = true; 852 msChartAddress = ::rtl::OUString::createFromAscii("all"); 853 if( !xNewDoc->hasInternalDataProvider() ) 854 { 855 xNewDoc->createInternalDataProvider( sal_False /* bCloneExistingData */ ); 856 SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); 857 try 858 { 859 lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); 860 } 861 catch( uno::Exception & ) 862 { 863 DBG_ERROR( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" ); 864 } 865 } 866 } 867 } 868 } 869 } 870 else 871 { 872 DBG_ERROR( " Must not get here" ); 873 } 874 875 // now all series and data point properties are available and can be set 876 { 877 if( bSpecialHandlingForDonutChart ) 878 { 879 uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() ); 880 lcl_swapPointAndSeriesStylesForDonutCharts( maSeriesDefaultsAndStyles.maSeriesStyleList 881 , SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram(xNewDiagram) ); 882 } 883 884 SchXMLSeries2Context::initSeriesPropertySets( maSeriesDefaultsAndStyles, uno::Reference< frame::XModel >(xDoc, uno::UNO_QUERY ) ); 885 886 //set defaults from diagram to the new series: 887 //check whether we need to remove lines from symbol only charts 888 bool bSwitchOffLinesForScatter = false; 889 { 890 bool bLinesOn = true; 891 if( (maSeriesDefaultsAndStyles.maLinesOnProperty >>= bLinesOn) && !bLinesOn ) 892 { 893 if( 0 == maChartTypeServiceName.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.ScatterChartType" ) ) ) 894 { 895 bSwitchOffLinesForScatter = true; 896 SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles.maSeriesStyleList ); 897 } 898 } 899 } 900 SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles ); 901 902 // set autostyles for series and data points 903 const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); 904 const SvXMLStyleContext* pStyle = NULL; 905 ::rtl::OUString sCurrStyleName; 906 907 if( pStylesCtxt ) 908 { 909 //iterate over data-series first 910 //don't set series styles for donut charts 911 if( !bSpecialHandlingForDonutChart ) 912 { 913 SchXMLSeries2Context::setStylesToSeries( maSeriesDefaultsAndStyles 914 , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, maLSequencesPerIndex ); 915 // ... then set attributes for statistics (after their existence was set in the series) 916 SchXMLSeries2Context::setStylesToStatisticsObjects( maSeriesDefaultsAndStyles 917 , pStylesCtxt, pStyle, sCurrStyleName ); 918 } 919 } 920 921 //#i98319# call switchRangesFromOuterToInternalIfNecessary before the data point styles are applied, otherwise in copy->paste scenario the data point styles do get lost 922 if( bSwitchRangesFromOuterToInternalIfNecessary ) 923 { 924 if( xNewDoc->hasInternalDataProvider() ) 925 SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( maTable, maLSequencesPerIndex, xNewDoc, meDataRowSource ); 926 } 927 928 if( pStylesCtxt ) 929 { 930 // ... then iterate over data-point attributes, so the latter are not overwritten 931 SchXMLSeries2Context::setStylesToDataPoints( maSeriesDefaultsAndStyles 932 , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, bSpecialHandlingForDonutChart, bSwitchOffLinesForScatter ); 933 } 934 } 935 936 if( xProp.is()) 937 xProp->setPropertyValue( rtl::OUString::createFromAscii( "RefreshAddInAllowed" ) , uno::makeAny( sal_True) ); 938 } 939 940 void SchXMLChartContext::MergeSeriesForStockChart() 941 { 942 OSL_ASSERT( mbIsStockChart ); 943 try 944 { 945 uno::Reference< chart::XChartDocument > xOldDoc( mrImportHelper.GetChartDocument()); 946 uno::Reference< chart2::XChartDocument > xDoc( xOldDoc, uno::UNO_QUERY_THROW ); 947 uno::Reference< chart2::XDiagram > xDiagram( xDoc->getFirstDiagram()); 948 if( ! xDiagram.is()) 949 return; 950 951 bool bHasJapaneseCandlestick = true; 952 uno::Reference< chart2::XDataSeriesContainer > xDSContainer; 953 uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); 954 uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); 955 for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) 956 { 957 uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); 958 uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); 959 for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx ) 960 { 961 if( aChartTypes[nCTIdx]->getChartType().equalsAsciiL( 962 RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2.CandleStickChartType"))) 963 { 964 xDSContainer.set( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW ); 965 uno::Reference< beans::XPropertySet > xCTProp( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW ); 966 xCTProp->getPropertyValue( ::rtl::OUString::createFromAscii("Japanese")) >>= bHasJapaneseCandlestick; 967 break; 968 } 969 } 970 } 971 972 if( xDSContainer.is()) 973 { 974 // with japanese candlesticks: open, low, high, close 975 // otherwise: low, high, close 976 uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDSContainer->getDataSeries()); 977 const sal_Int32 nSeriesCount( aSeriesSeq.getLength()); 978 const sal_Int32 nSeriesPerCandleStick = bHasJapaneseCandlestick ? 4: 3; 979 sal_Int32 nCandleStickCount = nSeriesCount / nSeriesPerCandleStick; 980 OSL_ASSERT( nSeriesPerCandleStick * nCandleStickCount == nSeriesCount ); 981 uno::Sequence< uno::Reference< chart2::XDataSeries > > aNewSeries( nCandleStickCount ); 982 for( sal_Int32 i=0; i<nCandleStickCount; ++i ) 983 { 984 sal_Int32 nSeriesIndex = i*nSeriesPerCandleStick; 985 if( bHasJapaneseCandlestick ) 986 { 987 // open values 988 lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], OUString::createFromAscii("values-first")); 989 aNewSeries[i] = aSeriesSeq[ nSeriesIndex ]; 990 // low values 991 lcl_MoveDataToCandleStickSeries( 992 uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), 993 aNewSeries[i], OUString::createFromAscii("values-min")); 994 } 995 else 996 { 997 // low values 998 lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], OUString::createFromAscii("values-min")); 999 aNewSeries[i] = aSeriesSeq[ nSeriesIndex ]; 1000 } 1001 // high values 1002 lcl_MoveDataToCandleStickSeries( 1003 uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), 1004 aNewSeries[i], OUString::createFromAscii("values-max")); 1005 // close values 1006 lcl_MoveDataToCandleStickSeries( 1007 uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), 1008 aNewSeries[i], OUString::createFromAscii("values-last")); 1009 } 1010 xDSContainer->setDataSeries( aNewSeries ); 1011 } 1012 } 1013 catch( uno::Exception & ) 1014 { 1015 DBG_ERROR( "Exception while merging series for stock chart" ); 1016 } 1017 } 1018 1019 SvXMLImportContext* SchXMLChartContext::CreateChildContext( 1020 sal_uInt16 nPrefix, 1021 const rtl::OUString& rLocalName, 1022 const uno::Reference< xml::sax::XAttributeList >& xAttrList ) 1023 { 1024 static const sal_Bool bTrue = sal_True; 1025 static const uno::Any aTrueBool( &bTrue, ::getBooleanCppuType()); 1026 1027 SvXMLImportContext* pContext = 0; 1028 const SvXMLTokenMap& rTokenMap = mrImportHelper.GetChartElemTokenMap(); 1029 uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); 1030 uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); 1031 1032 switch( rTokenMap.Get( nPrefix, rLocalName )) 1033 { 1034 case XML_TOK_CHART_PLOT_AREA: 1035 pContext = new SchXMLPlotAreaContext( mrImportHelper, GetImport(), rLocalName, 1036 m_aXLinkHRefAttributeToIndicateDataProvider, 1037 maSeriesAddresses, msCategoriesAddress, 1038 msChartAddress, m_bHasRangeAtPlotArea, mbAllRangeAddressesAvailable, 1039 mbColHasLabels, mbRowHasLabels, 1040 meDataRowSource, 1041 maSeriesDefaultsAndStyles, 1042 maChartTypeServiceName, 1043 maLSequencesPerIndex, maChartSize ); 1044 break; 1045 1046 case XML_TOK_CHART_TITLE: 1047 if( xDoc.is()) 1048 { 1049 if( xProp.is()) 1050 { 1051 xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasMainTitle" ), aTrueBool ); 1052 } 1053 uno::Reference< drawing::XShape > xTitleShape( xDoc->getTitle(), uno::UNO_QUERY ); 1054 pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), 1055 rLocalName, maMainTitle, xTitleShape ); 1056 } 1057 break; 1058 1059 case XML_TOK_CHART_SUBTITLE: 1060 if( xDoc.is()) 1061 { 1062 if( xProp.is()) 1063 { 1064 xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasSubTitle" ), aTrueBool ); 1065 } 1066 uno::Reference< drawing::XShape > xTitleShape( xDoc->getSubTitle(), uno::UNO_QUERY ); 1067 pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), 1068 rLocalName, maSubTitle, xTitleShape ); 1069 } 1070 break; 1071 1072 case XML_TOK_CHART_LEGEND: 1073 pContext = new SchXMLLegendContext( mrImportHelper, GetImport(), rLocalName ); 1074 break; 1075 1076 case XML_TOK_CHART_TABLE: 1077 { 1078 SchXMLTableContext * pTableContext = 1079 new SchXMLTableContext( mrImportHelper, GetImport(), rLocalName, maTable ); 1080 m_bHasTableElement = true; 1081 // #i85913# take into account column- and row- mapping for 1082 // charts with own data only for those which were not copied 1083 // from a place where they got data from the container. Note, 1084 // that this requires the plot-area been read before the table 1085 // (which is required in the ODF spec) 1086 // Note: For stock charts and donut charts with special handling 1087 // the mapping must not be applied! 1088 if( !msChartAddress.getLength() && !mbIsStockChart && 1089 !lcl_SpecialHandlingForDonutChartNeeded( 1090 maChartTypeServiceName, GetImport())) 1091 { 1092 if( msColTrans.getLength() > 0 ) 1093 { 1094 OSL_ASSERT( msRowTrans.getLength() == 0 ); 1095 pTableContext->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans, true )); 1096 msColTrans = OUString(); 1097 } 1098 else if( msRowTrans.getLength() > 0 ) 1099 { 1100 pTableContext->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans, true )); 1101 msRowTrans = OUString(); 1102 } 1103 } 1104 pContext = pTableContext; 1105 } 1106 break; 1107 1108 default: 1109 // try importing as an additional shape 1110 if( ! mxDrawPage.is()) 1111 { 1112 uno::Reference< drawing::XDrawPageSupplier > xSupp( xDoc, uno::UNO_QUERY ); 1113 if( xSupp.is()) 1114 mxDrawPage = uno::Reference< drawing::XShapes >( xSupp->getDrawPage(), uno::UNO_QUERY ); 1115 1116 DBG_ASSERT( mxDrawPage.is(), "Invalid Chart Page" ); 1117 } 1118 if( mxDrawPage.is()) 1119 pContext = GetImport().GetShapeImport()->CreateGroupChildContext( 1120 GetImport(), nPrefix, rLocalName, xAttrList, mxDrawPage ); 1121 break; 1122 } 1123 1124 if( ! pContext ) 1125 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 1126 1127 return pContext; 1128 } 1129 1130 1131 /* 1132 With a locked controller the following is done here: 1133 1. Hide title, subtitle, and legend. 1134 2. Set the size of the draw page. 1135 3. Set a (logically) empty data set. 1136 4. Set the chart type. 1137 */ 1138 void SchXMLChartContext::InitChart( 1139 const OUString & rChartTypeServiceName, // currently the old service name 1140 sal_Bool /* bSetSwitchData */ ) 1141 { 1142 uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); 1143 DBG_ASSERT( xDoc.is(), "No valid document!" ); 1144 uno::Reference< frame::XModel > xModel (xDoc, uno::UNO_QUERY ); 1145 1146 // Remove Title and Diagram ("De-InitNew") 1147 uno::Reference< chart2::XChartDocument > xNewDoc( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); 1148 if( xNewDoc.is()) 1149 { 1150 xNewDoc->setFirstDiagram( 0 ); 1151 uno::Reference< chart2::XTitled > xTitled( xNewDoc, uno::UNO_QUERY ); 1152 if( xTitled.is()) 1153 xTitled->setTitleObject( 0 ); 1154 } 1155 1156 // Set the chart type via setting the diagram. 1157 if( rChartTypeServiceName.getLength() && 1158 xDoc.is()) 1159 { 1160 uno::Reference< lang::XMultiServiceFactory > xFact( xDoc, uno::UNO_QUERY ); 1161 if( xFact.is()) 1162 { 1163 uno::Reference< chart::XDiagram > xDia( xFact->createInstance( rChartTypeServiceName ), uno::UNO_QUERY ); 1164 if( xDia.is()) 1165 xDoc->setDiagram( xDia ); 1166 } 1167 } 1168 } 1169 1170 // ---------------------------------------- 1171 1172 SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, 1173 const rtl::OUString& rLocalName, 1174 rtl::OUString& rTitle, 1175 uno::Reference< drawing::XShape >& xTitleShape ) : 1176 SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), 1177 mrImportHelper( rImpHelper ), 1178 mrTitle( rTitle ), 1179 mxTitleShape( xTitleShape ) 1180 { 1181 } 1182 1183 SchXMLTitleContext::~SchXMLTitleContext() 1184 {} 1185 1186 void SchXMLTitleContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) 1187 { 1188 sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; 1189 1190 com::sun::star::awt::Point maPosition; 1191 bool bHasXPosition=false; 1192 bool bHasYPosition=false; 1193 1194 for( sal_Int16 i = 0; i < nAttrCount; i++ ) 1195 { 1196 rtl::OUString sAttrName = xAttrList->getNameByIndex( i ); 1197 rtl::OUString aLocalName; 1198 rtl::OUString aValue = xAttrList->getValueByIndex( i ); 1199 sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); 1200 1201 if( nPrefix == XML_NAMESPACE_SVG ) 1202 { 1203 if( IsXMLToken( aLocalName, XML_X ) ) 1204 { 1205 GetImport().GetMM100UnitConverter().convertMeasure( maPosition.X, aValue ); 1206 bHasXPosition = true; 1207 } 1208 else if( IsXMLToken( aLocalName, XML_Y ) ) 1209 { 1210 GetImport().GetMM100UnitConverter().convertMeasure( maPosition.Y, aValue ); 1211 bHasYPosition = true; 1212 } 1213 } 1214 else if( nPrefix == XML_NAMESPACE_CHART ) 1215 { 1216 if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) 1217 msAutoStyleName = aValue; 1218 } 1219 } 1220 1221 1222 if( mxTitleShape.is()) 1223 { 1224 if( bHasXPosition && bHasYPosition ) 1225 mxTitleShape->setPosition( maPosition ); 1226 1227 uno::Reference< beans::XPropertySet > xProp( mxTitleShape, uno::UNO_QUERY ); 1228 if( xProp.is()) 1229 { 1230 const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); 1231 if( pStylesCtxt ) 1232 { 1233 const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( 1234 mrImportHelper.GetChartFamilyID(), msAutoStyleName ); 1235 1236 if( pStyle && pStyle->ISA( XMLPropStyleContext )) 1237 (( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp ); 1238 } 1239 } 1240 } 1241 } 1242 1243 SvXMLImportContext* SchXMLTitleContext::CreateChildContext( 1244 sal_uInt16 nPrefix, 1245 const rtl::OUString& rLocalName, 1246 const uno::Reference< xml::sax::XAttributeList >& ) 1247 { 1248 SvXMLImportContext* pContext = 0; 1249 1250 if( nPrefix == XML_NAMESPACE_TEXT && 1251 IsXMLToken( rLocalName, XML_P ) ) 1252 { 1253 pContext = new SchXMLParagraphContext( GetImport(), rLocalName, mrTitle ); 1254 } 1255 else 1256 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 1257 1258 return pContext; 1259 } 1260 1261 // ---------------------------------------- 1262