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