1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <config_features.h> 21 22 #include <ChartView.hxx> 23 #include <chartview/DrawModelWrapper.hxx> 24 #include <NumberFormatterWrapper.hxx> 25 #include <VDiagram.hxx> 26 #include "VTitle.hxx" 27 #include "VButton.hxx" 28 #include <ShapeFactory.hxx> 29 #include <VCoordinateSystem.hxx> 30 #include <VSeriesPlotter.hxx> 31 #include <CommonConverters.hxx> 32 #include <TitleHelper.hxx> 33 #include <LegendHelper.hxx> 34 #include "VLegend.hxx" 35 #include <PropertyMapper.hxx> 36 #include <ChartModel.hxx> 37 #include <ChartTypeHelper.hxx> 38 #include <ScaleAutomatism.hxx> 39 #include <ObjectIdentifier.hxx> 40 #include <DiagramHelper.hxx> 41 #include <RelativePositionHelper.hxx> 42 #include <servicenames.hxx> 43 #include <AxisHelper.hxx> 44 #include <AxisIndexDefines.hxx> 45 #include <BaseGFXHelper.hxx> 46 #include <DataSeriesHelper.hxx> 47 #include <DateHelper.hxx> 48 #include <ExplicitCategoriesProvider.hxx> 49 #include <defines.hxx> 50 #include <unonames.hxx> 51 #include <editeng/frmdiritem.hxx> 52 #include <tools/globname.hxx> 53 #include <comphelper/fileformat.h> 54 #include <comphelper/scopeguard.hxx> 55 #include <comphelper/servicehelper.hxx> 56 #include <cppuhelper/supportsservice.hxx> 57 #include <unotools/streamwrap.hxx> 58 #include <svx/svdpage.hxx> 59 #include <svx/unopage.hxx> 60 #include <svx/unoshape.hxx> 61 #include <vcl/svapp.hxx> 62 #include <osl/mutex.hxx> 63 #include <svx/unofill.hxx> 64 #include <drawinglayer/XShapeDumper.hxx> 65 66 #include <time.h> 67 68 #include <com/sun/star/awt/Size.hpp> 69 #include <com/sun/star/awt/Point.hpp> 70 #include <com/sun/star/chart/ChartAxisPosition.hpp> 71 #include <com/sun/star/chart/TimeUnit.hpp> 72 #include <com/sun/star/chart2/AxisType.hpp> 73 #include <com/sun/star/chart2/StackingDirection.hpp> 74 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> 75 #include <com/sun/star/chart2/XChartTypeContainer.hpp> 76 #include <com/sun/star/chart2/XDataSeriesContainer.hpp> 77 #include <com/sun/star/chart2/RelativePosition.hpp> 78 #include <com/sun/star/chart2/RelativeSize.hpp> 79 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> 80 #include <com/sun/star/chart2/data/PivotTableFieldEntry.hpp> 81 #include <com/sun/star/drawing/GraphicExportFilter.hpp> 82 #include <com/sun/star/drawing/XShapeGroup.hpp> 83 #include <com/sun/star/embed/Aspects.hpp> 84 #include <com/sun/star/io/XSeekable.hpp> 85 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 86 #include <com/sun/star/util/XRefreshable.hpp> 87 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> 88 #include <com/sun/star/text/XText.hpp> 89 #include <com/sun/star/text/XTextDocument.hpp> 90 #include <com/sun/star/text/WritingMode2.hpp> 91 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> 92 #include <com/sun/star/view/XSelectionSupplier.hpp> 93 #include <svl/itempool.hxx> 94 #include <svl/languageoptions.hxx> 95 #include <comphelper/classids.hxx> 96 #include <servicenames_charttypes.hxx> 97 98 99 #include <rtl/ustring.hxx> 100 #include <sal/log.hxx> 101 102 #include <tools/diagnose_ex.h> 103 104 #include <memory> 105 namespace com { namespace sun { namespace star { namespace chart2 { class XChartDocument; } } } } 106 107 namespace chart { 108 109 using namespace ::com::sun::star; 110 using namespace ::com::sun::star::chart2; 111 using ::com::sun::star::uno::Reference; 112 using ::com::sun::star::uno::Sequence; 113 using ::com::sun::star::uno::Any; 114 115 namespace { 116 117 class theExplicitValueProviderUnoTunnelId : public rtl::Static<UnoTunnelIdInit, theExplicitValueProviderUnoTunnelId> {}; 118 119 typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; //first index is the dimension, second index is the axis index that indicates whether this is a main or secondary axis 120 typedef std::map< VCoordinateSystem*, tFullAxisIndex > tCoordinateSystemMap; 121 122 /** This class handles a collection of coordinate systems and is used for 123 * executing some action on all coordinate systems such as 124 * `prepareAutomaticAxisScaling` and `setExplicitScaleAndIncrement`. 125 * Moreover it contains the `aAutoScaling` object that is an instance of 126 * the `ScaleAutomatism` class. The initialization of `aAutoScaling` is 127 * performed in the `SeriesPlotterContainer::initAxisUsageList` method and is 128 * used in the `SeriesPlotterContainer::doAutoScaling` for calculating explicit 129 * scale and increment objects (see `SeriesPlotterContainer::doAutoScaling`). 130 */ 131 struct AxisUsage 132 { 133 AxisUsage(); 134 ~AxisUsage(); 135 136 void addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); 137 std::vector< VCoordinateSystem* > getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); 138 sal_Int32 getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ); 139 140 void prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ); 141 void setExplicitScaleAndIncrement( sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc ); 142 143 ScaleAutomatism aAutoScaling; 144 145 private: 146 tCoordinateSystemMap aCoordinateSystems; 147 std::map< sal_Int32, sal_Int32 > aMaxIndexPerDimension; 148 }; 149 150 AxisUsage::AxisUsage() 151 : aAutoScaling(AxisHelper::createDefaultScale(), Date(Date::SYSTEM)) 152 { 153 } 154 155 AxisUsage::~AxisUsage() 156 { 157 aCoordinateSystems.clear(); 158 } 159 160 void AxisUsage::addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) 161 { 162 if(!pCooSys) 163 return; 164 165 tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); 166 tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) ); 167 168 //use one scale only once for each coordinate system 169 //main axis are preferred over secondary axis 170 //value scales are preferred 171 if(aFound!=aCoordinateSystems.end()) 172 { 173 sal_Int32 nFoundAxisIndex = aFound->second.second; 174 if( nFoundAxisIndex < nAxisIndex ) 175 return; 176 sal_Int32 nFoundDimension = aFound->second.first; 177 if( nFoundDimension ==1 ) 178 return; 179 if( nFoundDimension < nDimensionIndex ) 180 return; 181 } 182 aCoordinateSystems[pCooSys] = aFullAxisIndex; 183 184 //set maximum scale index 185 std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); 186 if( aIter != aMaxIndexPerDimension.end() ) 187 { 188 sal_Int32 nCurrentMaxIndex = aIter->second; 189 if( nCurrentMaxIndex < nAxisIndex ) 190 aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; 191 } 192 else 193 aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; 194 } 195 196 std::vector< VCoordinateSystem* > AxisUsage::getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) 197 { 198 std::vector< VCoordinateSystem* > aRet; 199 200 for (auto const& coordinateSystem : aCoordinateSystems) 201 { 202 if( coordinateSystem.second.first != nDimensionIndex ) 203 continue; 204 if( coordinateSystem.second.second != nAxisIndex ) 205 continue; 206 aRet.push_back( coordinateSystem.first ); 207 } 208 209 return aRet; 210 } 211 212 sal_Int32 AxisUsage::getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ) 213 { 214 sal_Int32 nRet = -1; 215 std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); 216 if( aIter != aMaxIndexPerDimension.end() ) 217 nRet = aIter->second; 218 return nRet; 219 } 220 221 void AxisUsage::prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) 222 { 223 std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex); 224 for (VCoordinateSystem * i : aVCooSysList) 225 i->prepareAutomaticAxisScaling(rScaleAutomatism, nDimIndex, nAxisIndex); 226 } 227 228 void AxisUsage::setExplicitScaleAndIncrement( 229 sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc ) 230 { 231 std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex); 232 for (VCoordinateSystem* i : aVCooSysList) 233 i->setExplicitScaleAndIncrement(nDimIndex, nAxisIndex, rScale, rInc); 234 } 235 236 typedef std::vector<std::unique_ptr<VSeriesPlotter> > SeriesPlottersType; 237 238 /** This class is a container of `SeriesPlotter` objects (such as `PieChart` 239 * instances). It is used for initializing coordinate systems, axes and scales 240 * of all series plotters which belongs to the container. 241 */ 242 class SeriesPlotterContainer 243 { 244 public: 245 explicit SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList ); 246 ~SeriesPlotterContainer(); 247 248 /** It is used to set coordinate systems (`m_rVCooSysList`), this method 249 * is invoked by `ChartView::createShapes2D` before of 250 * `ChartView::impl_createDiagramAndContent`. 251 * Coordinate systems are retrieved through the `XCoordinateSystemContainer` 252 * interface implemented by a diagram object which is provided by the 253 * `ChartModel` object passed to the method (`rChartModel.getFirstDiagram()`). 254 * 255 * It is used for creating series plotters and appending them 256 * to `m_aSeriesPlotterList`. The created series plotters are initialized 257 * through data (number formats supplier, color scheme, data series), 258 * extracted from the chart model or the diagram objects. An exception is 259 * the explicit category provider that is retrieved through the 260 * `VCoordinateSystem` object used by the series plotter. 261 * 262 * It sets the minimum-maximum supplier for a coordinate system: 263 * this supplier is the series plotter itself which utilizes the given 264 * coordinate system. In fact `VSeriesPlotter` has `MinimumMaximumSupplier` 265 * as one of its base classes. 266 * Hence, for instance, a `PieChart`, which is a series plotter, is 267 * a `MinimumMaximumSupplier`, too. 268 */ 269 void initializeCooSysAndSeriesPlotter( ChartModel& rModel ); 270 271 /** This method is invoked by `ChartView::impl_createDiagramAndContent`. 272 * It iterates on every axis of every coordinate systems, and if the axis 273 * is not yet present in `m_aAxisUsageList` it creates a new `AxisUsage` 274 * object and initialize its `aAutoScaling` member to the `ScaleData` 275 * object of the current axis. 276 */ 277 void initAxisUsageList(const Date& rNullDate); 278 279 /** 280 * Perform automatic axis scaling and determine the amount and spacing of 281 * increments. It assumes that the caller has determined the size of the 282 * largest axis label text object prior to calling this method. 283 * 284 * The new axis scaling data will be stored in the VCoordinateSystem 285 * objects. The label alignment direction for each axis will also get 286 * determined during this process, and stored in VAxis. 287 * 288 * This method is invoked by `ChartView::impl_createDiagramAndContent` 289 * soon after `initAxisUsageList`. 290 * It initializes explicit scale and increment objects for all coordinate 291 * systems in `m_rVCooSysList`. 292 * This action is achieved by iterating on the `m_aAxisUsageList` container, 293 * and performing 3 steps: 294 * 1- call `VCoordinateSystem::prepareAutomaticAxisScaling` for setting 295 * scaling parameters of the `aAutoScaling` member (a `ScaleAutomatism` 296 * object) for the current `AxisUsage` instance 297 * (see `VCoordinateSystem::prepareAutomaticAxisScaling`); 298 * 2- calculate the explicit scale and increment objects 299 * (see ScaleAutomatism::calculateExplicitScaleAndIncrement); 300 * 3- set the explicit scale and increment objects for each coordinate 301 * system. 302 */ 303 void doAutoScaling( ChartModel& rModel ); 304 305 /** 306 * After auto-scaling is performed, call this method to set the explicit 307 * scaling and increment data to all relevant VAxis objects. 308 */ 309 void updateScalesAndIncrementsOnAxes(); 310 311 /** 312 * After auto-scaling is performed, call this method to set the explicit 313 * scaling data to all the plotters. 314 */ 315 void setScalesFromCooSysToPlotter(); 316 317 void setNumberFormatsFromAxes(); 318 drawing::Direction3D getPreferredAspectRatio(); 319 320 SeriesPlottersType& getSeriesPlotterList() { return m_aSeriesPlotterList; } 321 std::vector< std::unique_ptr<VCoordinateSystem> >& getCooSysList() { return m_rVCooSysList; } 322 std::vector< LegendEntryProvider* > getLegendEntryProviderList(); 323 324 void AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel ); 325 326 bool isCategoryPositionShifted( 327 const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ) const; 328 329 private: 330 /** A vector of series plotters. 331 */ 332 SeriesPlottersType m_aSeriesPlotterList; 333 334 /** A vector of coordinate systems. 335 */ 336 std::vector< std::unique_ptr<VCoordinateSystem> >& m_rVCooSysList; 337 338 /** A map whose key is a `XAxis` interface and the related value is 339 * an object of `AxisUsage` type. 340 */ 341 std::map< uno::Reference< XAxis >, AxisUsage > m_aAxisUsageList; 342 343 /** 344 * Max axis index of all dimensions. Currently this can be either 0 or 1 345 * since we only support primary and secondary axes per dimension. The 346 * value of 0 means all dimensions have only primary axis, while 1 means 347 * at least one dimension has a secondary axis. 348 */ 349 sal_Int32 m_nMaxAxisIndex; 350 351 bool m_bChartTypeUsesShiftedCategoryPositionPerDefault; 352 sal_Int32 m_nDefaultDateNumberFormat; 353 }; 354 355 SeriesPlotterContainer::SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList ) 356 : m_rVCooSysList( rVCooSysList ) 357 , m_nMaxAxisIndex(0) 358 , m_bChartTypeUsesShiftedCategoryPositionPerDefault(false) 359 , m_nDefaultDateNumberFormat(0) 360 { 361 } 362 363 SeriesPlotterContainer::~SeriesPlotterContainer() 364 { 365 // - remove plotter from coordinatesystems 366 for(auto & nC : m_rVCooSysList) 367 nC->clearMinimumAndMaximumSupplierList(); 368 } 369 370 std::vector< LegendEntryProvider* > SeriesPlotterContainer::getLegendEntryProviderList() 371 { 372 std::vector< LegendEntryProvider* > aRet( m_aSeriesPlotterList.size() ); 373 sal_Int32 nN = 0; 374 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList) 375 aRet[nN++] = aPlotter.get(); 376 return aRet; 377 } 378 379 VCoordinateSystem* findInCooSysList( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList 380 , const uno::Reference< XCoordinateSystem >& xCooSys ) 381 { 382 for(auto & pVCooSys : rVCooSysList) 383 { 384 if(pVCooSys->getModel()==xCooSys) 385 return pVCooSys.get(); 386 } 387 return nullptr; 388 } 389 390 VCoordinateSystem* lcl_getCooSysForPlotter( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList, MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) 391 { 392 if(!pMinimumAndMaximumSupplier) 393 return nullptr; 394 for(auto & pVCooSys : rVCooSysList) 395 { 396 if(pVCooSys->hasMinimumAndMaximumSupplier( pMinimumAndMaximumSupplier )) 397 return pVCooSys.get(); 398 } 399 return nullptr; 400 } 401 402 VCoordinateSystem* addCooSysToList( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList 403 , const uno::Reference< XCoordinateSystem >& xCooSys 404 , ChartModel& rChartModel ) 405 { 406 VCoordinateSystem* pExistingVCooSys = findInCooSysList( rVCooSysList, xCooSys ); 407 if( pExistingVCooSys ) 408 return pExistingVCooSys; 409 410 std::unique_ptr<VCoordinateSystem> pVCooSys = VCoordinateSystem::createCoordinateSystem(xCooSys ); 411 if(!pVCooSys) 412 return nullptr; 413 414 OUString aCooSysParticle( ObjectIdentifier::createParticleForCoordinateSystem( xCooSys, rChartModel ) ); 415 pVCooSys->setParticle(aCooSysParticle); 416 417 pVCooSys->setExplicitCategoriesProvider( new ExplicitCategoriesProvider(xCooSys, rChartModel) ); 418 rVCooSysList.push_back( std::move(pVCooSys) ); 419 return rVCooSysList.back().get(); 420 } 421 422 void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter( 423 ChartModel& rChartModel ) 424 { 425 uno::Reference< XDiagram > xDiagram( rChartModel.getFirstDiagram() ); 426 if( !xDiagram.is()) 427 return; 428 429 uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( static_cast< ::cppu::OWeakObject* >( &rChartModel ), uno::UNO_QUERY ); 430 if( rChartModel.hasInternalDataProvider() && DiagramHelper::isSupportingDateAxis( xDiagram ) ) 431 m_nDefaultDateNumberFormat=DiagramHelper::getDateNumberFormat( xNumberFormatsSupplier ); 432 433 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); 434 if(!nDimensionCount) 435 { 436 //@todo handle mixed dimension 437 nDimensionCount = 2; 438 } 439 440 bool bSortByXValues = false; 441 bool bConnectBars = false; 442 bool bGroupBarsPerAxis = true; 443 bool bIncludeHiddenCells = true; 444 sal_Int32 nStartingAngle = 90; 445 sal_Int32 n3DRelativeHeight = 100; 446 try 447 { 448 uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY_THROW ); 449 xDiaProp->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= bSortByXValues; 450 xDiaProp->getPropertyValue( "ConnectBars" ) >>= bConnectBars; 451 xDiaProp->getPropertyValue( "GroupBarsPerAxis" ) >>= bGroupBarsPerAxis; 452 xDiaProp->getPropertyValue( "IncludeHiddenCells" ) >>= bIncludeHiddenCells; 453 xDiaProp->getPropertyValue( "StartingAngle" ) >>= nStartingAngle; 454 455 if (nDimensionCount == 3) 456 { 457 xDiaProp->getPropertyValue( "3DRelativeHeight" ) >>= n3DRelativeHeight; 458 } 459 } 460 catch( const uno::Exception & ) 461 { 462 DBG_UNHANDLED_EXCEPTION("chart2" ); 463 } 464 465 //prepare for autoscaling and shape creation 466 // - create plotter for charttypes (for each first scale group at each plotter, as they are independent) 467 // - add series to plotter (thus each charttype can provide minimum and maximum values for autoscaling) 468 // - add plotter to coordinate systems 469 470 //iterate through all coordinate systems 471 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); 472 OSL_ASSERT( xCooSysContainer.is()); 473 if( !xCooSysContainer.is()) 474 return; 475 uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); 476 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); 477 sal_Int32 nGlobalSeriesIndex = 0;//for automatic symbols 478 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS ) 479 { 480 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] ); 481 VCoordinateSystem* pVCooSys = addCooSysToList(m_rVCooSysList,xCooSys,rChartModel); 482 483 //iterate through all chart types in the current coordinate system 484 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY ); 485 OSL_ASSERT( xChartTypeContainer.is()); 486 if( !xChartTypeContainer.is() ) 487 continue; 488 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() ); 489 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT ) 490 { 491 uno::Reference< XChartType > xChartType( aChartTypeList[nT] ); 492 if(nDimensionCount == 3 && xChartType->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE)) 493 { 494 uno::Reference< beans::XPropertySet > xPropertySet( xChartType, uno::UNO_QUERY ); 495 if (xPropertySet.is()) 496 { 497 try 498 { 499 sal_Int32 n3DRelativeHeightOldValue(100); 500 uno::Any aAny = xPropertySet->getPropertyValue( "3DRelativeHeight" ); 501 aAny >>= n3DRelativeHeightOldValue; 502 if (n3DRelativeHeightOldValue != n3DRelativeHeight) 503 xPropertySet->setPropertyValue( "3DRelativeHeight", uno::Any(n3DRelativeHeight) ); 504 } 505 catch (const uno::Exception&) { } 506 } 507 } 508 509 if(nT==0) 510 m_bChartTypeUsesShiftedCategoryPositionPerDefault = ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault( xChartType ); 511 512 bool bExcludingPositioning = DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_EXCLUDING; 513 VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( xChartType, nDimensionCount, bExcludingPositioning ); 514 if( !pPlotter ) 515 continue; 516 517 m_aSeriesPlotterList.push_back( std::unique_ptr<VSeriesPlotter>(pPlotter) ); 518 pPlotter->setNumberFormatsSupplier( xNumberFormatsSupplier ); 519 pPlotter->setColorScheme( xColorScheme ); 520 if(pVCooSys) 521 pPlotter->setExplicitCategoriesProvider( pVCooSys->getExplicitCategoriesProvider() ); 522 sal_Int32 nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( xDiagram, xChartType ); 523 524 if(pVCooSys) 525 pVCooSys->addMinimumAndMaximumSupplier(pPlotter); 526 527 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); 528 OSL_ASSERT( xDataSeriesContainer.is()); 529 if( !xDataSeriesContainer.is() ) 530 continue; 531 532 sal_Int32 zSlot=-1; 533 sal_Int32 xSlot=-1; 534 sal_Int32 ySlot=-1; 535 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); 536 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS ) 537 { 538 uno::Reference< XDataSeries > xDataSeries( aSeriesList[nS], uno::UNO_QUERY ); 539 if(!xDataSeries.is()) 540 continue; 541 if( !bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries) ) 542 continue; 543 544 std::unique_ptr<VDataSeries> pSeries(new VDataSeries( xDataSeries )); 545 546 pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex); 547 nGlobalSeriesIndex++; 548 549 if( bSortByXValues ) 550 pSeries->doSortByXValues(); 551 552 pSeries->setConnectBars( bConnectBars ); 553 pSeries->setGroupBarsPerAxis( bGroupBarsPerAxis ); 554 pSeries->setStartingAngle( nStartingAngle ); 555 556 pSeries->setMissingValueTreatment( nMissingValueTreatment ); 557 558 OUString aSeriesParticle( ObjectIdentifier::createParticleForSeries( 0, nCS, nT, nS ) ); 559 pSeries->setParticle(aSeriesParticle); 560 561 OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) ); 562 pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole); 563 564 //ignore secondary axis for charttypes that do not support them 565 if( pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX && 566 !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) ) 567 { 568 pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX); 569 } 570 571 StackingDirection eDirection = pSeries->getStackingDirection(); 572 switch(eDirection) 573 { 574 case StackingDirection_NO_STACKING: 575 xSlot++; ySlot=-1; 576 if(zSlot<0) 577 zSlot=0; 578 break; 579 case StackingDirection_Y_STACKING: 580 ySlot++; 581 if(xSlot<0) 582 xSlot=0; 583 if(zSlot<0) 584 zSlot=0; 585 break; 586 case StackingDirection_Z_STACKING: 587 zSlot++; xSlot=-1; ySlot=-1; 588 break; 589 default: 590 // UNO enums have one additional auto-generated case 591 break; 592 } 593 pPlotter->addSeries( std::move(pSeries), zSlot, xSlot, ySlot ); 594 } 595 } 596 } 597 598 //transport seriesnames to the coordinatesystems if needed 599 if( !m_aSeriesPlotterList.empty() ) 600 { 601 uno::Sequence< OUString > aSeriesNames; 602 bool bSeriesNamesInitialized = false; 603 for(auto & pVCooSys : m_rVCooSysList) 604 { 605 if( pVCooSys->needSeriesNamesForAxis() ) 606 { 607 if(!bSeriesNamesInitialized) 608 { 609 aSeriesNames = m_aSeriesPlotterList[0]->getSeriesNames(); 610 bSeriesNamesInitialized = true; 611 } 612 pVCooSys->setSeriesNamesForAxis( aSeriesNames ); 613 } 614 } 615 } 616 } 617 618 bool SeriesPlotterContainer::isCategoryPositionShifted( 619 const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ) const 620 { 621 if (rSourceScale.AxisType == AxisType::CATEGORY && m_bChartTypeUsesShiftedCategoryPositionPerDefault) 622 return true; 623 624 if (rSourceScale.AxisType==AxisType::CATEGORY && bHasComplexCategories) 625 return true; 626 627 if (rSourceScale.AxisType == AxisType::DATE) 628 return true; 629 630 if (rSourceScale.AxisType == AxisType::SERIES) 631 return true; 632 633 return false; 634 } 635 636 void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate) 637 { 638 m_aAxisUsageList.clear(); 639 640 // Loop through coordinate systems in the diagram (though for now 641 // there should only be one coordinate system per diagram). 642 for (auto & pVCooSys : m_rVCooSysList) 643 { 644 uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel(); 645 sal_Int32 nDimCount = xCooSys->getDimension(); 646 647 for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) 648 { 649 bool bDateAxisAllowed = ChartTypeHelper::isSupportingDateAxis( 650 AxisHelper::getChartTypeByIndex(xCooSys, 0), nDimIndex); 651 652 // Each dimension may have primary and secondary axes. 653 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex); 654 for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; ++nAxisIndex) 655 { 656 uno::Reference<XAxis> xAxis = xCooSys->getAxisByDimension(nDimIndex, nAxisIndex); 657 658 if (!xAxis.is()) 659 continue; 660 661 if (m_aAxisUsageList.find(xAxis) == m_aAxisUsageList.end()) 662 { 663 // Create axis usage object for this axis. 664 665 chart2::ScaleData aSourceScale = xAxis->getScaleData(); 666 ExplicitCategoriesProvider* pCatProvider = pVCooSys->getExplicitCategoriesProvider(); 667 if (nDimIndex == 0) 668 AxisHelper::checkDateAxis( aSourceScale, pCatProvider, bDateAxisAllowed ); 669 670 bool bHasComplexCat = pCatProvider && pCatProvider->hasComplexCategories(); 671 aSourceScale.ShiftedCategoryPosition = isCategoryPositionShifted(aSourceScale, bHasComplexCat); 672 673 m_aAxisUsageList[xAxis].aAutoScaling = ScaleAutomatism(aSourceScale, rNullDate); 674 } 675 676 AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis]; 677 rAxisUsage.addCoordinateSystem(pVCooSys.get(), nDimIndex, nAxisIndex); 678 } 679 } 680 } 681 682 // Determine the highest axis index of all dimensions. 683 m_nMaxAxisIndex = 0; 684 for (auto & pVCooSys : m_rVCooSysList) 685 { 686 uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel(); 687 sal_Int32 nDimCount = xCooSys->getDimension(); 688 689 for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) 690 { 691 for (auto & axisUsage : m_aAxisUsageList) 692 { 693 sal_Int32 nLocalMax = axisUsage.second.getMaxAxisIndexForDimension(nDimIndex); 694 if (m_nMaxAxisIndex < nLocalMax) 695 m_nMaxAxisIndex = nLocalMax; 696 } 697 } 698 } 699 } 700 701 void SeriesPlotterContainer::setScalesFromCooSysToPlotter() 702 { 703 //set scales to plotter to enable them to provide the preferred scene AspectRatio 704 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList ) 705 { 706 VSeriesPlotter* pSeriesPlotter = aPlotter.get(); 707 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); 708 if(pVCooSys) 709 { 710 pSeriesPlotter->setScales( pVCooSys->getExplicitScales(0,0), pVCooSys->getPropertySwapXAndYAxis() ); 711 sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension(1);//only additional value axis are relevant for series plotter 712 for( sal_Int32 nI=1; nI<=nMaxAxisIndex; nI++ ) 713 pSeriesPlotter->addSecondaryValueScale( pVCooSys->getExplicitScale(1,nI), nI ); 714 } 715 } 716 } 717 718 void SeriesPlotterContainer::setNumberFormatsFromAxes() 719 { 720 //set numberformats to plotter to enable them to display the data labels in the numberformat of the axis 721 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList ) 722 { 723 VSeriesPlotter* pSeriesPlotter = aPlotter.get(); 724 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); 725 if(pVCooSys) 726 { 727 AxesNumberFormats aAxesNumberFormats; 728 const uno::Reference< XCoordinateSystem >& xCooSys = pVCooSys->getModel(); 729 sal_Int32 nDimensionCount = xCooSys->getDimension(); 730 for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nDimensionCount; ++nDimensionIndex) 731 { 732 const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); 733 for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) 734 { 735 try 736 { 737 Reference< beans::XPropertySet > xAxisProp( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY ); 738 if( xAxisProp.is()) 739 { 740 sal_Int32 nNumberFormatKey(0); 741 if( xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey ) 742 { 743 aAxesNumberFormats.setFormat( nNumberFormatKey, nDimensionIndex, nAxisIndex ); 744 } 745 else if( nDimensionIndex==0 ) 746 { 747 //provide a default date format for date axis with own data 748 aAxesNumberFormats.setFormat( m_nDefaultDateNumberFormat, nDimensionIndex, nAxisIndex ); 749 } 750 } 751 } 752 catch( const lang::IndexOutOfBoundsException& e ) 753 { 754 SAL_WARN("chart2", "Exception caught. " << e ); 755 } 756 } 757 } 758 pSeriesPlotter->setAxesNumberFormats( aAxesNumberFormats ); 759 } 760 } 761 } 762 763 void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes() 764 { 765 for(auto & nC : m_rVCooSysList) 766 nC->updateScalesAndIncrementsOnAxes(); 767 } 768 769 void SeriesPlotterContainer::doAutoScaling( ChartModel& rChartModel ) 770 { 771 if (m_aSeriesPlotterList.empty() || m_aAxisUsageList.empty()) 772 // We need these two containers populated to do auto-scaling. Bail out. 773 return; 774 775 //iterate over the main scales first than secondary axis 776 for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; ++nAxisIndex) 777 { 778 // - first do autoscale for all x and z scales (because they are treated independent) 779 for (auto & axisUsage : m_aAxisUsageList) 780 { 781 AxisUsage& rAxisUsage = axisUsage.second; 782 783 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 0, nAxisIndex); 784 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 2, nAxisIndex); 785 786 ExplicitScaleData aExplicitScale; 787 ExplicitIncrementData aExplicitIncrement; 788 rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); 789 790 rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement); 791 rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement); 792 } 793 794 // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already ) 795 for (auto & axisUsage : m_aAxisUsageList) 796 { 797 AxisUsage& rAxisUsage = axisUsage.second; 798 799 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAxisIndex); 800 801 ExplicitScaleData aExplicitScale; 802 ExplicitIncrementData aExplicitIncrement; 803 rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); 804 805 rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement); 806 rAxisUsage.setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScale, aExplicitIncrement); 807 rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement); 808 } 809 } 810 AdaptScaleOfYAxisWithoutAttachedSeries( rChartModel ); 811 } 812 813 void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel ) 814 { 815 //issue #i80518# 816 for( sal_Int32 nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ ) 817 { 818 for (auto & axisUsage : m_aAxisUsageList) 819 { 820 AxisUsage& rAxisUsage = axisUsage.second; 821 std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems( 1, nAxisIndex ); 822 if( aVCooSysList_Y.empty() ) 823 continue; 824 825 uno::Reference< XDiagram > xDiagram( rModel.getFirstDiagram() ); 826 if (!xDiagram.is()) 827 continue; 828 829 bool bSeriesAttachedToThisAxis = false; 830 sal_Int32 nAttachedAxisIndex = -1; 831 { 832 std::vector< Reference< XDataSeries > > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); 833 for (auto const& series : aSeriesVector) 834 { 835 sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series); 836 if( nAxisIndex == nCurrentIndex ) 837 { 838 bSeriesAttachedToThisAxis = true; 839 break; 840 } 841 else if( nAttachedAxisIndex<0 || nAttachedAxisIndex>nCurrentIndex ) 842 nAttachedAxisIndex=nCurrentIndex; 843 } 844 } 845 846 if (bSeriesAttachedToThisAxis || nAttachedAxisIndex < 0) 847 continue; 848 849 for(VCoordinateSystem* nC : aVCooSysList_Y) 850 { 851 nC->prepareAutomaticAxisScaling( rAxisUsage.aAutoScaling, 1, nAttachedAxisIndex ); 852 853 ExplicitScaleData aExplicitScaleSource = nC->getExplicitScale( 1,nAttachedAxisIndex ); 854 ExplicitIncrementData aExplicitIncrementSource = nC->getExplicitIncrement( 1,nAttachedAxisIndex ); 855 856 ExplicitScaleData aExplicitScaleDest = nC->getExplicitScale( 1,nAxisIndex ); 857 ExplicitIncrementData aExplicitIncrementDest = nC->getExplicitIncrement( 1,nAxisIndex ); 858 859 aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation; 860 aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling; 861 aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType; 862 863 aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue; 864 865 ScaleData aScale( rAxisUsage.aAutoScaling.getScale() ); 866 if( !aScale.Minimum.hasValue() ) 867 { 868 bool bNewMinOK = true; 869 double fMax=0.0; 870 if( aScale.Maximum >>= fMax ) 871 bNewMinOK = (aExplicitScaleSource.Minimum <= fMax); 872 if( bNewMinOK ) 873 aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum; 874 } 875 else 876 aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum; 877 878 if( !aScale.Maximum.hasValue() ) 879 { 880 bool bNewMaxOK = true; 881 double fMin=0.0; 882 if( aScale.Minimum >>= fMin ) 883 bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum); 884 if( bNewMaxOK ) 885 aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum; 886 } 887 if( !aScale.Origin.hasValue() ) 888 aExplicitScaleDest.Origin = aExplicitScaleSource.Origin; 889 890 if( !aScale.IncrementData.Distance.hasValue() ) 891 aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance; 892 893 bool bAutoMinorInterval = true; 894 if( aScale.IncrementData.SubIncrements.getLength() ) 895 bAutoMinorInterval = !( aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() ); 896 if( bAutoMinorInterval ) 897 { 898 if( !aExplicitIncrementDest.SubIncrements.empty() && !aExplicitIncrementSource.SubIncrements.empty() ) 899 aExplicitIncrementDest.SubIncrements[0].IntervalCount = 900 aExplicitIncrementSource.SubIncrements[0].IntervalCount; 901 } 902 903 nC->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScaleDest, aExplicitIncrementDest ); 904 } 905 } 906 } 907 908 if( AxisHelper::isAxisPositioningEnabled() ) 909 { 910 //correct origin for y main axis (the origin is where the other main axis crosses) 911 sal_Int32 nAxisIndex=0; 912 sal_Int32 nDimensionIndex=1; 913 for (auto & axisUsage : m_aAxisUsageList) 914 { 915 AxisUsage& rAxisUsage = axisUsage.second; 916 std::vector< VCoordinateSystem* > aVCooSysList = rAxisUsage.getCoordinateSystems(nDimensionIndex,nAxisIndex); 917 size_t nC; 918 for( nC=0; nC < aVCooSysList.size(); nC++) 919 { 920 ExplicitScaleData aExplicitScale( aVCooSysList[nC]->getExplicitScale( nDimensionIndex, nAxisIndex ) ); 921 ExplicitIncrementData aExplicitIncrement( aVCooSysList[nC]->getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); 922 923 Reference< chart2::XCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() ); 924 Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); 925 Reference< beans::XPropertySet > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ), uno::UNO_QUERY ); 926 927 css::chart::ChartAxisPosition eCrossingMainAxisPos( css::chart::ChartAxisPosition_ZERO ); 928 if( xCrossingMainAxis.is() ) 929 { 930 xCrossingMainAxis->getPropertyValue("CrossoverPosition") >>= eCrossingMainAxisPos; 931 if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_VALUE ) 932 { 933 double fValue = 0.0; 934 xCrossingMainAxis->getPropertyValue("CrossoverValue") >>= fValue; 935 aExplicitScale.Origin = fValue; 936 } 937 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_ZERO ) 938 aExplicitScale.Origin = 0.0; 939 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_START ) 940 aExplicitScale.Origin = aExplicitScale.Minimum; 941 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_END ) 942 aExplicitScale.Origin = aExplicitScale.Maximum; 943 } 944 945 aVCooSysList[nC]->setExplicitScaleAndIncrement( nDimensionIndex, nAxisIndex, aExplicitScale, aExplicitIncrement ); 946 } 947 } 948 } 949 } 950 951 drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio() 952 { 953 drawing::Direction3D aPreferredAspectRatio(1.0,1.0,1.0); 954 955 //get a list of all preferred aspect ratios and combine them 956 //first with special demands wins (less or equal zero <-> arbitrary) 957 double fx, fy, fz; 958 fx = fy = fz = -1.0; 959 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList ) 960 { 961 drawing::Direction3D aSingleRatio( aPlotter->getPreferredDiagramAspectRatio() ); 962 if( fx<0 && aSingleRatio.DirectionX>0 ) 963 fx = aSingleRatio.DirectionX; 964 965 if( fy<0 && aSingleRatio.DirectionY>0 ) 966 { 967 if( fx>0 && aSingleRatio.DirectionX>0 ) 968 fy = fx*aSingleRatio.DirectionY/aSingleRatio.DirectionX; 969 else if( fz>0 && aSingleRatio.DirectionZ>0 ) 970 fy = fz*aSingleRatio.DirectionY/aSingleRatio.DirectionZ; 971 else 972 fy = aSingleRatio.DirectionY; 973 } 974 975 if( fz<0 && aSingleRatio.DirectionZ>0 ) 976 { 977 if( fx>0 && aSingleRatio.DirectionX>0 ) 978 fz = fx*aSingleRatio.DirectionZ/aSingleRatio.DirectionX; 979 else if( fy>0 && aSingleRatio.DirectionY>0 ) 980 fz = fy*aSingleRatio.DirectionZ/aSingleRatio.DirectionY; 981 else 982 fz = aSingleRatio.DirectionZ; 983 } 984 985 if( fx>0 && fy>0 && fz>0 ) 986 break; 987 } 988 aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz); 989 return aPreferredAspectRatio; 990 } 991 992 } 993 994 struct CreateShapeParam2D 995 { 996 css::awt::Rectangle maRemainingSpace; 997 998 std::shared_ptr<SeriesPlotterContainer> mpSeriesPlotterContainer; 999 1000 std::shared_ptr<VTitle> mpVTitleX; 1001 std::shared_ptr<VTitle> mpVTitleY; 1002 std::shared_ptr<VTitle> mpVTitleZ; 1003 1004 std::shared_ptr<VTitle> mpVTitleSecondX; 1005 std::shared_ptr<VTitle> mpVTitleSecondY; 1006 1007 css::uno::Reference<css::drawing::XShape> mxMarkHandles; 1008 css::uno::Reference<css::drawing::XShape> mxPlotAreaWithAxes; 1009 1010 css::uno::Reference<css::drawing::XShapes> mxDiagramWithAxesShapes; 1011 1012 bool mbAutoPosTitleX; 1013 bool mbAutoPosTitleY; 1014 bool mbAutoPosTitleZ; 1015 1016 bool mbAutoPosSecondTitleX; 1017 bool mbAutoPosSecondTitleY; 1018 1019 bool mbUseFixedInnerSize; 1020 1021 CreateShapeParam2D() : 1022 mbAutoPosTitleX(true), 1023 mbAutoPosTitleY(true), 1024 mbAutoPosTitleZ(true), 1025 mbAutoPosSecondTitleX(true), 1026 mbAutoPosSecondTitleY(true), 1027 mbUseFixedInnerSize(false) {} 1028 }; 1029 1030 const uno::Sequence<sal_Int8>& ExplicitValueProvider::getUnoTunnelId() 1031 { 1032 return theExplicitValueProviderUnoTunnelId::get().getSeq(); 1033 } 1034 1035 ExplicitValueProvider* ExplicitValueProvider::getExplicitValueProvider( 1036 const Reference< uno::XInterface >& xChartView ) 1037 { 1038 ExplicitValueProvider* pExplicitValueProvider=nullptr; 1039 1040 Reference< lang::XUnoTunnel > xTunnel( xChartView, uno::UNO_QUERY ); 1041 if( xTunnel.is() ) 1042 { 1043 pExplicitValueProvider = reinterpret_cast<ExplicitValueProvider*>(xTunnel->getSomething( 1044 ExplicitValueProvider::getUnoTunnelId() )); 1045 } 1046 return pExplicitValueProvider; 1047 } 1048 1049 ChartView::ChartView( 1050 uno::Reference<uno::XComponentContext> const & xContext, 1051 ChartModel& rModel) 1052 : m_aMutex() 1053 , m_xCC(xContext) 1054 , mrChartModel(rModel) 1055 , m_xShapeFactory() 1056 , m_xDrawPage() 1057 , m_pDrawModelWrapper() 1058 , m_aListenerContainer( m_aMutex ) 1059 , m_bViewDirty(true) 1060 , m_bInViewUpdate(false) 1061 , m_bViewUpdatePending(false) 1062 , m_bRefreshAddIn(true) 1063 , m_aPageResolution(1000,1000) 1064 , m_bPointsWereSkipped(false) 1065 , m_nScaleXNumerator(1) 1066 , m_nScaleXDenominator(1) 1067 , m_nScaleYNumerator(1) 1068 , m_nScaleYDenominator(1) 1069 , m_bSdrViewIsInEditMode(false) 1070 , m_aResultingDiagramRectangleExcludingAxes(0,0,0,0) 1071 { 1072 init(); 1073 } 1074 1075 void ChartView::init() 1076 { 1077 if( !m_pDrawModelWrapper.get() ) 1078 { 1079 SolarMutexGuard aSolarGuard; 1080 m_pDrawModelWrapper = std::make_shared< DrawModelWrapper >(); 1081 m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory(); 1082 m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage(); 1083 StartListening( m_pDrawModelWrapper->getSdrModel() ); 1084 } 1085 } 1086 1087 void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& ) 1088 { 1089 init(); 1090 } 1091 1092 ChartView::~ChartView() 1093 { 1094 maTimeBased.maTimer.Stop(); 1095 // #i120831#. In ChartView::initialize(), m_xShapeFactory is created from SdrModel::getUnoModel() and indirectly 1096 // from SfxBaseModel, it needs call dispose() to make sure SfxBaseModel object is freed correctly. 1097 uno::Reference< lang::XComponent > xComp( m_xShapeFactory, uno::UNO_QUERY); 1098 if ( xComp.is() ) 1099 xComp->dispose(); 1100 1101 if( m_pDrawModelWrapper.get() ) 1102 { 1103 SolarMutexGuard aSolarGuard; 1104 EndListening( m_pDrawModelWrapper->getSdrModel() ); 1105 m_pDrawModelWrapper.reset(); 1106 } 1107 m_xDrawPage = nullptr; 1108 impl_deleteCoordinateSystems(); 1109 } 1110 1111 void ChartView::impl_deleteCoordinateSystems() 1112 { 1113 //delete all coordinate systems 1114 m_aVCooSysList.clear(); 1115 } 1116 1117 // datatransfer::XTransferable 1118 namespace 1119 { 1120 const OUString lcl_aGDIMetaFileMIMEType( 1121 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ); 1122 const OUString lcl_aGDIMetaFileMIMETypeHighContrast( 1123 "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" ); 1124 } // anonymous namespace 1125 1126 void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream 1127 , bool bUseHighContrast ) 1128 { 1129 if( !m_xDrawPage.is() ) 1130 return; 1131 1132 // creating the graphic exporter 1133 uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( m_xCC ); 1134 1135 uno::Sequence< beans::PropertyValue > aProps(3); 1136 aProps[0].Name = "FilterName"; 1137 aProps[0].Value <<= OUString("SVM"); 1138 1139 aProps[1].Name = "OutputStream"; 1140 aProps[1].Value <<= xOutStream; 1141 1142 uno::Sequence< beans::PropertyValue > aFilterData(8); 1143 aFilterData[0].Name = "ExportOnlyBackground"; 1144 aFilterData[0].Value <<= false; 1145 aFilterData[1].Name = "HighContrast"; 1146 aFilterData[1].Value <<= bUseHighContrast; 1147 1148 aFilterData[2].Name = "Version"; 1149 const sal_Int32 nVersion = SOFFICE_FILEFORMAT_50; 1150 aFilterData[2].Value <<= nVersion; 1151 1152 aFilterData[3].Name = "CurrentPage"; 1153 aFilterData[3].Value <<= uno::Reference< uno::XInterface >( m_xDrawPage, uno::UNO_QUERY ); 1154 1155 //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% 1156 aFilterData[4].Name = "ScaleXNumerator"; 1157 aFilterData[4].Value <<= m_nScaleXNumerator; 1158 aFilterData[5].Name = "ScaleXDenominator"; 1159 aFilterData[5].Value <<= m_nScaleXDenominator; 1160 aFilterData[6].Name = "ScaleYNumerator"; 1161 aFilterData[6].Value <<= m_nScaleYNumerator; 1162 aFilterData[7].Name = "ScaleYDenominator"; 1163 aFilterData[7].Value <<= m_nScaleYDenominator; 1164 1165 1166 aProps[2].Name = "FilterData"; 1167 aProps[2].Value <<= aFilterData; 1168 1169 xExporter->setSourceDocument( uno::Reference< lang::XComponent >( m_xDrawPage, uno::UNO_QUERY) ); 1170 if( xExporter->filter( aProps ) ) 1171 { 1172 xOutStream->flush(); 1173 xOutStream->closeOutput(); 1174 uno::Reference< io::XSeekable > xSeekable( xOutStream, uno::UNO_QUERY ); 1175 if( xSeekable.is() ) 1176 xSeekable->seek(0); 1177 } 1178 } 1179 1180 uno::Any SAL_CALL ChartView::getTransferData( const datatransfer::DataFlavor& aFlavor ) 1181 { 1182 bool bHighContrastMetaFile( aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast); 1183 uno::Any aRet; 1184 if( ! (bHighContrastMetaFile || aFlavor.MimeType == lcl_aGDIMetaFileMIMEType) ) 1185 return aRet; 1186 1187 update(); 1188 1189 SvMemoryStream aStream( 1024, 1024 ); 1190 utl::OStreamWrapper* pStreamWrapper = new utl::OStreamWrapper( aStream ); 1191 1192 uno::Reference< io::XOutputStream > xOutStream( pStreamWrapper ); 1193 uno::Reference< io::XInputStream > xInStream( pStreamWrapper ); 1194 uno::Reference< io::XSeekable > xSeekable( pStreamWrapper ); 1195 1196 if( xOutStream.is() ) 1197 { 1198 this->getMetaFile( xOutStream, bHighContrastMetaFile ); 1199 1200 if( xInStream.is() && xSeekable.is() ) 1201 { 1202 xSeekable->seek(0); 1203 sal_Int32 nBytesToRead = xInStream->available(); 1204 uno::Sequence< sal_Int8 > aSeq( nBytesToRead ); 1205 xInStream->readBytes( aSeq, nBytesToRead); 1206 aRet <<= aSeq; 1207 xInStream->closeInput(); 1208 } 1209 } 1210 1211 return aRet; 1212 } 1213 uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors() 1214 { 1215 uno::Sequence< datatransfer::DataFlavor > aRet(2); 1216 1217 aRet[0] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMEType, 1218 "GDIMetaFile", 1219 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); 1220 aRet[1] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast, 1221 "GDIMetaFile", 1222 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); 1223 1224 return aRet; 1225 } 1226 sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) 1227 { 1228 return ( aFlavor.MimeType == lcl_aGDIMetaFileMIMEType || 1229 aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast ); 1230 } 1231 1232 // ____ XUnoTunnel ___ 1233 ::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier ) 1234 { 1235 if( aIdentifier.getLength() == 16 && memcmp( ExplicitValueProvider::getUnoTunnelId().getConstArray(), 1236 aIdentifier.getConstArray(), 16 ) == 0 ) 1237 { 1238 ExplicitValueProvider* pProvider = this; 1239 return reinterpret_cast<sal_Int64>(pProvider); 1240 } 1241 return 0; 1242 } 1243 1244 // lang::XServiceInfo 1245 1246 OUString SAL_CALL ChartView::getImplementationName() 1247 { 1248 return OUString(CHART_VIEW_SERVICE_IMPLEMENTATION_NAME); 1249 } 1250 1251 sal_Bool SAL_CALL ChartView::supportsService( const OUString& rServiceName ) 1252 { 1253 return cppu::supportsService(this, rServiceName); 1254 } 1255 1256 css::uno::Sequence< OUString > SAL_CALL ChartView::getSupportedServiceNames() 1257 { 1258 return { CHART_VIEW_SERVICE_NAME }; 1259 } 1260 1261 static ::basegfx::B3DHomMatrix createTransformationSceneToScreen( 1262 const ::basegfx::B2IRectangle& rDiagramRectangleWithoutAxes ) 1263 { 1264 ::basegfx::B3DHomMatrix aM; 1265 aM.scale(double(rDiagramRectangleWithoutAxes.getWidth())/FIXED_SIZE_FOR_3D_CHART_VOLUME 1266 , -double(rDiagramRectangleWithoutAxes.getHeight())/FIXED_SIZE_FOR_3D_CHART_VOLUME, 1.0 ); 1267 aM.translate(double(rDiagramRectangleWithoutAxes.getMinX()) 1268 , double(rDiagramRectangleWithoutAxes.getMinY()+rDiagramRectangleWithoutAxes.getHeight()-1), 0); 1269 return aM; 1270 } 1271 1272 namespace 1273 { 1274 1275 bool lcl_IsPieOrDonut( const uno::Reference< XDiagram >& xDiagram ) 1276 { 1277 //special treatment for pie charts 1278 //the size is checked after complete creation to get the datalabels into the given space 1279 1280 //todo: this is just a workaround at the moment for pie and donut labels 1281 return DiagramHelper::isPieOrDonutChart( xDiagram ); 1282 } 1283 1284 void lcl_setDefaultWritingMode( const std::shared_ptr< DrawModelWrapper >& pDrawModelWrapper, ChartModel& rModel) 1285 { 1286 //get writing mode from parent document: 1287 if( SvtLanguageOptions().IsCTLFontEnabled() ) 1288 { 1289 try 1290 { 1291 sal_Int16 nWritingMode=-1; 1292 uno::Reference< beans::XPropertySet > xParentProps( rModel.getParent(), uno::UNO_QUERY ); 1293 uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSupplier( xParentProps, uno::UNO_QUERY ); 1294 if( xStyleFamiliesSupplier.is() ) 1295 { 1296 uno::Reference< container::XNameAccess > xStylesFamilies( xStyleFamiliesSupplier->getStyleFamilies() ); 1297 if( xStylesFamilies.is() ) 1298 { 1299 if( !xStylesFamilies->hasByName( "PageStyles" ) ) 1300 { 1301 //draw/impress is parent document 1302 uno::Reference< lang::XMultiServiceFactory > xFatcory( xParentProps, uno::UNO_QUERY ); 1303 if( xFatcory.is() ) 1304 { 1305 uno::Reference< beans::XPropertySet > xDrawDefaults( xFatcory->createInstance( "com.sun.star.drawing.Defaults" ), uno::UNO_QUERY ); 1306 if( xDrawDefaults.is() ) 1307 xDrawDefaults->getPropertyValue( "WritingMode" ) >>= nWritingMode; 1308 } 1309 } 1310 else 1311 { 1312 uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( "PageStyles" ), uno::UNO_QUERY ); 1313 if( xPageStyles.is() ) 1314 { 1315 OUString aPageStyle; 1316 1317 uno::Reference< text::XTextDocument > xTextDocument( xParentProps, uno::UNO_QUERY ); 1318 if( xTextDocument.is() ) 1319 { 1320 //writer is parent document 1321 //retrieve the current page style from the text cursor property PageStyleName 1322 1323 uno::Reference< text::XTextEmbeddedObjectsSupplier > xTextEmbeddedObjectsSupplier( xTextDocument, uno::UNO_QUERY ); 1324 if( xTextEmbeddedObjectsSupplier.is() ) 1325 { 1326 uno::Reference< container::XNameAccess > xEmbeddedObjects( xTextEmbeddedObjectsSupplier->getEmbeddedObjects() ); 1327 if( xEmbeddedObjects.is() ) 1328 { 1329 uno::Sequence< OUString > aNames( xEmbeddedObjects->getElementNames() ); 1330 1331 sal_Int32 nCount = aNames.getLength(); 1332 for( sal_Int32 nN=0; nN<nCount; nN++ ) 1333 { 1334 uno::Reference< beans::XPropertySet > xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY ); 1335 if( xEmbeddedProps.is() ) 1336 { 1337 static OUString aChartCLSID = SvGlobalName( SO3_SCH_CLASSID ).GetHexName(); 1338 OUString aCLSID; 1339 xEmbeddedProps->getPropertyValue( "CLSID" ) >>= aCLSID; 1340 if( aCLSID == aChartCLSID ) 1341 { 1342 uno::Reference< text::XTextContent > xEmbeddedObject( xEmbeddedProps, uno::UNO_QUERY ); 1343 if( xEmbeddedObject.is() ) 1344 { 1345 uno::Reference< text::XTextRange > xAnchor( xEmbeddedObject->getAnchor() ); 1346 if( xAnchor.is() ) 1347 { 1348 uno::Reference< beans::XPropertySet > xAnchorProps( xAnchor, uno::UNO_QUERY ); 1349 if( xAnchorProps.is() ) 1350 { 1351 xAnchorProps->getPropertyValue( "WritingMode" ) >>= nWritingMode; 1352 } 1353 uno::Reference< text::XText > xText( xAnchor->getText() ); 1354 if( xText.is() ) 1355 { 1356 uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); 1357 if( xTextCursorProps.is() ) 1358 xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle; 1359 } 1360 } 1361 } 1362 break; 1363 } 1364 } 1365 } 1366 } 1367 } 1368 if( aPageStyle.isEmpty() ) 1369 { 1370 uno::Reference< text::XText > xText( xTextDocument->getText() ); 1371 if( xText.is() ) 1372 { 1373 uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); 1374 if( xTextCursorProps.is() ) 1375 xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle; 1376 } 1377 } 1378 } 1379 else 1380 { 1381 //Calc is parent document 1382 xParentProps->getPropertyValue( "PageStyle" ) >>= aPageStyle; 1383 if(aPageStyle.isEmpty()) 1384 aPageStyle = "Default"; 1385 } 1386 if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE ) 1387 { 1388 uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY ); 1389 if( xPageStyle.is() ) 1390 xPageStyle->getPropertyValue( "WritingMode" ) >>= nWritingMode; 1391 } 1392 } 1393 } 1394 } 1395 } 1396 if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE ) 1397 { 1398 if( pDrawModelWrapper.get() ) 1399 pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SvxFrameDirectionItem(static_cast<SvxFrameDirection>(nWritingMode), EE_PARA_WRITINGDIR) ); 1400 } 1401 } 1402 catch( const uno::Exception& ) 1403 { 1404 DBG_UNHANDLED_EXCEPTION("chart2" ); 1405 } 1406 } 1407 } 1408 1409 sal_Int16 lcl_getDefaultWritingModeFromPool( const std::shared_ptr<DrawModelWrapper>& pDrawModelWrapper ) 1410 { 1411 sal_Int16 nWritingMode = text::WritingMode2::LR_TB; 1412 if(!pDrawModelWrapper) 1413 return nWritingMode; 1414 1415 const SfxPoolItem& rItem = pDrawModelWrapper->GetItemPool().GetDefaultItem(EE_PARA_WRITINGDIR); 1416 nWritingMode 1417 = static_cast<sal_Int16>(static_cast<const SvxFrameDirectionItem&>(rItem).GetValue()); 1418 return nWritingMode; 1419 } 1420 1421 } //end anonymous namespace 1422 1423 awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D& rParam, const awt::Size& rPageSize ) 1424 { 1425 //return the used rectangle 1426 awt::Rectangle aUsedOuterRect(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y, 0, 0); 1427 1428 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() ); 1429 if( !xDiagram.is()) 1430 return aUsedOuterRect; 1431 1432 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); 1433 if(!nDimensionCount) 1434 { 1435 //@todo handle mixed dimension 1436 nDimensionCount = 2; 1437 } 1438 1439 basegfx::B2IRectangle aAvailableOuterRect = BaseGFXHelper::makeRectangle(rParam.maRemainingSpace); 1440 1441 const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList( rParam.mpSeriesPlotterContainer->getCooSysList() ); 1442 SeriesPlottersType& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList(); 1443 1444 //create VAxis, so they can give necessary information for automatic scaling 1445 uno::Reference<chart2::XChartDocument> const xChartDoc(&mrChartModel); 1446 uno::Reference<util::XNumberFormatsSupplier> const xNumberFormatsSupplier( 1447 mrChartModel.getNumberFormatsSupplier()); 1448 size_t nC = 0; 1449 for( nC=0; nC < rVCooSysList.size(); nC++) 1450 { 1451 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); 1452 if(nDimensionCount==3) 1453 { 1454 uno::Reference<beans::XPropertySet> xSceneProperties( xDiagram, uno::UNO_QUERY ); 1455 CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xSceneProperties ) ); 1456 CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xSceneProperties ) ); 1457 CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xSceneProperties ) ); 1458 pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos ); 1459 } 1460 1461 pVCooSys->createVAxisList(xChartDoc, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize); 1462 } 1463 1464 // - prepare list of all axis and how they are used 1465 Date aNullDate = NumberFormatterWrapper( xNumberFormatsSupplier ).getNullDate(); 1466 rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate); 1467 rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel ); 1468 rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter(); 1469 rParam.mpSeriesPlotterContainer->setNumberFormatsFromAxes(); 1470 1471 //create shapes 1472 1473 //aspect ratio 1474 drawing::Direction3D aPreferredAspectRatio = 1475 rParam.mpSeriesPlotterContainer->getPreferredAspectRatio(); 1476 1477 uno::Reference< drawing::XShapes > xSeriesTargetInFrontOfAxis; 1478 uno::Reference< drawing::XShapes > xSeriesTargetBehindAxis; 1479 VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount); 1480 bool bIsPieOrDonut = lcl_IsPieOrDonut(xDiagram); 1481 {//create diagram 1482 aVDiagram.init(rParam.mxDiagramWithAxesShapes, m_xShapeFactory); 1483 aVDiagram.createShapes( 1484 awt::Point(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y), 1485 awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height)); 1486 1487 xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion(); 1488 // It is preferable to use full size than minimum for pie charts 1489 if (!bIsPieOrDonut && !rParam.mbUseFixedInnerSize) 1490 aVDiagram.reduceToMimimumSize(); 1491 } 1492 1493 uno::Reference< drawing::XShapes > xTextTargetShapes = 1494 ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory)->createGroup2D(rParam.mxDiagramWithAxesShapes); 1495 1496 // - create axis and grids for all coordinate systems 1497 1498 //init all coordinate systems 1499 for( nC=0; nC < rVCooSysList.size(); nC++) 1500 { 1501 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); 1502 pVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis,xTextTargetShapes,m_xShapeFactory,xSeriesTargetBehindAxis); 1503 1504 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( 1505 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); 1506 1507 pVCooSys->initVAxisInList(); 1508 } 1509 1510 //calculate resulting size respecting axis label layout and fontscaling 1511 1512 uno::Reference< drawing::XShape > xBoundingShape(rParam.mxDiagramWithAxesShapes, uno::UNO_QUERY); 1513 ::basegfx::B2IRectangle aConsumedOuterRect; 1514 1515 //use first coosys only so far; todo: calculate for more than one coosys if we have more in future 1516 //todo: this is just a workaround at the moment for pie and donut labels 1517 if( !bIsPieOrDonut && (!rVCooSysList.empty()) ) 1518 { 1519 VCoordinateSystem* pVCooSys = rVCooSysList[0].get(); 1520 pVCooSys->createMaximumAxesLabels(); 1521 1522 aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape); 1523 ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); 1524 if (!rParam.mbUseFixedInnerSize) 1525 aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); 1526 1527 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( 1528 createTransformationSceneToScreen( aNewInnerRect ) )); 1529 1530 //redo autoscaling to get size and text dependent automatic main increment count 1531 rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel ); 1532 rParam.mpSeriesPlotterContainer->updateScalesAndIncrementsOnAxes(); 1533 rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter(); 1534 1535 pVCooSys->createAxesLabels(); 1536 1537 bool bLessSpaceConsumedThanExpected = false; 1538 { 1539 aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape); 1540 if( aConsumedOuterRect.getMinX() > aAvailableOuterRect.getMinX() 1541 || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX() 1542 || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY() 1543 || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() ) 1544 bLessSpaceConsumedThanExpected = true; 1545 } 1546 1547 if (bLessSpaceConsumedThanExpected && !rParam.mbUseFixedInnerSize) 1548 { 1549 aVDiagram.adjustInnerSize( aConsumedOuterRect ); 1550 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( 1551 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); 1552 } 1553 pVCooSys->updatePositions();//todo: logically this belongs to the condition above, but it seems also to be necessary to give the axes group shapes the right bounding rects for hit test - probably caused by bug i106183 -> check again if fixed 1554 } 1555 1556 //create axes and grids for the final size 1557 for( nC=0; nC < rVCooSysList.size(); nC++) 1558 { 1559 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); 1560 1561 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( 1562 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); 1563 1564 pVCooSys->createAxesShapes(); 1565 pVCooSys->createGridShapes(); 1566 } 1567 1568 // - create data series for all charttypes 1569 m_bPointsWereSkipped = false; 1570 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList ) 1571 { 1572 VSeriesPlotter* pSeriesPlotter = aPlotter.get(); 1573 uno::Reference< drawing::XShapes > xSeriesTarget; 1574 if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() ) 1575 xSeriesTarget = xSeriesTargetInFrontOfAxis; 1576 else 1577 { 1578 xSeriesTarget = xSeriesTargetBehindAxis; 1579 OSL_ENSURE( !bIsPieOrDonut, "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" ); 1580 } 1581 pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,m_xShapeFactory,OUString() ); 1582 pSeriesPlotter->setPageReferenceSize( rPageSize ); 1583 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); 1584 if(nDimensionCount==2) 1585 pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); 1586 //better performance for big data 1587 { 1588 //calculate resolution for coordinate system 1589 Sequence<sal_Int32> aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution ); 1590 pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution ); 1591 } 1592 1593 pSeriesPlotter->createShapes(); 1594 m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped(); 1595 } 1596 1597 //recreate all with corrected sizes if requested 1598 if( bIsPieOrDonut ) 1599 { 1600 m_bPointsWereSkipped = false; 1601 1602 aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape); 1603 ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); 1604 if (!rParam.mbUseFixedInnerSize) 1605 aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); 1606 1607 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList ) 1608 { 1609 aPlotter->releaseShapes(); 1610 } 1611 1612 //clear and recreate 1613 ShapeFactory::removeSubShapes( xSeriesTargetInFrontOfAxis ); //xSeriesTargetBehindAxis is a sub shape of xSeriesTargetInFrontOfAxis and will be removed here 1614 xSeriesTargetBehindAxis.clear(); 1615 ShapeFactory::removeSubShapes( xTextTargetShapes ); 1616 1617 //set new transformation 1618 for( nC=0; nC < rVCooSysList.size(); nC++) 1619 { 1620 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); 1621 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( 1622 createTransformationSceneToScreen( aNewInnerRect ) )); 1623 } 1624 1625 // - create data series for all charttypes 1626 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList ) 1627 { 1628 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, aPlotter.get() ); 1629 if(nDimensionCount==2) 1630 aPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); 1631 aPlotter->createShapes(); 1632 m_bPointsWereSkipped = m_bPointsWereSkipped || aPlotter->PointsWereSkipped(); 1633 } 1634 1635 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList ) 1636 aPlotter->rearrangeLabelToAvoidOverlapIfRequested(rPageSize); 1637 } 1638 1639 if (rParam.mbUseFixedInnerSize) 1640 { 1641 aUsedOuterRect = awt::Rectangle( aConsumedOuterRect.getMinX(), aConsumedOuterRect.getMinY(), aConsumedOuterRect.getWidth(), aConsumedOuterRect.getHeight() ); 1642 } 1643 else 1644 aUsedOuterRect = rParam.maRemainingSpace; 1645 1646 bool bSnapRectToUsedArea = false; 1647 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList ) 1648 { 1649 bSnapRectToUsedArea = aPlotter->shouldSnapRectToUsedArea(); 1650 if(bSnapRectToUsedArea) 1651 break; 1652 } 1653 if(bSnapRectToUsedArea) 1654 { 1655 if (rParam.mbUseFixedInnerSize) 1656 m_aResultingDiagramRectangleExcludingAxes = getRectangleOfObject( "PlotAreaExcludingAxes" ); 1657 else 1658 { 1659 ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); 1660 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() ); 1661 } 1662 } 1663 else 1664 { 1665 if (rParam.mbUseFixedInnerSize) 1666 m_aResultingDiagramRectangleExcludingAxes = rParam.maRemainingSpace; 1667 else 1668 { 1669 ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); 1670 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() ); 1671 } 1672 } 1673 1674 if (rParam.mxMarkHandles.is()) 1675 { 1676 awt::Point aPos(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y); 1677 awt::Size aSize(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height); 1678 1679 bool bPosSizeExcludeAxesProperty = true; 1680 uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY_THROW ); 1681 xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty; 1682 if (rParam.mbUseFixedInnerSize || bPosSizeExcludeAxesProperty) 1683 { 1684 aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y ); 1685 aSize = awt::Size( m_aResultingDiagramRectangleExcludingAxes.Width, m_aResultingDiagramRectangleExcludingAxes.Height ); 1686 } 1687 rParam.mxMarkHandles->setPosition(aPos); 1688 rParam.mxMarkHandles->setSize(aSize); 1689 } 1690 1691 return aUsedOuterRect; 1692 } 1693 1694 bool ChartView::getExplicitValuesForAxis( 1695 uno::Reference< XAxis > xAxis 1696 , ExplicitScaleData& rExplicitScale 1697 , ExplicitIncrementData& rExplicitIncrement ) 1698 { 1699 SolarMutexGuard aSolarGuard; 1700 1701 impl_updateView(); 1702 1703 if(!xAxis.is()) 1704 return false; 1705 1706 uno::Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstDiagram() ) ); 1707 const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys); 1708 if(!pVCooSys) 1709 return false; 1710 1711 sal_Int32 nDimensionIndex=-1; 1712 sal_Int32 nAxisIndex=-1; 1713 if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) ) 1714 { 1715 rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex); 1716 rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex); 1717 if( rExplicitScale.ShiftedCategoryPosition ) 1718 { 1719 //remove 'one' from max 1720 if( rExplicitScale.AxisType == css::chart2::AxisType::DATE ) 1721 { 1722 Date aMaxDate(rExplicitScale.NullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum)); 1723 //for explicit scales with shifted categories we need one interval more 1724 switch( rExplicitScale.TimeResolution ) 1725 { 1726 case css::chart::TimeUnit::DAY: 1727 --aMaxDate; 1728 break; 1729 case css::chart::TimeUnit::MONTH: 1730 aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1); 1731 break; 1732 case css::chart::TimeUnit::YEAR: 1733 aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1); 1734 break; 1735 } 1736 rExplicitScale.Maximum = aMaxDate - rExplicitScale.NullDate; 1737 } 1738 else if( rExplicitScale.AxisType == css::chart2::AxisType::CATEGORY ) 1739 rExplicitScale.Maximum -= 1.0; 1740 else if( rExplicitScale.AxisType == css::chart2::AxisType::SERIES ) 1741 rExplicitScale.Maximum -= 1.0; 1742 } 1743 return true; 1744 } 1745 return false; 1746 } 1747 1748 SdrPage* ChartView::getSdrPage() 1749 { 1750 SdrPage* pPage=nullptr; 1751 Reference< lang::XUnoTunnel> xUnoTunnel(m_xDrawPage,uno::UNO_QUERY); 1752 if(xUnoTunnel.is()) 1753 { 1754 SvxDrawPage* pSvxDrawPage = reinterpret_cast<SvxDrawPage*>(xUnoTunnel->getSomething( 1755 SvxDrawPage::getUnoTunnelId() )); 1756 if(pSvxDrawPage) 1757 { 1758 pPage = pSvxDrawPage->GetSdrPage(); 1759 } 1760 } 1761 return pPage; 1762 } 1763 1764 uno::Reference< drawing::XShape > ChartView::getShapeForCID( const OUString& rObjectCID ) 1765 { 1766 SolarMutexGuard aSolarGuard; 1767 SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() ); 1768 if( pObj ) 1769 return uno::Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY); 1770 return nullptr; 1771 } 1772 1773 awt::Rectangle ChartView::getDiagramRectangleExcludingAxes() 1774 { 1775 impl_updateView(); 1776 return m_aResultingDiagramRectangleExcludingAxes; 1777 } 1778 1779 awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool bSnapRect ) 1780 { 1781 impl_updateView(); 1782 1783 awt::Rectangle aRet; 1784 uno::Reference< drawing::XShape > xShape( getShapeForCID(rObjectCID) ); 1785 if(xShape.is()) 1786 { 1787 //special handling for axis for old api: 1788 //same special handling for diagram 1789 ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) ); 1790 if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM ) 1791 { 1792 SolarMutexGuard aSolarGuard; 1793 SvxShape* pRoot = SvxShape::getImplementation( xShape ); 1794 if( pRoot ) 1795 { 1796 SdrObject* pRootSdrObject = pRoot->GetSdrObject(); 1797 if( pRootSdrObject ) 1798 { 1799 SdrObjList* pRootList = pRootSdrObject->GetSubList(); 1800 if( pRootList ) 1801 { 1802 OUString aShapeName = "MarkHandles"; 1803 if( eObjectType == OBJECTTYPE_DIAGRAM ) 1804 aShapeName = "PlotAreaIncludingAxes"; 1805 SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList ); 1806 if( pShape ) 1807 xShape.set( pShape->getUnoShape(), uno::UNO_QUERY); 1808 } 1809 } 1810 } 1811 } 1812 1813 awt::Size aSize( xShape->getSize() ); 1814 awt::Point aPoint( xShape->getPosition() ); 1815 aRet = awt::Rectangle( aPoint.X, aPoint.Y, aSize.Width, aSize.Height ); 1816 if( bSnapRect ) 1817 { 1818 //for rotated objects the shape size and position differs from the visible rectangle 1819 SvxShape* pShape = SvxShape::getImplementation( xShape ); 1820 if( pShape ) 1821 { 1822 SdrObject* pSdrObject = pShape->GetSdrObject(); 1823 if( pSdrObject ) 1824 { 1825 tools::Rectangle aSnapRect( pSdrObject->GetSnapRect() ); 1826 aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight()); 1827 } 1828 } 1829 } 1830 } 1831 return aRet; 1832 } 1833 1834 std::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper() 1835 { 1836 return m_pDrawModelWrapper; 1837 } 1838 1839 namespace 1840 { 1841 sal_Int32 lcl_getDiagramTitleSpace() 1842 { 1843 return 200; //=0,2 cm spacing 1844 } 1845 bool lcl_getPropertySwapXAndYAxis( const uno::Reference< XDiagram >& xDiagram ) 1846 { 1847 bool bSwapXAndY = false; 1848 1849 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); 1850 if( xCooSysContainer.is() ) 1851 { 1852 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); 1853 if( aCooSysList.getLength() ) 1854 { 1855 uno::Reference<beans::XPropertySet> xProp(aCooSysList[0], uno::UNO_QUERY ); 1856 if( xProp.is()) try 1857 { 1858 xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY; 1859 } 1860 catch( const uno::Exception& e ) 1861 { 1862 SAL_WARN("chart2", "Exception caught. " << e ); 1863 } 1864 } 1865 } 1866 return bSwapXAndY; 1867 } 1868 1869 } 1870 1871 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( 1872 const Reference< chart2::XAxis >& xAxis 1873 , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem 1874 , const Reference<chart2::XChartDocument>& xChartDoc) 1875 { 1876 return AxisHelper::getExplicitNumberFormatKeyForAxis( xAxis, xCorrespondingCoordinateSystem, xChartDoc 1877 , true /*bSearchForParallelAxisIfNothingIsFound*/ ); 1878 } 1879 1880 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( 1881 const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, 1882 const uno::Reference< XDataSeries >& xSeries, 1883 sal_Int32 nPointIndex /*-1 for whole series*/, 1884 const uno::Reference< XDiagram >& xDiagram 1885 ) 1886 { 1887 sal_Int32 nFormat=0; 1888 if( !xSeriesOrPointProp.is() ) 1889 return nFormat; 1890 1891 bool bLinkToSource = true; 1892 try 1893 { 1894 xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource; 1895 } 1896 catch ( const beans::UnknownPropertyException& ) {} 1897 1898 xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat; 1899 sal_Int32 nOldFormat = nFormat; 1900 if (bLinkToSource) 1901 { 1902 uno::Reference< chart2::XChartType > xChartType( DataSeriesHelper::getChartTypeOfSeries( xSeries, xDiagram ) ); 1903 1904 bool bFormatFound = false; 1905 if( ChartTypeHelper::shouldLabelNumberFormatKeyBeDetectedFromYAxis( xChartType ) ) 1906 { 1907 uno::Reference< beans::XPropertySet > xAttachedAxisProps( DiagramHelper::getAttachedAxis( xSeries, xDiagram ), uno::UNO_QUERY ); 1908 if (xAttachedAxisProps.is() && (xAttachedAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat)) 1909 bFormatFound = true; 1910 } 1911 if( !bFormatFound ) 1912 { 1913 Reference< chart2::data::XDataSource > xSeriesSource( xSeries, uno::UNO_QUERY ); 1914 OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) ); 1915 1916 Reference< data::XLabeledDataSequence > xLabeledSequence( 1917 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, aRole )); 1918 if( xLabeledSequence.is() ) 1919 { 1920 Reference< data::XDataSequence > xValues( xLabeledSequence->getValues() ); 1921 if( xValues.is() ) 1922 nFormat = xValues->getNumberFormatKeyByIndex( nPointIndex ); 1923 } 1924 } 1925 1926 if (nFormat >= 0 && nOldFormat != nFormat) 1927 xSeriesOrPointProp->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(nFormat)); 1928 } 1929 1930 if(nFormat<0) 1931 nFormat=0; 1932 return nFormat; 1933 } 1934 1935 sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( 1936 const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, 1937 const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) 1938 { 1939 sal_Int32 nFormat=0; 1940 if( !xSeriesOrPointProp.is() ) 1941 return nFormat; 1942 if( !(xSeriesOrPointProp->getPropertyValue("PercentageNumberFormat") >>= nFormat) ) 1943 { 1944 nFormat = DiagramHelper::getPercentNumberFormat( xNumberFormatsSupplier ); 1945 } 1946 if(nFormat<0) 1947 nFormat=0; 1948 return nFormat; 1949 } 1950 1951 awt::Rectangle ExplicitValueProvider::AddSubtractAxisTitleSizes( 1952 ChartModel& rModel 1953 , const Reference< uno::XInterface >& xChartView 1954 , const awt::Rectangle& rPositionAndSize, bool bSubtract ) 1955 { 1956 awt::Rectangle aRet(rPositionAndSize); 1957 1958 //add axis title sizes to the diagram size 1959 uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, rModel ) ); 1960 uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, rModel ) ); 1961 uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, rModel ) ); 1962 uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, rModel ) ); 1963 if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() ) 1964 { 1965 ExplicitValueProvider* pExplicitValueProvider = ExplicitValueProvider::getExplicitValueProvider(xChartView); 1966 if( pExplicitValueProvider ) 1967 { 1968 //detect whether x axis points into x direction or not 1969 if( lcl_getPropertySwapXAndYAxis( rModel.getFirstDiagram() ) ) 1970 { 1971 std::swap( xTitle_Height, xTitle_Width ); 1972 std::swap( xSecondTitle_Height, xSecondTitle_Width ); 1973 } 1974 1975 sal_Int32 nTitleSpaceWidth = 0; 1976 sal_Int32 nTitleSpaceHeight = 0; 1977 sal_Int32 nSecondTitleSpaceWidth = 0; 1978 sal_Int32 nSecondTitleSpaceHeight = 0; 1979 1980 if( xTitle_Height.is() ) 1981 { 1982 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, rModel ) ); 1983 nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; 1984 if( nTitleSpaceHeight ) 1985 nTitleSpaceHeight+=lcl_getDiagramTitleSpace(); 1986 } 1987 if( xTitle_Width.is() ) 1988 { 1989 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, rModel ) ); 1990 nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; 1991 if(nTitleSpaceWidth) 1992 nTitleSpaceWidth+=lcl_getDiagramTitleSpace(); 1993 } 1994 if( xSecondTitle_Height.is() ) 1995 { 1996 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, rModel ) ); 1997 nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; 1998 if( nSecondTitleSpaceHeight ) 1999 nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace(); 2000 } 2001 if( xSecondTitle_Width.is() ) 2002 { 2003 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, rModel ) ); 2004 nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; 2005 if( nSecondTitleSpaceWidth ) 2006 nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace(); 2007 } 2008 if( bSubtract ) 2009 { 2010 aRet.X += nTitleSpaceWidth; 2011 aRet.Y += nSecondTitleSpaceHeight; 2012 aRet.Width -= (nTitleSpaceWidth + nSecondTitleSpaceWidth); 2013 aRet.Height -= (nTitleSpaceHeight + nSecondTitleSpaceHeight); 2014 } 2015 else 2016 { 2017 2018 aRet.X -= nTitleSpaceWidth; 2019 aRet.Y -= nSecondTitleSpaceHeight; 2020 aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth; 2021 aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight; 2022 } 2023 } 2024 } 2025 return aRet; 2026 } 2027 2028 namespace { 2029 2030 double lcl_getPageLayoutDistancePercentage() 2031 { 2032 return 0.02; 2033 } 2034 2035 bool getAvailablePosAndSizeForDiagram( 2036 CreateShapeParam2D& rParam, const awt::Size & rPageSize, const uno::Reference<XDiagram>& xDiagram ) 2037 { 2038 rParam.mbUseFixedInnerSize = false; 2039 2040 //@todo: we need a size dependent on the axis labels 2041 sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); 2042 sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); 2043 rParam.maRemainingSpace.X += nXDistance; 2044 rParam.maRemainingSpace.Width -= 2*nXDistance; 2045 rParam.maRemainingSpace.Y += nYDistance; 2046 rParam.maRemainingSpace.Height -= 2*nYDistance; 2047 2048 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0) 2049 return false; 2050 2051 uno::Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY); 2052 2053 bool bPosSizeExcludeAxes = false; 2054 if( xProp.is() ) 2055 xProp->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes; 2056 2057 //size: 2058 css::chart2::RelativeSize aRelativeSize; 2059 if( xProp.is() && (xProp->getPropertyValue( "RelativeSize" )>>=aRelativeSize) ) 2060 { 2061 rParam.maRemainingSpace.Height = static_cast<sal_Int32>(aRelativeSize.Secondary*rPageSize.Height); 2062 rParam.maRemainingSpace.Width = static_cast<sal_Int32>(aRelativeSize.Primary*rPageSize.Width); 2063 rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes; 2064 } 2065 2066 //position: 2067 chart2::RelativePosition aRelativePosition; 2068 if( xProp.is() && (xProp->getPropertyValue( "RelativePosition" )>>=aRelativePosition) ) 2069 { 2070 //@todo decide whether x is primary or secondary 2071 2072 //the coordinates re relative to the page 2073 double fX = aRelativePosition.Primary*rPageSize.Width; 2074 double fY = aRelativePosition.Secondary*rPageSize.Height; 2075 2076 awt::Point aPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( 2077 awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)), 2078 awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height), 2079 aRelativePosition.Anchor); 2080 2081 rParam.maRemainingSpace.X = aPos.X; 2082 rParam.maRemainingSpace.Y = aPos.Y; 2083 2084 rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes; 2085 } 2086 2087 //ensure that the diagram does not lap out right side or out of bottom 2088 if (rParam.maRemainingSpace.Y + rParam.maRemainingSpace.Height > rPageSize.Height) 2089 rParam.maRemainingSpace.Height = rPageSize.Height - rParam.maRemainingSpace.Y; 2090 2091 if (rParam.maRemainingSpace.X + rParam.maRemainingSpace.Width > rPageSize.Width) 2092 rParam.maRemainingSpace.Width = rPageSize.Width - rParam.maRemainingSpace.X; 2093 2094 return true; 2095 } 2096 2097 enum TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z }; 2098 2099 void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment 2100 , awt::Rectangle const & rDiagramPlusAxesRect, const awt::Size & rPageSize ) 2101 { 2102 if(!pVTitle) 2103 return; 2104 2105 awt::Point aNewPosition(0,0); 2106 awt::Size aTitleSize = pVTitle->getFinalSize(); 2107 sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); 2108 sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); 2109 switch( eAlignment ) 2110 { 2111 case ALIGN_TOP: 2112 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 2113 , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance ); 2114 break; 2115 case ALIGN_BOTTOM: 2116 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 2117 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance ); 2118 break; 2119 case ALIGN_LEFT: 2120 aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance 2121 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); 2122 break; 2123 case ALIGN_RIGHT: 2124 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance 2125 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); 2126 break; 2127 case ALIGN_Z: 2128 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance 2129 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 ); 2130 break; 2131 default: 2132 break; 2133 } 2134 2135 sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2; 2136 sal_Int32 nMaxX = rPageSize.Width - aTitleSize.Width/2; 2137 sal_Int32 nMinX = aTitleSize.Width/2; 2138 sal_Int32 nMinY = aTitleSize.Height/2; 2139 if( aNewPosition.Y > nMaxY ) 2140 aNewPosition.Y = nMaxY; 2141 if( aNewPosition.X > nMaxX ) 2142 aNewPosition.X = nMaxX; 2143 if( aNewPosition.Y < nMinY ) 2144 aNewPosition.Y = nMinY; 2145 if( aNewPosition.X < nMinX ) 2146 aNewPosition.X = nMinX; 2147 2148 pVTitle->changePosition( aNewPosition ); 2149 } 2150 2151 std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType 2152 , const uno::Reference< drawing::XShapes>& xPageShapes 2153 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory 2154 , ChartModel& rModel 2155 , awt::Rectangle& rRemainingSpace 2156 , const awt::Size & rPageSize 2157 , TitleAlignment eAlignment 2158 , bool& rbAutoPosition ) 2159 { 2160 std::shared_ptr<VTitle> apVTitle; 2161 2162 // #i109336# Improve auto positioning in chart 2163 double fPercentage = lcl_getPageLayoutDistancePercentage(); 2164 sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage ); 2165 sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage ); 2166 if ( eType == TitleHelper::MAIN_TITLE ) 2167 { 2168 nYDistance += 135; // 1/100 mm 2169 } 2170 else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION ) 2171 { 2172 nYDistance = 420; // 1/100 mm 2173 } 2174 else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION ) 2175 { 2176 nXDistance = 450; // 1/100 mm 2177 } 2178 2179 uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, rModel ) ); 2180 OUString aCompleteString = TitleHelper::getCompleteString(xTitle); 2181 if (aCompleteString.isEmpty()) 2182 return apVTitle; 2183 2184 //create title 2185 apVTitle.reset(new VTitle(xTitle)); 2186 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, rModel); 2187 apVTitle->init(xPageShapes, xShapeFactory, aCID); 2188 apVTitle->createShapes(awt::Point(0,0), rPageSize); 2189 awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize(); 2190 awt::Size aTitleSize = apVTitle->getFinalSize(); 2191 2192 //position 2193 rbAutoPosition = true; 2194 awt::Point aNewPosition(0,0); 2195 chart2::RelativePosition aRelativePosition; 2196 uno::Reference<beans::XPropertySet> xProp(xTitle, uno::UNO_QUERY); 2197 if (xProp.is() && (xProp->getPropertyValue("RelativePosition") >>= aRelativePosition)) 2198 { 2199 rbAutoPosition = false; 2200 2201 //@todo decide whether x is primary or secondary 2202 double fX = aRelativePosition.Primary*rPageSize.Width; 2203 double fY = aRelativePosition.Secondary*rPageSize.Height; 2204 2205 double fAnglePi = apVTitle->getRotationAnglePi(); 2206 aNewPosition = RelativePositionHelper::getCenterOfAnchoredObject( 2207 awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)) 2208 , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi ); 2209 } 2210 else //auto position 2211 { 2212 switch( eAlignment ) 2213 { 2214 case ALIGN_TOP: 2215 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 2216 , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance ); 2217 break; 2218 case ALIGN_BOTTOM: 2219 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 2220 , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance ); 2221 break; 2222 case ALIGN_LEFT: 2223 aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance 2224 , rRemainingSpace.Y + rRemainingSpace.Height/2 ); 2225 break; 2226 case ALIGN_RIGHT: 2227 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance 2228 , rRemainingSpace.Y + rRemainingSpace.Height/2 ); 2229 break; 2230 default: 2231 break; 2232 2233 } 2234 } 2235 apVTitle->changePosition( aNewPosition ); 2236 2237 //remaining space 2238 switch( eAlignment ) 2239 { 2240 case ALIGN_TOP: 2241 // Push the remaining space down from top. 2242 rRemainingSpace.Y += ( aTitleSize.Height + nYDistance ); 2243 rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); 2244 break; 2245 case ALIGN_BOTTOM: 2246 // Push the remaining space up from bottom. 2247 rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); 2248 break; 2249 case ALIGN_LEFT: 2250 // Push the remaining space to the right from left edge. 2251 rRemainingSpace.X += ( aTitleSize.Width + nXDistance ); 2252 rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); 2253 break; 2254 case ALIGN_RIGHT: 2255 // Push the remaining space to the left from right edge. 2256 rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); 2257 break; 2258 default: 2259 break; 2260 } 2261 2262 return apVTitle; 2263 } 2264 2265 bool lcl_createLegend( const uno::Reference< XLegend > & xLegend 2266 , const uno::Reference< drawing::XShapes>& xPageShapes 2267 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory 2268 , const uno::Reference< uno::XComponentContext > & xContext 2269 , awt::Rectangle & rRemainingSpace 2270 , const awt::Size & rPageSize 2271 , ChartModel& rModel 2272 , const std::vector< LegendEntryProvider* >& rLegendEntryProviderList 2273 , sal_Int16 nDefaultWritingMode ) 2274 { 2275 if (!VLegend::isVisible(xLegend)) 2276 return false; 2277 2278 VLegend aVLegend( xLegend, xContext, rLegendEntryProviderList, 2279 xPageShapes, xShapeFactory, rModel); 2280 aVLegend.setDefaultWritingMode( nDefaultWritingMode ); 2281 aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ), 2282 rPageSize ); 2283 aVLegend.changePosition( rRemainingSpace, rPageSize ); 2284 return true; 2285 } 2286 2287 void lcl_createButtons(const uno::Reference<drawing::XShapes>& xPageShapes, 2288 const uno::Reference<lang::XMultiServiceFactory>& xShapeFactory, 2289 ChartModel& rModel, 2290 awt::Rectangle& rRemainingSpace) 2291 { 2292 uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY); 2293 if (!xPivotTableDataProvider.is()) 2294 return; 2295 2296 uno::Reference<beans::XPropertySet> xModelPage(rModel.getPageBackground()); 2297 2298 awt::Size aSize(4000, 700); // size of the button 2299 2300 long x = 0; 2301 2302 if (xPivotTableDataProvider->getPageFields().hasElements()) 2303 { 2304 x = 0; 2305 2306 for (css::chart2::data::PivotTableFieldEntry const & rPageFieldEntry : xPivotTableDataProvider->getPageFields()) 2307 { 2308 std::unique_ptr<VButton> pButton(new VButton); 2309 pButton->init(xPageShapes, xShapeFactory); 2310 awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100); 2311 sal_Int32 nDimensionIndex = rPageFieldEntry.DimensionIndex; 2312 OUString aFieldOutputDescription = xPivotTableDataProvider->getFieldOutputDescription(nDimensionIndex); 2313 pButton->setLabel(rPageFieldEntry.Name + " | " + aFieldOutputDescription); 2314 pButton->setCID("FieldButton.Page." + OUString::number(nDimensionIndex)); 2315 pButton->setPosition(aNewPosition); 2316 pButton->setSize(aSize); 2317 if (rPageFieldEntry.HasHiddenMembers) 2318 pButton->setArrowColor(Color(0x0000FF)); 2319 2320 pButton->createShapes(xModelPage); 2321 x += aSize.Width + 100; 2322 } 2323 rRemainingSpace.Y += (aSize.Height + 100 + 100); 2324 rRemainingSpace.Height -= (aSize.Height + 100 + 100); 2325 } 2326 2327 aSize = awt::Size(3000, 700); // size of the button 2328 2329 if (xPivotTableDataProvider->getRowFields().hasElements()) 2330 { 2331 x = 200; 2332 for (css::chart2::data::PivotTableFieldEntry const & rRowFieldEntry : xPivotTableDataProvider->getRowFields()) 2333 { 2334 2335 std::unique_ptr<VButton> pButton(new VButton); 2336 pButton->init(xPageShapes, xShapeFactory); 2337 awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100, 2338 rRemainingSpace.Y + rRemainingSpace.Height - aSize.Height - 100); 2339 pButton->setLabel(rRowFieldEntry.Name); 2340 pButton->setCID("FieldButton.Row." + OUString::number(rRowFieldEntry.DimensionIndex)); 2341 pButton->setPosition(aNewPosition); 2342 pButton->setSize(aSize); 2343 if ( rRowFieldEntry.Name == "Data" ) 2344 { 2345 pButton->setBGColor( Color(0x00F6F6F6) ); 2346 pButton->showArrow( false ); 2347 } 2348 else if (rRowFieldEntry.HasHiddenMembers) 2349 pButton->setArrowColor(Color(0x0000FF)); 2350 pButton->createShapes(xModelPage); 2351 x += aSize.Width + 100; 2352 } 2353 rRemainingSpace.Height -= (aSize.Height + 100 + 100); 2354 } 2355 } 2356 2357 void formatPage( 2358 ChartModel& rChartModel 2359 , const awt::Size& rPageSize 2360 , const uno::Reference< drawing::XShapes >& xTarget 2361 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory 2362 ) 2363 { 2364 try 2365 { 2366 uno::Reference< beans::XPropertySet > xModelPage( rChartModel.getPageBackground()); 2367 if( ! xModelPage.is()) 2368 return; 2369 2370 if( !xShapeFactory.is() ) 2371 return; 2372 2373 //format page 2374 tPropertyNameValueMap aNameValueMap; 2375 PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage ); 2376 2377 OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ); 2378 aNameValueMap.emplace( "Name", uno::Any( aCID ) ); //CID OUString 2379 2380 tNameSequence aNames; 2381 tAnySequence aValues; 2382 PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap ); 2383 2384 ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(xShapeFactory); 2385 pShapeFactory->createRectangle( 2386 xTarget, rPageSize, awt::Point(0, 0), aNames, aValues); 2387 } 2388 catch( const uno::Exception & ) 2389 { 2390 DBG_UNHANDLED_EXCEPTION("chart2" ); 2391 } 2392 } 2393 2394 void lcl_removeEmptyGroupShapes( const Reference< drawing::XShapes>& xParent ) 2395 { 2396 if(!xParent.is()) 2397 return; 2398 Reference< drawing::XShapeGroup > xParentGroup( xParent, uno::UNO_QUERY ); 2399 if( !xParentGroup.is() ) 2400 { 2401 Reference< drawing::XDrawPage > xPage( xParent, uno::UNO_QUERY ); 2402 if( !xPage.is() ) 2403 return; 2404 } 2405 2406 //iterate from back! 2407 for( sal_Int32 nN = xParent->getCount(); nN--; ) 2408 { 2409 uno::Any aAny = xParent->getByIndex( nN ); 2410 Reference< drawing::XShapes> xShapes; 2411 if( aAny >>= xShapes ) 2412 lcl_removeEmptyGroupShapes( xShapes ); 2413 if( xShapes.is() && xShapes->getCount()==0 ) 2414 { 2415 //remove empty group shape 2416 Reference< drawing::XShapeGroup > xGroup( xShapes, uno::UNO_QUERY ); 2417 Reference< drawing::XShape > xShape( xShapes, uno::UNO_QUERY ); 2418 if( xGroup.is() ) 2419 xParent->remove( xShape ); 2420 } 2421 } 2422 } 2423 2424 } 2425 2426 void ChartView::impl_refreshAddIn() 2427 { 2428 if( !m_bRefreshAddIn ) 2429 return; 2430 2431 uno::Reference< beans::XPropertySet > xProp( static_cast< ::cppu::OWeakObject* >( &mrChartModel ), uno::UNO_QUERY ); 2432 if( xProp.is()) try 2433 { 2434 uno::Reference< util::XRefreshable > xAddIn; 2435 xProp->getPropertyValue( "AddIn" ) >>= xAddIn; 2436 if( xAddIn.is() ) 2437 { 2438 bool bRefreshAddInAllowed = true; 2439 xProp->getPropertyValue( "RefreshAddInAllowed" ) >>= bRefreshAddInAllowed; 2440 if( bRefreshAddInAllowed ) 2441 xAddIn->refresh(); 2442 } 2443 } 2444 catch( const uno::Exception& e ) 2445 { 2446 SAL_WARN("chart2", "Exception caught. " << e ); 2447 } 2448 } 2449 2450 static const char* envChartDummyFactory = getenv("CHART_DUMMY_FACTORY"); 2451 2452 void ChartView::createShapes() 2453 { 2454 SolarMutexGuard aSolarGuard; 2455 2456 osl::ResettableMutexGuard aTimedGuard(maTimeMutex); 2457 if(mrChartModel.isTimeBased()) 2458 { 2459 maTimeBased.bTimeBased = true; 2460 } 2461 2462 //make sure add-in is refreshed after creating the shapes 2463 const ::comphelper::ScopeGuard aGuard( [this]() { this->impl_refreshAddIn(); } ); 2464 2465 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle(0,0,0,0); 2466 impl_deleteCoordinateSystems(); 2467 if( m_pDrawModelWrapper ) 2468 { 2469 // #i12587# support for shapes in chart 2470 m_pDrawModelWrapper->getSdrModel().EnableUndo( false ); 2471 m_pDrawModelWrapper->clearMainDrawPage(); 2472 } 2473 2474 lcl_setDefaultWritingMode( m_pDrawModelWrapper, mrChartModel ); 2475 2476 awt::Size aPageSize = mrChartModel.getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); 2477 2478 ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory); 2479 if(!mxRootShape.is()) 2480 mxRootShape = pShapeFactory->getOrCreateChartRootShape( m_xDrawPage ); 2481 2482 SdrPage* pPage = ChartView::getSdrPage(); 2483 if(pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset 2484 pPage->SetSize(Size(aPageSize.Width,aPageSize.Height)); 2485 else 2486 { 2487 OSL_FAIL("could not set page size correctly"); 2488 } 2489 ShapeFactory::setPageSize(mxRootShape, aPageSize); 2490 2491 createShapes2D(aPageSize); 2492 2493 // #i12587# support for shapes in chart 2494 if ( m_pDrawModelWrapper ) 2495 { 2496 m_pDrawModelWrapper->getSdrModel().EnableUndo( true ); 2497 } 2498 2499 if(maTimeBased.bTimeBased) 2500 { 2501 maTimeBased.nFrame++; 2502 } 2503 } 2504 2505 // util::XEventListener (base of XCloseListener) 2506 void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ ) 2507 { 2508 } 2509 2510 void ChartView::impl_updateView( bool bCheckLockedCtrler ) 2511 { 2512 if( !m_pDrawModelWrapper ) 2513 return; 2514 2515 // #i12587# support for shapes in chart 2516 if ( m_bSdrViewIsInEditMode ) 2517 { 2518 return; 2519 } 2520 2521 if (bCheckLockedCtrler && mrChartModel.hasControllersLocked()) 2522 return; 2523 2524 if( m_bViewDirty && !m_bInViewUpdate ) 2525 { 2526 m_bInViewUpdate = true; 2527 //bool bOldRefreshAddIn = m_bRefreshAddIn; 2528 //m_bRefreshAddIn = false; 2529 try 2530 { 2531 impl_notifyModeChangeListener("invalid"); 2532 2533 //prepare draw model 2534 { 2535 SolarMutexGuard aSolarGuard; 2536 m_pDrawModelWrapper->lockControllers(); 2537 } 2538 2539 //create chart view 2540 { 2541 m_bViewDirty = false; 2542 m_bViewUpdatePending = false; 2543 createShapes(); 2544 2545 if( m_bViewDirty ) 2546 { 2547 //avoid recursions due to add-in 2548 m_bRefreshAddIn = false; 2549 m_bViewDirty = false; 2550 m_bViewUpdatePending = false; 2551 //delete old chart view 2552 createShapes(); 2553 m_bRefreshAddIn = true; 2554 } 2555 } 2556 2557 m_bViewDirty = m_bViewUpdatePending; 2558 m_bViewUpdatePending = false; 2559 m_bInViewUpdate = false; 2560 } 2561 catch( const uno::Exception& ) 2562 { 2563 DBG_UNHANDLED_EXCEPTION("chart2" ); 2564 m_bViewDirty = m_bViewUpdatePending; 2565 m_bViewUpdatePending = false; 2566 m_bInViewUpdate = false; 2567 } 2568 2569 { 2570 SolarMutexGuard aSolarGuard; 2571 m_pDrawModelWrapper->unlockControllers(); 2572 } 2573 2574 impl_notifyModeChangeListener("valid"); 2575 2576 //m_bRefreshAddIn = bOldRefreshAddIn; 2577 } 2578 } 2579 2580 // ____ XModifyListener ____ 2581 void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ ) 2582 { 2583 m_bViewDirty = true; 2584 if( m_bInViewUpdate ) 2585 m_bViewUpdatePending = true; 2586 2587 impl_notifyModeChangeListener("dirty"); 2588 } 2589 2590 //SfxListener 2591 void ChartView::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) 2592 { 2593 //#i77362 change notification for changes on additional shapes are missing 2594 if( m_bInViewUpdate ) 2595 return; 2596 2597 // #i12587# support for shapes in chart 2598 if ( m_bSdrViewIsInEditMode ) 2599 { 2600 uno::Reference< view::XSelectionSupplier > xSelectionSupplier( mrChartModel.getCurrentController(), uno::UNO_QUERY ); 2601 if ( xSelectionSupplier.is() ) 2602 { 2603 OUString aSelObjCID; 2604 uno::Any aSelObj( xSelectionSupplier->getSelection() ); 2605 aSelObj >>= aSelObjCID; 2606 if ( !aSelObjCID.isEmpty() ) 2607 { 2608 return; 2609 } 2610 } 2611 } 2612 2613 const SdrHint* pSdrHint = dynamic_cast< const SdrHint* >(&rHint); 2614 if( !pSdrHint ) 2615 return; 2616 2617 bool bShapeChanged = false; 2618 switch( pSdrHint->GetKind() ) 2619 { 2620 case SdrHintKind::ObjectChange: 2621 bShapeChanged = true; 2622 break; 2623 case SdrHintKind::ObjectInserted: 2624 bShapeChanged = true; 2625 break; 2626 case SdrHintKind::ObjectRemoved: 2627 bShapeChanged = true; 2628 break; 2629 case SdrHintKind::ModelCleared: 2630 bShapeChanged = true; 2631 break; 2632 case SdrHintKind::EndEdit: 2633 bShapeChanged = true; 2634 break; 2635 default: 2636 break; 2637 } 2638 2639 if(bShapeChanged) 2640 { 2641 //#i76053# do not send view modified notifications for changes on the hidden page which contains e.g. the symbols for the dialogs 2642 if( ChartView::getSdrPage() != pSdrHint->GetPage() ) 2643 bShapeChanged=false; 2644 } 2645 2646 if(!bShapeChanged) 2647 return; 2648 2649 mrChartModel.setModified(true); 2650 } 2651 2652 void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode ) 2653 { 2654 try 2655 { 2656 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer 2657 .getContainer( cppu::UnoType<util::XModeChangeListener>::get()); 2658 if( pIC ) 2659 { 2660 util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode ); 2661 ::cppu::OInterfaceIteratorHelper aIt( *pIC ); 2662 while( aIt.hasMoreElements() ) 2663 { 2664 uno::Reference< util::XModeChangeListener > xListener( aIt.next(), uno::UNO_QUERY ); 2665 if( xListener.is() ) 2666 xListener->modeChanged( aEvent ); 2667 } 2668 } 2669 } 2670 catch( const uno::Exception& ) 2671 { 2672 DBG_UNHANDLED_EXCEPTION("chart2"); 2673 } 2674 } 2675 2676 // ____ XModeChangeBroadcaster ____ 2677 2678 void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) 2679 { 2680 m_aListenerContainer.addInterface( 2681 cppu::UnoType<util::XModeChangeListener>::get(), xListener ); 2682 } 2683 void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) 2684 { 2685 m_aListenerContainer.removeInterface( 2686 cppu::UnoType<util::XModeChangeListener>::get(), xListener ); 2687 } 2688 void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) 2689 { 2690 2691 } 2692 void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) 2693 { 2694 2695 } 2696 2697 // ____ XUpdatable ____ 2698 void SAL_CALL ChartView::update() 2699 { 2700 impl_updateView(); 2701 2702 //#i100778# migrate all imported or old documents to a plot area sizing exclusive axes (in case the save settings allow for this): 2703 //Although in general it is a bad idea to change the model from within the view this is exceptionally the best place to do this special conversion. 2704 //When a view update is requested (what happens for creating the metafile or displaying 2705 //the chart in edit mode or printing) it is most likely that all necessary information are available - like the underlying spreadsheet data for example. 2706 //Those data are important for the correct axis label sizes which are needed during conversion. 2707 if( DiagramHelper::switchDiagramPositioningToExcludingPositioning( mrChartModel, true, false ) ) 2708 impl_updateView(); 2709 } 2710 2711 void SAL_CALL ChartView::updateSoft() 2712 { 2713 update(); 2714 } 2715 2716 void SAL_CALL ChartView::updateHard() 2717 { 2718 impl_updateView(false); 2719 } 2720 2721 // ____ XPropertySet ____ 2722 Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo() 2723 { 2724 OSL_FAIL("not implemented"); 2725 return nullptr; 2726 } 2727 2728 void SAL_CALL ChartView::setPropertyValue( const OUString& rPropertyName 2729 , const Any& rValue ) 2730 { 2731 if( rPropertyName == "Resolution" ) 2732 { 2733 awt::Size aNewResolution; 2734 if( ! (rValue >>= aNewResolution) ) 2735 throw lang::IllegalArgumentException( "Property 'Resolution' requires value of type awt::Size", nullptr, 0 ); 2736 2737 if( m_aPageResolution.Width!=aNewResolution.Width || m_aPageResolution.Height!=aNewResolution.Height ) 2738 { 2739 //set modified only when the new resolution is higher and points were skipped before 2740 bool bSetModified = m_bPointsWereSkipped && (m_aPageResolution.Width<aNewResolution.Width || m_aPageResolution.Height<aNewResolution.Height); 2741 2742 m_aPageResolution = aNewResolution; 2743 2744 if( bSetModified ) 2745 this->modified( lang::EventObject( static_cast< uno::XWeak* >( this ) ) ); 2746 } 2747 } 2748 else if( rPropertyName == "ZoomFactors" ) 2749 { 2750 //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% 2751 uno::Sequence< beans::PropertyValue > aZoomFactors; 2752 if( ! (rValue >>= aZoomFactors) ) 2753 throw lang::IllegalArgumentException( "Property 'ZoomFactors' requires value of type Sequence< PropertyValue >", nullptr, 0 ); 2754 2755 sal_Int32 nFilterArgs = aZoomFactors.getLength(); 2756 beans::PropertyValue* pDataValues = aZoomFactors.getArray(); 2757 while( nFilterArgs-- ) 2758 { 2759 if ( pDataValues->Name == "ScaleXNumerator" ) 2760 pDataValues->Value >>= m_nScaleXNumerator; 2761 else if ( pDataValues->Name == "ScaleXDenominator" ) 2762 pDataValues->Value >>= m_nScaleXDenominator; 2763 else if ( pDataValues->Name == "ScaleYNumerator" ) 2764 pDataValues->Value >>= m_nScaleYNumerator; 2765 else if ( pDataValues->Name == "ScaleYDenominator" ) 2766 pDataValues->Value >>= m_nScaleYDenominator; 2767 2768 pDataValues++; 2769 } 2770 } 2771 else if( rPropertyName == "SdrViewIsInEditMode" ) 2772 { 2773 //#i77362 change notification for changes on additional shapes are missing 2774 if( ! (rValue >>= m_bSdrViewIsInEditMode) ) 2775 throw lang::IllegalArgumentException( "Property 'SdrViewIsInEditMode' requires value of type sal_Bool", nullptr, 0 ); 2776 } 2777 else 2778 throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard", nullptr ); 2779 } 2780 2781 Any SAL_CALL ChartView::getPropertyValue( const OUString& rPropertyName ) 2782 { 2783 if( rPropertyName != "Resolution" ) 2784 throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard", nullptr ); 2785 2786 return Any(m_aPageResolution); 2787 } 2788 2789 void SAL_CALL ChartView::addPropertyChangeListener( 2790 const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ ) 2791 { 2792 OSL_FAIL("not implemented"); 2793 } 2794 void SAL_CALL ChartView::removePropertyChangeListener( 2795 const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ ) 2796 { 2797 OSL_FAIL("not implemented"); 2798 } 2799 2800 void SAL_CALL ChartView::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) 2801 { 2802 OSL_FAIL("not implemented"); 2803 } 2804 2805 void SAL_CALL ChartView::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) 2806 { 2807 OSL_FAIL("not implemented"); 2808 } 2809 2810 // ____ XMultiServiceFactory ____ 2811 2812 Reference< uno::XInterface > ChartView::createInstance( const OUString& aServiceSpecifier ) 2813 { 2814 SolarMutexGuard aSolarGuard; 2815 2816 SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : nullptr ); 2817 if ( pModel ) 2818 { 2819 if ( aServiceSpecifier == "com.sun.star.drawing.DashTable" ) 2820 { 2821 if ( !m_xDashTable.is() ) 2822 { 2823 m_xDashTable = SvxUnoDashTable_createInstance( pModel ); 2824 } 2825 return m_xDashTable; 2826 } 2827 else if ( aServiceSpecifier == "com.sun.star.drawing.GradientTable" ) 2828 { 2829 if ( !m_xGradientTable.is() ) 2830 { 2831 m_xGradientTable = SvxUnoGradientTable_createInstance( pModel ); 2832 } 2833 return m_xGradientTable; 2834 } 2835 else if ( aServiceSpecifier == "com.sun.star.drawing.HatchTable" ) 2836 { 2837 if ( !m_xHatchTable.is() ) 2838 { 2839 m_xHatchTable = SvxUnoHatchTable_createInstance( pModel ); 2840 } 2841 return m_xHatchTable; 2842 } 2843 else if ( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" ) 2844 { 2845 if ( !m_xBitmapTable.is() ) 2846 { 2847 m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel ); 2848 } 2849 return m_xBitmapTable; 2850 } 2851 else if ( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" ) 2852 { 2853 if ( !m_xTransGradientTable.is() ) 2854 { 2855 m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel ); 2856 } 2857 return m_xTransGradientTable; 2858 } 2859 else if ( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" ) 2860 { 2861 if ( !m_xMarkerTable.is() ) 2862 { 2863 m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel ); 2864 } 2865 return m_xMarkerTable; 2866 } 2867 } 2868 2869 return nullptr; 2870 } 2871 2872 Reference< uno::XInterface > ChartView::createInstanceWithArguments( const OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments ) 2873 { 2874 OSL_ENSURE( Arguments.getLength(), "ChartView::createInstanceWithArguments: arguments are ignored" ); 2875 return createInstance( ServiceSpecifier ); 2876 } 2877 2878 uno::Sequence< OUString > ChartView::getAvailableServiceNames() 2879 { 2880 uno::Sequence< OUString > aServiceNames( 6 ); 2881 2882 aServiceNames[0] = "com.sun.star.drawing.DashTable"; 2883 aServiceNames[1] = "com.sun.star.drawing.GradientTable"; 2884 aServiceNames[2] = "com.sun.star.drawing.HatchTable"; 2885 aServiceNames[3] = "com.sun.star.drawing.BitmapTable"; 2886 aServiceNames[4] = "com.sun.star.drawing.TransparencyGradientTable"; 2887 aServiceNames[5] = "com.sun.star.drawing.MarkerTable"; 2888 2889 return aServiceNames; 2890 } 2891 2892 OUString ChartView::dump() 2893 { 2894 #if HAVE_FEATURE_DESKTOP 2895 // Used for unit tests and in chartcontroller only, no need to drag in this when cross-compiling 2896 // for non-desktop 2897 impl_updateView(); 2898 uno::Reference< drawing::XShapes > xShapes( m_xDrawPage, uno::UNO_QUERY_THROW ); 2899 sal_Int32 n = xShapes->getCount(); 2900 OUStringBuffer aBuffer; 2901 for(sal_Int32 i = 0; i < n; ++i) 2902 { 2903 uno::Reference< drawing::XShapes > xShape(xShapes->getByIndex(i), uno::UNO_QUERY); 2904 if(xShape.is()) 2905 { 2906 XShapeDumper dumper; 2907 OUString aString = XShapeDumper::dump(mxRootShape); 2908 aBuffer.append(aString); 2909 } 2910 else 2911 { 2912 uno::Reference< drawing::XShape > xSingleShape(xShapes->getByIndex(i), uno::UNO_QUERY); 2913 if(!xSingleShape.is()) 2914 continue; 2915 XShapeDumper dumper; 2916 OUString aString = XShapeDumper::dump(xSingleShape); 2917 aBuffer.append(aString); 2918 } 2919 aBuffer.append("\n\n"); 2920 } 2921 2922 return aBuffer.makeStringAndClear(); 2923 #else 2924 return OUString(); 2925 #endif 2926 } 2927 2928 void ChartView::setViewDirty() 2929 { 2930 osl::ResettableMutexGuard aGuard(maTimeMutex); 2931 m_bViewDirty = true; 2932 } 2933 2934 IMPL_LINK_NOARG(ChartView, UpdateTimeBased, Timer *, void) 2935 { 2936 setViewDirty(); 2937 update(); 2938 } 2939 2940 void ChartView::createShapes2D( const awt::Size& rPageSize ) 2941 { 2942 ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory); 2943 2944 // todo: it would be nicer to just pass the page m_xDrawPage and format it, 2945 // but the draw page does not support XPropertySet 2946 formatPage( mrChartModel, rPageSize, mxRootShape, m_xShapeFactory ); 2947 2948 CreateShapeParam2D aParam; 2949 aParam.maRemainingSpace.X = 0; 2950 aParam.maRemainingSpace.Y = 0; 2951 aParam.maRemainingSpace.Width = rPageSize.Width; 2952 aParam.maRemainingSpace.Height = rPageSize.Height; 2953 2954 //create the group shape for diagram and axes first to have title and legends on top of it 2955 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() ); 2956 OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ) );//todo: other index if more than one diagram is possible 2957 uno::Reference< drawing::XShapes > xDiagramPlusAxesPlusMarkHandlesGroup_Shapes( 2958 pShapeFactory->createGroup2D(mxRootShape,aDiagramCID) ); 2959 2960 aParam.mxMarkHandles = pShapeFactory->createInvisibleRectangle( 2961 xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0)); 2962 ShapeFactory::setShapeName(aParam.mxMarkHandles, "MarkHandles"); 2963 2964 aParam.mxPlotAreaWithAxes = pShapeFactory->createInvisibleRectangle( 2965 xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0, 0)); 2966 ShapeFactory::setShapeName(aParam.mxPlotAreaWithAxes, "PlotAreaIncludingAxes"); 2967 2968 aParam.mxDiagramWithAxesShapes = pShapeFactory->createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes); 2969 2970 bool bAutoPositionDummy = true; 2971 2972 // create buttons 2973 lcl_createButtons(mxRootShape, m_xShapeFactory, mrChartModel, aParam.maRemainingSpace); 2974 2975 lcl_createTitle( 2976 TitleHelper::MAIN_TITLE, mxRootShape, m_xShapeFactory, mrChartModel, 2977 aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy); 2978 if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0) 2979 return; 2980 2981 lcl_createTitle( 2982 TitleHelper::SUB_TITLE, mxRootShape, m_xShapeFactory, mrChartModel, 2983 aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy ); 2984 if (aParam.maRemainingSpace.Width <= 0|| aParam.maRemainingSpace.Height <= 0) 2985 return; 2986 2987 aParam.mpSeriesPlotterContainer.reset(new SeriesPlotterContainer(m_aVCooSysList)); 2988 aParam.mpSeriesPlotterContainer->initializeCooSysAndSeriesPlotter( mrChartModel ); 2989 if(maTimeBased.bTimeBased && maTimeBased.nFrame != 0) 2990 { 2991 SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); 2992 size_t n = rSeriesPlotter.size(); 2993 for(size_t i = 0; i < n; ++i) 2994 { 2995 std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries(); 2996 std::vector< VDataSeries* >& rAllOldDataSeries = 2997 maTimeBased.m_aDataSeriesList[i]; 2998 size_t m = std::min(aAllNewDataSeries.size(), rAllOldDataSeries.size()); 2999 for(size_t j = 0; j < m; ++j) 3000 { 3001 aAllNewDataSeries[j]->setOldTimeBased( 3002 rAllOldDataSeries[j], (maTimeBased.nFrame % 60)/60.0); 3003 } 3004 } 3005 } 3006 3007 lcl_createLegend( 3008 LegendHelper::getLegend( mrChartModel ), mxRootShape, m_xShapeFactory, m_xCC, 3009 aParam.maRemainingSpace, rPageSize, mrChartModel, aParam.mpSeriesPlotterContainer->getLegendEntryProviderList(), 3010 lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) ); 3011 if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0) 3012 return; 3013 3014 if (!createAxisTitleShapes2D(aParam, rPageSize)) 3015 return; 3016 3017 bool bDummy = false; 3018 bool bIsVertical = DiagramHelper::getVertical(xDiagram, bDummy, bDummy); 3019 3020 if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, mrChartModel.getFirstDiagram())) 3021 { 3022 awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent(aParam, rPageSize); 3023 3024 if (aParam.mxPlotAreaWithAxes.is()) 3025 { 3026 aParam.mxPlotAreaWithAxes->setPosition(awt::Point(aUsedOuterRect.X, aUsedOuterRect.Y)); 3027 aParam.mxPlotAreaWithAxes->setSize(awt::Size(aUsedOuterRect.Width, aUsedOuterRect.Height)); 3028 } 3029 3030 //correct axis title position 3031 awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect ); 3032 if (aParam.mbAutoPosTitleX) 3033 changePositionOfAxisTitle(aParam.mpVTitleX.get(), ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize); 3034 if (aParam.mbAutoPosTitleY) 3035 changePositionOfAxisTitle(aParam.mpVTitleY.get(), ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize); 3036 if (aParam.mbAutoPosTitleZ) 3037 changePositionOfAxisTitle(aParam.mpVTitleZ.get(), ALIGN_Z, aDiagramPlusAxesRect, rPageSize); 3038 if (aParam.mbAutoPosSecondTitleX) 3039 changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? ALIGN_RIGHT : ALIGN_TOP, aDiagramPlusAxesRect, rPageSize); 3040 if (aParam.mbAutoPosSecondTitleY) 3041 changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? ALIGN_TOP : ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize); 3042 } 3043 3044 //cleanup: remove all empty group shapes to avoid grey border lines: 3045 lcl_removeEmptyGroupShapes( mxRootShape ); 3046 3047 if(maTimeBased.bTimeBased && maTimeBased.nFrame % 60 == 0) 3048 { 3049 // create copy of the data for next frame 3050 SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); 3051 size_t n = rSeriesPlotter.size(); 3052 maTimeBased.m_aDataSeriesList.clear(); 3053 maTimeBased.m_aDataSeriesList.resize(n); 3054 for(size_t i = 0; i < n; ++i) 3055 { 3056 std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries(); 3057 std::vector<VDataSeries*>& rAllOldDataSeries = maTimeBased.m_aDataSeriesList[i]; 3058 size_t m = aAllNewDataSeries.size(); 3059 for(size_t j = 0; j < m; ++j) 3060 { 3061 rAllOldDataSeries.push_back( aAllNewDataSeries[j]-> 3062 createCopyForTimeBased() ); 3063 } 3064 } 3065 3066 maTimeBased.maTimer.Stop(); 3067 } 3068 3069 if(maTimeBased.bTimeBased && !maTimeBased.maTimer.IsActive()) 3070 { 3071 maTimeBased.maTimer.SetTimeout(15); 3072 maTimeBased.maTimer.SetInvokeHandler(LINK(this, ChartView, UpdateTimeBased)); 3073 maTimeBased.maTimer.Start(); 3074 } 3075 } 3076 3077 bool ChartView::createAxisTitleShapes2D( CreateShapeParam2D& rParam, const css::awt::Size& rPageSize ) 3078 { 3079 uno::Reference<XDiagram> xDiagram = mrChartModel.getFirstDiagram(); 3080 3081 Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); 3082 sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram ); 3083 3084 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) ) 3085 rParam.mpVTitleX = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel 3086 , rParam.maRemainingSpace, rPageSize, ALIGN_BOTTOM, rParam.mbAutoPosTitleX ); 3087 if (rParam.maRemainingSpace.Width <= 0 ||rParam.maRemainingSpace.Height <= 0) 3088 return false; 3089 3090 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) ) 3091 rParam.mpVTitleY = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel 3092 , rParam.maRemainingSpace, rPageSize, ALIGN_LEFT, rParam.mbAutoPosTitleY ); 3093 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0) 3094 return false; 3095 3096 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) ) 3097 rParam.mpVTitleZ = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel 3098 , rParam.maRemainingSpace, rPageSize, ALIGN_RIGHT, rParam.mbAutoPosTitleZ ); 3099 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0) 3100 return false; 3101 3102 bool bDummy = false; 3103 bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); 3104 3105 if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) 3106 rParam.mpVTitleSecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel 3107 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_RIGHT : ALIGN_TOP, rParam.mbAutoPosSecondTitleX ); 3108 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0) 3109 return false; 3110 3111 if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) 3112 rParam.mpVTitleSecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel 3113 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_TOP : ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY ); 3114 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0) 3115 return false; 3116 3117 return true; 3118 } 3119 3120 } //namespace chart 3121 3122 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * 3123 com_sun_star_comp_chart2_ChartView_get_implementation(css::uno::XComponentContext *context, 3124 css::uno::Sequence<css::uno::Any> const &) 3125 { 3126 ::chart::ChartModel *pChartModel = new ::chart::ChartModel(context); 3127 return cppu::acquire(new ::chart::ChartView(context, *pChartModel)); 3128 } 3129 3130 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 3131
