/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include "SeriesPlotterContainer.hxx" #include #include #include #include #include #include #include #include "VTitle.hxx" #include "VButton.hxx" #include #include #include #include #include #include #include #include #include "VLegend.hxx" #include #include #include #include #include #include #include #include #include #include #include "AxisUsage.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace com::sun::star::chart2 { class XChartDocument; } namespace chart { using namespace ::com::sun::star; using namespace ::com::sun::star::chart2; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Any; struct CreateShapeParam2D { css::awt::Rectangle maRemainingSpace; std::shared_ptr mpSeriesPlotterContainer; std::shared_ptr mpVTitleX; std::shared_ptr mpVTitleY; std::shared_ptr mpVTitleZ; std::shared_ptr mpVTitleSecondX; std::shared_ptr mpVTitleSecondY; rtl::Reference mxMarkHandles; rtl::Reference mxPlotAreaWithAxes; rtl::Reference mxDiagramWithAxesShapes; bool mbAutoPosTitleX; bool mbAutoPosTitleY; bool mbAutoPosTitleZ; bool mbAutoPosSecondTitleX; bool mbAutoPosSecondTitleY; bool mbUseFixedInnerSize; CreateShapeParam2D() : mbAutoPosTitleX(true), mbAutoPosTitleY(true), mbAutoPosTitleZ(true), mbAutoPosSecondTitleX(true), mbAutoPosSecondTitleY(true), mbUseFixedInnerSize(false) {} }; ChartView::ChartView( uno::Reference const & xContext, ChartModel& rModel) : m_xCC(xContext) , mrChartModel(rModel) , m_aListenerContainer( m_aMutex ) , m_bViewDirty(true) , m_bInViewUpdate(false) , m_bViewUpdatePending(false) , m_bRefreshAddIn(true) , m_aPageResolution(1000,1000) , m_bPointsWereSkipped(false) , m_nScaleXNumerator(1) , m_nScaleXDenominator(1) , m_nScaleYNumerator(1) , m_nScaleYDenominator(1) , m_bSdrViewIsInEditMode(false) , m_aResultingDiagramRectangleExcludingAxes(0,0,0,0) { init(); } void ChartView::init() { if( !m_pDrawModelWrapper ) { SolarMutexGuard aSolarGuard; m_pDrawModelWrapper = std::make_shared< DrawModelWrapper >(); m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory(); m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage(); StartListening( m_pDrawModelWrapper->getSdrModel() ); } } void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& ) { init(); } ChartView::~ChartView() { maTimeBased.maTimer.Stop(); // #i120831#. In ChartView::initialize(), m_xShapeFactory is created from SdrModel::getUnoModel() and indirectly // from SfxBaseModel, it needs call dispose() to make sure SfxBaseModel object is freed correctly. uno::Reference< lang::XComponent > xComp( m_xShapeFactory, uno::UNO_QUERY); if ( xComp.is() ) xComp->dispose(); if( m_pDrawModelWrapper ) { SolarMutexGuard aSolarGuard; EndListening( m_pDrawModelWrapper->getSdrModel() ); m_pDrawModelWrapper.reset(); } m_xDrawPage = nullptr; impl_deleteCoordinateSystems(); } void ChartView::impl_deleteCoordinateSystems() { //delete all coordinate systems m_aVCooSysList.clear(); } // datatransfer::XTransferable namespace { constexpr OUStringLiteral lcl_aGDIMetaFileMIMEType( u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ); constexpr OUStringLiteral lcl_aGDIMetaFileMIMETypeHighContrast( u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" ); } // anonymous namespace void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream , bool bUseHighContrast ) { if( !m_xDrawPage.is() ) return; // creating the graphic exporter uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( m_xCC ); uno::Sequence< beans::PropertyValue > aFilterData{ comphelper::makePropertyValue("ExportOnlyBackground", false), comphelper::makePropertyValue("HighContrast", bUseHighContrast), comphelper::makePropertyValue("Version", sal_Int32(SOFFICE_FILEFORMAT_50)), comphelper::makePropertyValue("CurrentPage", uno::Reference< uno::XInterface >( static_cast(m_xDrawPage.get()), uno::UNO_QUERY )), //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% comphelper::makePropertyValue("ScaleXNumerator", m_nScaleXNumerator), comphelper::makePropertyValue("ScaleXDenominator", m_nScaleXDenominator), comphelper::makePropertyValue("ScaleYNumerator", m_nScaleYNumerator), comphelper::makePropertyValue("ScaleYDenominator", m_nScaleYDenominator) }; uno::Sequence< beans::PropertyValue > aProps{ comphelper::makePropertyValue("FilterName", OUString("SVM")), comphelper::makePropertyValue("OutputStream", xOutStream), comphelper::makePropertyValue("FilterData", aFilterData) }; xExporter->setSourceDocument( m_xDrawPage ); if( xExporter->filter( aProps ) ) { xOutStream->flush(); xOutStream->closeOutput(); uno::Reference< io::XSeekable > xSeekable( xOutStream, uno::UNO_QUERY ); if( xSeekable.is() ) xSeekable->seek(0); } } uno::Any SAL_CALL ChartView::getTransferData( const datatransfer::DataFlavor& aFlavor ) { bool bHighContrastMetaFile( aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast); uno::Any aRet; if( ! (bHighContrastMetaFile || aFlavor.MimeType == lcl_aGDIMetaFileMIMEType) ) return aRet; update(); SvMemoryStream aStream( 1024, 1024 ); rtl::Reference pStreamWrapper = new utl::OStreamWrapper( aStream ); this->getMetaFile( pStreamWrapper, bHighContrastMetaFile ); pStreamWrapper->seek(0); sal_Int32 nBytesToRead = pStreamWrapper->available(); uno::Sequence< sal_Int8 > aSeq( nBytesToRead ); pStreamWrapper->readBytes( aSeq, nBytesToRead); aRet <<= aSeq; pStreamWrapper->closeInput(); return aRet; } uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors() { return { { lcl_aGDIMetaFileMIMEType, "GDIMetaFile", cppu::UnoType>::get() }, { lcl_aGDIMetaFileMIMETypeHighContrast, "GDIMetaFile", cppu::UnoType>::get() } }; } sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) { return ( aFlavor.MimeType == lcl_aGDIMetaFileMIMEType || aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast ); } // ____ XUnoTunnel ___ ::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier ) { return comphelper::getSomethingImpl(aIdentifier, this); } // lang::XServiceInfo OUString SAL_CALL ChartView::getImplementationName() { return CHART_VIEW_SERVICE_IMPLEMENTATION_NAME; } sal_Bool SAL_CALL ChartView::supportsService( const OUString& rServiceName ) { return cppu::supportsService(this, rServiceName); } css::uno::Sequence< OUString > SAL_CALL ChartView::getSupportedServiceNames() { return { CHART_VIEW_SERVICE_NAME }; } static ::basegfx::B3DHomMatrix createTransformationSceneToScreen( const ::basegfx::B2IRectangle& rDiagramRectangleWithoutAxes ) { ::basegfx::B3DHomMatrix aM; aM.scale(double(rDiagramRectangleWithoutAxes.getWidth())/FIXED_SIZE_FOR_3D_CHART_VOLUME , -double(rDiagramRectangleWithoutAxes.getHeight())/FIXED_SIZE_FOR_3D_CHART_VOLUME, 1.0 ); aM.translate(double(rDiagramRectangleWithoutAxes.getMinX()) , double(rDiagramRectangleWithoutAxes.getMinY()+rDiagramRectangleWithoutAxes.getHeight()-1), 0); return aM; } namespace { bool lcl_IsPieOrDonut( const rtl::Reference< Diagram >& xDiagram ) { //special treatment for pie charts //the size is checked after complete creation to get the datalabels into the given space //todo: this is just a workaround at the moment for pie and donut labels return DiagramHelper::isPieOrDonutChart( xDiagram ); } void lcl_setDefaultWritingMode( const std::shared_ptr< DrawModelWrapper >& pDrawModelWrapper, ChartModel& rModel) { //get writing mode from parent document: if( !SvtCTLOptions().IsCTLFontEnabled() ) return; try { sal_Int16 nWritingMode=-1; uno::Reference< beans::XPropertySet > xParentProps( rModel.getParent(), uno::UNO_QUERY ); uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSupplier( xParentProps, uno::UNO_QUERY ); if( xStyleFamiliesSupplier.is() ) { uno::Reference< container::XNameAccess > xStylesFamilies( xStyleFamiliesSupplier->getStyleFamilies() ); if( xStylesFamilies.is() ) { if( !xStylesFamilies->hasByName( "PageStyles" ) ) { //draw/impress is parent document uno::Reference< lang::XMultiServiceFactory > xFatcory( xParentProps, uno::UNO_QUERY ); if( xFatcory.is() ) { uno::Reference< beans::XPropertySet > xDrawDefaults( xFatcory->createInstance( "com.sun.star.drawing.Defaults" ), uno::UNO_QUERY ); if( xDrawDefaults.is() ) xDrawDefaults->getPropertyValue( "WritingMode" ) >>= nWritingMode; } } else { uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( "PageStyles" ), uno::UNO_QUERY ); if( xPageStyles.is() ) { OUString aPageStyle; uno::Reference< text::XTextDocument > xTextDocument( xParentProps, uno::UNO_QUERY ); if( xTextDocument.is() ) { //writer is parent document //retrieve the current page style from the text cursor property PageStyleName uno::Reference< text::XTextEmbeddedObjectsSupplier > xTextEmbeddedObjectsSupplier( xTextDocument, uno::UNO_QUERY ); if( xTextEmbeddedObjectsSupplier.is() ) { uno::Reference< container::XNameAccess > xEmbeddedObjects( xTextEmbeddedObjectsSupplier->getEmbeddedObjects() ); if( xEmbeddedObjects.is() ) { uno::Sequence< OUString > aNames( xEmbeddedObjects->getElementNames() ); sal_Int32 nCount = aNames.getLength(); for( sal_Int32 nN=0; nN xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY ); if( xEmbeddedProps.is() ) { static OUString aChartCLSID = SvGlobalName( SO3_SCH_CLASSID ).GetHexName(); OUString aCLSID; xEmbeddedProps->getPropertyValue( "CLSID" ) >>= aCLSID; if( aCLSID == aChartCLSID ) { uno::Reference< text::XTextContent > xEmbeddedObject( xEmbeddedProps, uno::UNO_QUERY ); if( xEmbeddedObject.is() ) { uno::Reference< text::XTextRange > xAnchor( xEmbeddedObject->getAnchor() ); if( xAnchor.is() ) { uno::Reference< beans::XPropertySet > xAnchorProps( xAnchor, uno::UNO_QUERY ); if( xAnchorProps.is() ) { xAnchorProps->getPropertyValue( "WritingMode" ) >>= nWritingMode; } uno::Reference< text::XText > xText( xAnchor->getText() ); if( xText.is() ) { uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); if( xTextCursorProps.is() ) xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle; } } } break; } } } } } if( aPageStyle.isEmpty() ) { uno::Reference< text::XText > xText( xTextDocument->getText() ); if( xText.is() ) { uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); if( xTextCursorProps.is() ) xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle; } } if(aPageStyle.isEmpty()) aPageStyle = "Standard"; } else { //Calc is parent document Reference< com::sun::star::beans::XPropertySetInfo > xInfo = xParentProps->getPropertySetInfo(); if (xInfo->hasPropertyByName("PageStyle")) { xParentProps->getPropertyValue( "PageStyle" ) >>= aPageStyle; } if(aPageStyle.isEmpty()) aPageStyle = "Default"; } if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE ) { uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY ); Reference< com::sun::star::beans::XPropertySetInfo > xInfo = xPageStyle->getPropertySetInfo(); if (xInfo->hasPropertyByName("WritingMode")) { if( xPageStyle.is() ) xPageStyle->getPropertyValue( "WritingMode" ) >>= nWritingMode; } } } } } } if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE ) { if( pDrawModelWrapper ) pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SvxFrameDirectionItem(static_cast(nWritingMode), EE_PARA_WRITINGDIR) ); } } catch( const uno::Exception& ) { DBG_UNHANDLED_EXCEPTION("chart2" ); } } sal_Int16 lcl_getDefaultWritingModeFromPool( const std::shared_ptr& pDrawModelWrapper ) { sal_Int16 nWritingMode = text::WritingMode2::LR_TB; if(!pDrawModelWrapper) return nWritingMode; const SfxPoolItem& rItem = pDrawModelWrapper->GetItemPool().GetDefaultItem(EE_PARA_WRITINGDIR); nWritingMode = static_cast(static_cast(rItem).GetValue()); return nWritingMode; } } //end anonymous namespace awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D& rParam, const awt::Size& rPageSize ) { //return the used rectangle awt::Rectangle aUsedOuterRect(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y, 0, 0); rtl::Reference< Diagram > xDiagram( mrChartModel.getFirstChartDiagram() ); if( !xDiagram.is()) return aUsedOuterRect; sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); if(!nDimensionCount) { //@todo handle mixed dimension nDimensionCount = 2; } basegfx::B2IRectangle aAvailableOuterRect = BaseGFXHelper::makeRectangle(rParam.maRemainingSpace); const std::vector< std::unique_ptr >& rVCooSysList( rParam.mpSeriesPlotterContainer->getCooSysList() ); auto& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList(); //create VAxis, so they can give necessary information for automatic scaling uno::Reference const xNumberFormatsSupplier( mrChartModel.getNumberFormatsSupplier()); for (auto& rpVCooSys : rVCooSysList) { if (nDimensionCount == 3) { CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xDiagram ) ); CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xDiagram ) ); CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xDiagram ) ); rpVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos ); } rpVCooSys->createVAxisList(&mrChartModel, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize); } // - prepare list of all axis and how they are used Date aNullDate = NumberFormatterWrapper( xNumberFormatsSupplier ).getNullDate(); rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate); rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel ); rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter(); rParam.mpSeriesPlotterContainer->setNumberFormatsFromAxes(); //create shapes //aspect ratio drawing::Direction3D aPreferredAspectRatio = rParam.mpSeriesPlotterContainer->getPreferredAspectRatio(); rtl::Reference xSeriesTargetInFrontOfAxis; rtl::Reference xSeriesTargetBehindAxis; VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount); {//create diagram aVDiagram.init(rParam.mxDiagramWithAxesShapes); aVDiagram.createShapes( awt::Point(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y), awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height)); xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion(); // It is preferable to use full size than minimum for pie charts if (!rParam.mbUseFixedInnerSize) aVDiagram.reduceToMinimumSize(); } rtl::Reference xTextTargetShapes = ShapeFactory::createGroup2D(rParam.mxDiagramWithAxesShapes); // - create axis and grids for all coordinate systems //init all coordinate systems for (auto& rpVCooSys : rVCooSysList) { rpVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis, xTextTargetShapes, xSeriesTargetBehindAxis); rpVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); rpVCooSys->initVAxisInList(); } //calculate resulting size respecting axis label layout and fontscaling rtl::Reference xBoundingShape(rParam.mxDiagramWithAxesShapes); ::basegfx::B2IRectangle aConsumedOuterRect; //use first coosys only so far; todo: calculate for more than one coosys if we have more in future //todo: this is just a workaround at the moment for pie and donut labels bool bIsPieOrDonut = lcl_IsPieOrDonut(xDiagram); if( !bIsPieOrDonut && (!rVCooSysList.empty()) ) { VCoordinateSystem* pVCooSys = rVCooSysList[0].get(); pVCooSys->createMaximumAxesLabels(); aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); if (!rParam.mbUseFixedInnerSize) aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen( aNewInnerRect ) )); //redo autoscaling to get size and text dependent automatic main increment count rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel ); rParam.mpSeriesPlotterContainer->updateScalesAndIncrementsOnAxes(); rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter(); pVCooSys->createAxesLabels(); bool bLessSpaceConsumedThanExpected = false; { aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); if( aConsumedOuterRect.getMinX() > aAvailableOuterRect.getMinX() || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX() || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY() || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() ) { bLessSpaceConsumedThanExpected = true; } } if (bLessSpaceConsumedThanExpected && !rParam.mbUseFixedInnerSize) { aVDiagram.adjustInnerSize( aConsumedOuterRect ); pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); // Need to re-adjust again if the labels have changed height because of // text can break. Ideally this shouldn't be needed, but the chart height // isn't readjusted otherwise. pVCooSys->createAxesLabels(); aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); aVDiagram.adjustInnerSize(aConsumedOuterRect); pVCooSys->setTransformationSceneToScreen(B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen(aVDiagram.getCurrentRectangle()))); } 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 } //create axes and grids for the final size for (auto& rpVCooSys : rVCooSysList) { rpVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); rpVCooSys->createAxesShapes(); rpVCooSys->createGridShapes(); } // - create data series for all charttypes m_bPointsWereSkipped = false; for( const std::unique_ptr& aPlotter : rSeriesPlotterList ) { VSeriesPlotter* pSeriesPlotter = aPlotter.get(); rtl::Reference xSeriesTarget; if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() ) xSeriesTarget = xSeriesTargetInFrontOfAxis; else { xSeriesTarget = xSeriesTargetBehindAxis; OSL_ENSURE( !bIsPieOrDonut, "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" ); } pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,OUString() ); pSeriesPlotter->setPageReferenceSize( rPageSize ); VCoordinateSystem* pVCooSys = SeriesPlotterContainer::getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); if(nDimensionCount==2) pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); //better performance for big data { //calculate resolution for coordinate system Sequence aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution ); pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution ); } // Do not allow to move data labels in case of pie or donut chart, yet! pSeriesPlotter->setPieLabelsAllowToMove(!bIsPieOrDonut); // use the pagesize as remaining space if we have a fixed inner size if( rParam.mbUseFixedInnerSize ) aAvailableOuterRect = BaseGFXHelper::makeRectangle(awt::Rectangle(0, 0, rPageSize.Width, rPageSize.Height)); // set the available space for data labels to avoid moving out from chart area pSeriesPlotter->setAvailableOuterRect(aAvailableOuterRect); pSeriesPlotter->createShapes(); m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped(); } //recreate all with corrected sizes if requested if( bIsPieOrDonut ) { m_bPointsWereSkipped = false; aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); if (!rParam.mbUseFixedInnerSize) aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); for( std::unique_ptr& aPlotter : rSeriesPlotterList ) { aPlotter->releaseShapes(); } //clear and recreate ShapeFactory::removeSubShapes( xSeriesTargetInFrontOfAxis ); //xSeriesTargetBehindAxis is a sub shape of xSeriesTargetInFrontOfAxis and will be removed here xSeriesTargetBehindAxis.clear(); ShapeFactory::removeSubShapes( xTextTargetShapes ); //set new transformation for (auto& rpVCooSys : rVCooSysList) { auto aMatrix = createTransformationSceneToScreen(aNewInnerRect); rpVCooSys->setTransformationSceneToScreen(B3DHomMatrixToHomogenMatrix(aMatrix)); } // - create data series for all charttypes for( std::unique_ptr& aPlotter : rSeriesPlotterList ) { VCoordinateSystem* pVCooSys = SeriesPlotterContainer::getCooSysForPlotter( rVCooSysList, aPlotter.get() ); if(nDimensionCount==2) aPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); // Now we can move data labels in case of pie or donut chart! aPlotter->setPieLabelsAllowToMove(bIsPieOrDonut); aPlotter->createShapes(); m_bPointsWereSkipped = m_bPointsWereSkipped || aPlotter->PointsWereSkipped(); } for( std::unique_ptr& aPlotter : rSeriesPlotterList ) aPlotter->rearrangeLabelToAvoidOverlapIfRequested(rPageSize); } if (rParam.mbUseFixedInnerSize) { aUsedOuterRect = awt::Rectangle( aConsumedOuterRect.getMinX(), aConsumedOuterRect.getMinY(), aConsumedOuterRect.getWidth(), aConsumedOuterRect.getHeight() ); } else aUsedOuterRect = rParam.maRemainingSpace; bool bSnapRectToUsedArea = false; for( std::unique_ptr& aPlotter : rSeriesPlotterList ) { bSnapRectToUsedArea = aPlotter->shouldSnapRectToUsedArea(); if(bSnapRectToUsedArea) break; } if(bSnapRectToUsedArea) { if (rParam.mbUseFixedInnerSize) m_aResultingDiagramRectangleExcludingAxes = getRectangleOfObject( "PlotAreaExcludingAxes" ); else { ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); m_aResultingDiagramRectangleExcludingAxes = BaseGFXHelper::toAwtRectangle(aConsumedInnerRect); } } else { if (rParam.mbUseFixedInnerSize) m_aResultingDiagramRectangleExcludingAxes = rParam.maRemainingSpace; else { ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); m_aResultingDiagramRectangleExcludingAxes = BaseGFXHelper::toAwtRectangle(aConsumedInnerRect); } } if (rParam.mxMarkHandles.is()) { awt::Point aPos(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y); awt::Size aSize(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height); bool bPosSizeExcludeAxesProperty = true; xDiagram->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty; if (rParam.mbUseFixedInnerSize || bPosSizeExcludeAxesProperty) { aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y ); aSize = awt::Size( m_aResultingDiagramRectangleExcludingAxes.Width, m_aResultingDiagramRectangleExcludingAxes.Height ); } rParam.mxMarkHandles->setPosition(aPos); rParam.mxMarkHandles->setSize(aSize); } return aUsedOuterRect; } bool ChartView::getExplicitValuesForAxis( uno::Reference< XAxis > xAxis , ExplicitScaleData& rExplicitScale , ExplicitIncrementData& rExplicitIncrement ) { SolarMutexGuard aSolarGuard; impl_updateView(); if(!xAxis.is()) return false; rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstChartDiagram() ); const VCoordinateSystem* pVCooSys = SeriesPlotterContainer::findInCooSysList(m_aVCooSysList, xCooSys); if(!pVCooSys) return false; sal_Int32 nDimensionIndex=-1; sal_Int32 nAxisIndex=-1; if( !AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) ) return false; rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex); rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex); if( !rExplicitScale.m_bShiftedCategoryPosition ) return true; //remove 'one' from max if( rExplicitScale.AxisType == css::chart2::AxisType::DATE ) { Date aMaxDate(rExplicitScale.NullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum)); //for explicit scales with shifted categories we need one interval more switch( rExplicitScale.TimeResolution ) { case css::chart::TimeUnit::DAY: --aMaxDate; break; case css::chart::TimeUnit::MONTH: aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1); break; case css::chart::TimeUnit::YEAR: aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1); break; } rExplicitScale.Maximum = aMaxDate - rExplicitScale.NullDate; } else if( rExplicitScale.AxisType == css::chart2::AxisType::CATEGORY ) rExplicitScale.Maximum -= 1.0; else if( rExplicitScale.AxisType == css::chart2::AxisType::SERIES ) rExplicitScale.Maximum -= 1.0; return true; } SdrPage* ChartView::getSdrPage() { if(m_xDrawPage) return m_xDrawPage->GetSdrPage(); return nullptr; } rtl::Reference< SvxShape > ChartView::getShapeForCID( const OUString& rObjectCID ) { SolarMutexGuard aSolarGuard; SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() ); if( !pObj ) return nullptr; uno::Reference< drawing::XShape > xShape = pObj->getUnoShape(); rtl::Reference xShape2 = dynamic_cast(xShape.get()); assert(xShape2 || !xShape); return xShape2; } awt::Rectangle ChartView::getDiagramRectangleExcludingAxes() { impl_updateView(); return m_aResultingDiagramRectangleExcludingAxes; } awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool bSnapRect ) { impl_updateView(); awt::Rectangle aRet; rtl::Reference< SvxShape > xShape = getShapeForCID(rObjectCID); if(xShape.is()) { //special handling for axis for old api: //same special handling for diagram ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) ); if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM ) { SolarMutexGuard aSolarGuard; SdrObject* pRootSdrObject = xShape->GetSdrObject(); if( pRootSdrObject ) { SdrObjList* pRootList = pRootSdrObject->GetSubList(); if( pRootList ) { OUString aShapeName = "MarkHandles"; if( eObjectType == OBJECTTYPE_DIAGRAM ) aShapeName = "PlotAreaIncludingAxes"; SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList ); if( pShape ) { xShape = dynamic_cast(pShape->getUnoShape().get()); assert(xShape); } } } } awt::Size aSize( xShape->getSize() ); awt::Point aPoint( xShape->getPosition() ); aRet = awt::Rectangle( aPoint.X, aPoint.Y, aSize.Width, aSize.Height ); if( bSnapRect ) { //for rotated objects the shape size and position differs from the visible rectangle SdrObject* pSdrObject = xShape->GetSdrObject(); if( pSdrObject ) { tools::Rectangle aSnapRect( pSdrObject->GetSnapRect() ); aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight()); } } } return aRet; } std::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper() { return m_pDrawModelWrapper; } namespace { constexpr double constPageLayoutDistancePercentage = 0.02; bool getAvailablePosAndSizeForDiagram( CreateShapeParam2D& rParam, const awt::Size & rPageSize, const uno::Reference< beans::XPropertySet >& xProp) { rParam.mbUseFixedInnerSize = false; //@todo: we need a size dependent on the axis labels sal_Int32 nYDistance = static_cast(rPageSize.Height * constPageLayoutDistancePercentage); sal_Int32 nXDistance = static_cast(rPageSize.Width * constPageLayoutDistancePercentage); rParam.maRemainingSpace.X += nXDistance; rParam.maRemainingSpace.Width -= 2*nXDistance; rParam.maRemainingSpace.Y += nYDistance; rParam.maRemainingSpace.Height -= 2*nYDistance; bool bPosSizeExcludeAxes = false; if( xProp.is() ) xProp->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes; //size: css::chart2::RelativeSize aRelativeSize; if( xProp.is() && (xProp->getPropertyValue( "RelativeSize" )>>=aRelativeSize) ) { rParam.maRemainingSpace.Height = static_cast(aRelativeSize.Secondary*rPageSize.Height); rParam.maRemainingSpace.Width = static_cast(aRelativeSize.Primary*rPageSize.Width); rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes; } if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0) return false; //position: chart2::RelativePosition aRelativePosition; if( xProp.is() && (xProp->getPropertyValue( "RelativePosition" )>>=aRelativePosition) ) { //@todo decide whether x is primary or secondary //the coordinates re relative to the page double fX = aRelativePosition.Primary*rPageSize.Width; double fY = aRelativePosition.Secondary*rPageSize.Height; awt::Point aPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( awt::Point(static_cast(fX),static_cast(fY)), awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height), aRelativePosition.Anchor); rParam.maRemainingSpace.X = aPos.X; rParam.maRemainingSpace.Y = aPos.Y; rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes; } //ensure that the diagram does not lap out right side or out of bottom if (rParam.maRemainingSpace.Y + rParam.maRemainingSpace.Height > rPageSize.Height) rParam.maRemainingSpace.Height = rPageSize.Height - rParam.maRemainingSpace.Y; if (rParam.maRemainingSpace.X + rParam.maRemainingSpace.Width > rPageSize.Width) rParam.maRemainingSpace.Width = rPageSize.Width - rParam.maRemainingSpace.X; return true; } enum class TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z }; void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment , awt::Rectangle const & rDiagramPlusAxesRect, const awt::Size & rPageSize ) { if(!pVTitle) return; awt::Point aNewPosition(0,0); awt::Size aTitleSize = pVTitle->getFinalSize(); sal_Int32 nYDistance = static_cast(rPageSize.Height * constPageLayoutDistancePercentage); sal_Int32 nXDistance = static_cast(rPageSize.Width * constPageLayoutDistancePercentage); switch (eAlignment) { case TitleAlignment::ALIGN_TOP: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance ); break; case TitleAlignment::ALIGN_BOTTOM: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance ); break; case TitleAlignment::ALIGN_LEFT: aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); break; case TitleAlignment::ALIGN_RIGHT: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); break; case TitleAlignment::ALIGN_Z: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 ); break; } sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2; sal_Int32 nMaxX = rPageSize.Width - aTitleSize.Width/2; sal_Int32 nMinX = aTitleSize.Width/2; sal_Int32 nMinY = aTitleSize.Height/2; if( aNewPosition.Y > nMaxY ) aNewPosition.Y = nMaxY; if( aNewPosition.X > nMaxX ) aNewPosition.X = nMaxX; if( aNewPosition.Y < nMinY ) aNewPosition.Y = nMinY; if( aNewPosition.X < nMinX ) aNewPosition.X = nMinX; pVTitle->changePosition( aNewPosition ); } std::shared_ptr lcl_createTitle( TitleHelper::eTitleType eType , const rtl::Reference& xPageShapes , ChartModel& rModel , awt::Rectangle& rRemainingSpace , const awt::Size & rPageSize , TitleAlignment eAlignment , bool& rbAutoPosition ) { std::shared_ptr apVTitle; // #i109336# Improve auto positioning in chart double fPercentage = constPageLayoutDistancePercentage; sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage ); sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage ); if ( eType == TitleHelper::MAIN_TITLE ) { nYDistance += 135; // 1/100 mm } else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION ) { nYDistance = 420; // 1/100 mm } else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION ) { nXDistance = 450; // 1/100 mm } uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, rModel ) ); OUString aCompleteString = TitleHelper::getCompleteString(xTitle); if (aCompleteString.isEmpty() || !VTitle::isVisible(xTitle)) return apVTitle; //create title awt::Size aTextMaxWidth(rPageSize.Width, rPageSize.Height); bool bYAxisTitle = false; if (eType == TitleHelper::MAIN_TITLE || eType == TitleHelper::SUB_TITLE) { aTextMaxWidth.Width = static_cast(rPageSize.Width * 0.8); aTextMaxWidth.Height = static_cast(rPageSize.Height * 0.5); } else if (eType == TitleHelper::X_AXIS_TITLE || eType == TitleHelper::SECONDARY_X_AXIS_TITLE || eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION) { aTextMaxWidth.Width = static_cast(rPageSize.Width * 0.8); aTextMaxWidth.Height = static_cast(rPageSize.Height * 0.2); } else if (eType == TitleHelper::Y_AXIS_TITLE || eType == TitleHelper::SECONDARY_Y_AXIS_TITLE || eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION) { aTextMaxWidth.Width = static_cast(rPageSize.Width * 0.2); aTextMaxWidth.Height = static_cast(rPageSize.Height * 0.8); bYAxisTitle = true; } apVTitle = std::make_shared(xTitle); OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, &rModel); apVTitle->init(xPageShapes, aCID); apVTitle->createShapes(awt::Point(0, 0), rPageSize, aTextMaxWidth, bYAxisTitle); awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize(); awt::Size aTitleSize = apVTitle->getFinalSize(); //position rbAutoPosition = true; awt::Point aNewPosition(0,0); chart2::RelativePosition aRelativePosition; uno::Reference xProp(xTitle, uno::UNO_QUERY); if (xProp.is() && (xProp->getPropertyValue("RelativePosition") >>= aRelativePosition)) { rbAutoPosition = false; //@todo decide whether x is primary or secondary double fX = aRelativePosition.Primary*rPageSize.Width; double fY = aRelativePosition.Secondary*rPageSize.Height; double fAnglePi = apVTitle->getRotationAnglePi(); aNewPosition = RelativePositionHelper::getCenterOfAnchoredObject( awt::Point(static_cast(fX),static_cast(fY)) , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi ); } else //auto position { switch( eAlignment ) { case TitleAlignment::ALIGN_TOP: aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance ); break; case TitleAlignment::ALIGN_BOTTOM: aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance ); break; case TitleAlignment::ALIGN_LEFT: aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance , rRemainingSpace.Y + rRemainingSpace.Height/2 ); break; case TitleAlignment::ALIGN_RIGHT: aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance , rRemainingSpace.Y + rRemainingSpace.Height/2 ); break; case TitleAlignment::ALIGN_Z: break; } } apVTitle->changePosition( aNewPosition ); //remaining space switch( eAlignment ) { case TitleAlignment::ALIGN_TOP: // Push the remaining space down from top. rRemainingSpace.Y += ( aTitleSize.Height + nYDistance ); rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); break; case TitleAlignment::ALIGN_BOTTOM: // Push the remaining space up from bottom. rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); break; case TitleAlignment::ALIGN_LEFT: // Push the remaining space to the right from left edge. rRemainingSpace.X += ( aTitleSize.Width + nXDistance ); rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); break; case TitleAlignment::ALIGN_RIGHT: // Push the remaining space to the left from right edge. rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); break; case TitleAlignment::ALIGN_Z: break; } return apVTitle; } bool lcl_createLegend( const rtl::Reference< Legend > & xLegend , const rtl::Reference& xPageShapes , const uno::Reference< uno::XComponentContext > & xContext , awt::Rectangle & rRemainingSpace , const awt::Size & rPageSize , ChartModel& rModel , std::vector< LegendEntryProvider* >&& rLegendEntryProviderList , sal_Int16 nDefaultWritingMode ) { if (!VLegend::isVisible(xLegend)) return false; awt::Size rDefaultLegendSize; VLegend aVLegend( xLegend, xContext, std::move(rLegendEntryProviderList), xPageShapes, rModel); aVLegend.setDefaultWritingMode( nDefaultWritingMode ); aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ), rPageSize, rDefaultLegendSize ); aVLegend.changePosition( rRemainingSpace, rPageSize, rDefaultLegendSize ); return true; } void lcl_createButtons(const rtl::Reference& xPageShapes, ChartModel& rModel, awt::Rectangle& rRemainingSpace) { uno::Reference xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY); if (!xPivotTableDataProvider.is()) return; uno::Reference xModelPage(rModel.getPageBackground()); awt::Size aSize(4000, 700); // size of the button tools::Long x = 0; if (xPivotTableDataProvider->getPageFields().hasElements()) { x = 0; const css::uno::Sequence aPivotFieldEntries = xPivotTableDataProvider->getPageFields(); for (css::chart2::data::PivotTableFieldEntry const & rPageFieldEntry : aPivotFieldEntries) { VButton aButton; aButton.init(xPageShapes); awt::Point aNewPosition(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100); sal_Int32 nDimensionIndex = rPageFieldEntry.DimensionIndex; OUString aFieldOutputDescription = xPivotTableDataProvider->getFieldOutputDescription(nDimensionIndex); aButton.setLabel(rPageFieldEntry.Name + " | " + aFieldOutputDescription); aButton.setCID("FieldButton.Page." + OUString::number(nDimensionIndex)); aButton.setPosition(aNewPosition); aButton.setSize(aSize); if (rPageFieldEntry.HasHiddenMembers) aButton.setArrowColor(Color(0x0000FF)); aButton.createShapes(xModelPage); x += aSize.Width + 100; } rRemainingSpace.Y += (aSize.Height + 100 + 100); rRemainingSpace.Height -= (aSize.Height + 100 + 100); } aSize = awt::Size(3000, 700); // size of the button if (!xPivotTableDataProvider->getRowFields().hasElements()) return; x = 200; const css::uno::Sequence aPivotFieldEntries = xPivotTableDataProvider->getRowFields(); for (css::chart2::data::PivotTableFieldEntry const & rRowFieldEntry : aPivotFieldEntries) { VButton aButton; aButton.init(xPageShapes); awt::Point aNewPosition(rRemainingSpace.X + x + 100, rRemainingSpace.Y + rRemainingSpace.Height - aSize.Height - 100); aButton.setLabel(rRowFieldEntry.Name); aButton.setCID("FieldButton.Row." + OUString::number(rRowFieldEntry.DimensionIndex)); aButton.setPosition(aNewPosition); aButton.setSize(aSize); if ( rRowFieldEntry.Name == "Data" ) { aButton.setBGColor( Color(0x00F6F6F6) ); aButton.showArrow( false ); } else if (rRowFieldEntry.HasHiddenMembers) aButton.setArrowColor(Color(0x0000FF)); aButton.createShapes(xModelPage); x += aSize.Width + 100; } rRemainingSpace.Height -= (aSize.Height + 100 + 100); } void formatPage( ChartModel& rChartModel , const awt::Size& rPageSize , const rtl::Reference& xTarget ) { try { uno::Reference< beans::XPropertySet > xModelPage( rChartModel.getPageBackground()); if( ! xModelPage.is()) return; //format page tPropertyNameValueMap aNameValueMap; PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage ); OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ); aNameValueMap.emplace( "Name", uno::Any( aCID ) ); //CID OUString tNameSequence aNames; tAnySequence aValues; PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap ); ShapeFactory::createRectangle( xTarget, rPageSize, awt::Point(0, 0), aNames, aValues); } catch( const uno::Exception & ) { DBG_UNHANDLED_EXCEPTION("chart2" ); } } void lcl_removeEmptyGroupShapes( const SdrObject& rParent ) { SdrObjList* pObjList = rParent.getChildrenOfSdrObject(); if (!pObjList || pObjList->GetObjCount() == 0) return; //iterate from back! for(auto nIdx = static_cast(pObjList->GetObjCount() - 1); nIdx >= 0; --nIdx) { SdrObject* pChildSdrObject = pObjList->GetObj(nIdx); SdrObjList* pChildObjList = pChildSdrObject->getChildrenOfSdrObject(); if (!pChildObjList) continue; if (pChildObjList->GetObjCount() == 0) { //remove empty group shape SdrObject* pRemoved = pObjList->NbcRemoveObject(nIdx); SdrObject::Free( pRemoved ); } else lcl_removeEmptyGroupShapes(*pChildSdrObject); } } } void ChartView::impl_refreshAddIn() { if( !m_bRefreshAddIn ) return; uno::Reference< beans::XPropertySet > xProp( static_cast< ::cppu::OWeakObject* >( &mrChartModel ), uno::UNO_QUERY ); if( !xProp.is()) return; try { uno::Reference< util::XRefreshable > xAddIn; xProp->getPropertyValue( "AddIn" ) >>= xAddIn; if( xAddIn.is() ) { bool bRefreshAddInAllowed = true; xProp->getPropertyValue( "RefreshAddInAllowed" ) >>= bRefreshAddInAllowed; if( bRefreshAddInAllowed ) xAddIn->refresh(); } } catch( const uno::Exception& ) { TOOLS_WARN_EXCEPTION("chart2", "" ); } } void ChartView::createShapes() { SolarMutexGuard aSolarGuard; osl::MutexGuard aTimedGuard(maTimeMutex); if(mrChartModel.isTimeBased()) { maTimeBased.bTimeBased = true; } //make sure add-in is refreshed after creating the shapes const ::comphelper::ScopeGuard aGuard( [this]() { this->impl_refreshAddIn(); } ); m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle(0,0,0,0); impl_deleteCoordinateSystems(); if( m_pDrawModelWrapper ) { // #i12587# support for shapes in chart m_pDrawModelWrapper->getSdrModel().EnableUndo( false ); m_pDrawModelWrapper->clearMainDrawPage(); } lcl_setDefaultWritingMode( m_pDrawModelWrapper, mrChartModel ); awt::Size aPageSize = mrChartModel.getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); if(!mxRootShape.is()) mxRootShape = ShapeFactory::getOrCreateChartRootShape( m_xDrawPage ); SdrPage* pPage = ChartView::getSdrPage(); if(pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset pPage->SetSize(Size(aPageSize.Width,aPageSize.Height)); else { OSL_FAIL("could not set page size correctly"); } ShapeFactory::setPageSize(mxRootShape, aPageSize); createShapes2D(aPageSize); // #i12587# support for shapes in chart if ( m_pDrawModelWrapper ) { m_pDrawModelWrapper->getSdrModel().EnableUndo( true ); } if(maTimeBased.bTimeBased) { maTimeBased.nFrame++; } } // util::XEventListener (base of XCloseListener) void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ ) { } void ChartView::impl_updateView( bool bCheckLockedCtrler ) { if( !m_pDrawModelWrapper ) return; // #i12587# support for shapes in chart if ( m_bSdrViewIsInEditMode ) { return; } if (bCheckLockedCtrler && mrChartModel.hasControllersLocked()) return; if( !m_bViewDirty || m_bInViewUpdate ) return; m_bInViewUpdate = true; //bool bOldRefreshAddIn = m_bRefreshAddIn; //m_bRefreshAddIn = false; try { impl_notifyModeChangeListener("invalid"); //prepare draw model { SolarMutexGuard aSolarGuard; m_pDrawModelWrapper->lockControllers(); } //create chart view { m_bViewDirty = false; m_bViewUpdatePending = false; createShapes(); if( m_bViewDirty ) { //avoid recursions due to add-in m_bRefreshAddIn = false; m_bViewDirty = false; m_bViewUpdatePending = false; //delete old chart view createShapes(); m_bRefreshAddIn = true; } } m_bViewDirty = m_bViewUpdatePending; m_bViewUpdatePending = false; m_bInViewUpdate = false; } catch( const uno::Exception& ) { DBG_UNHANDLED_EXCEPTION("chart2" ); m_bViewDirty = m_bViewUpdatePending; m_bViewUpdatePending = false; m_bInViewUpdate = false; } { SolarMutexGuard aSolarGuard; m_pDrawModelWrapper->unlockControllers(); } impl_notifyModeChangeListener("valid"); //m_bRefreshAddIn = bOldRefreshAddIn; } // ____ XModifyListener ____ void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ ) { m_bViewDirty = true; if( m_bInViewUpdate ) m_bViewUpdatePending = true; impl_notifyModeChangeListener("dirty"); } //SfxListener void ChartView::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) { //#i77362 change notification for changes on additional shapes are missing if( m_bInViewUpdate ) return; // #i12587# support for shapes in chart if ( m_bSdrViewIsInEditMode ) { uno::Reference< view::XSelectionSupplier > xSelectionSupplier( mrChartModel.getCurrentController(), uno::UNO_QUERY ); if ( xSelectionSupplier.is() ) { OUString aSelObjCID; uno::Any aSelObj( xSelectionSupplier->getSelection() ); aSelObj >>= aSelObjCID; if ( !aSelObjCID.isEmpty() ) { return; } } } if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint) return; const SdrHint* pSdrHint = static_cast< const SdrHint* >(&rHint); bool bShapeChanged = false; switch( pSdrHint->GetKind() ) { case SdrHintKind::ObjectChange: bShapeChanged = true; break; case SdrHintKind::ObjectInserted: bShapeChanged = true; break; case SdrHintKind::ObjectRemoved: bShapeChanged = true; break; case SdrHintKind::ModelCleared: bShapeChanged = true; break; case SdrHintKind::EndEdit: bShapeChanged = true; break; default: break; } if(bShapeChanged) { //#i76053# do not send view modified notifications for changes on the hidden page which contains e.g. the symbols for the dialogs if( ChartView::getSdrPage() != pSdrHint->GetPage() ) bShapeChanged=false; } if(!bShapeChanged) return; mrChartModel.setModified(true); } void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode ) { try { comphelper::OInterfaceContainerHelper2* pIC = m_aListenerContainer .getContainer( cppu::UnoType::get()); if( pIC ) { util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode ); comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); while( aIt.hasMoreElements() ) { static_cast< util::XModeChangeListener* >( aIt.next() )->modeChanged( aEvent ); } } } catch( const uno::Exception& ) { DBG_UNHANDLED_EXCEPTION("chart2"); } } // ____ XModeChangeBroadcaster ____ void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) { m_aListenerContainer.addInterface( cppu::UnoType::get(), xListener ); } void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) { m_aListenerContainer.removeInterface( cppu::UnoType::get(), xListener ); } void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) { } void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) { } // ____ XUpdatable ____ void SAL_CALL ChartView::update() { impl_updateView(); //#i100778# migrate all imported or old documents to a plot area sizing exclusive axes (in case the save settings allow for this): //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. //When a view update is requested (what happens for creating the metafile or displaying //the chart in edit mode or printing) it is most likely that all necessary information is available - like the underlying spreadsheet data for example. //Those data are important for the correct axis label sizes which are needed during conversion. if( DiagramHelper::switchDiagramPositioningToExcludingPositioning( mrChartModel, true, false ) ) impl_updateView(); } void SAL_CALL ChartView::updateSoft() { update(); } void SAL_CALL ChartView::updateHard() { impl_updateView(false); } // ____ XPropertySet ____ Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo() { OSL_FAIL("not implemented"); return nullptr; } void SAL_CALL ChartView::setPropertyValue( const OUString& rPropertyName , const Any& rValue ) { if( rPropertyName == "Resolution" ) { awt::Size aNewResolution; if( ! (rValue >>= aNewResolution) ) throw lang::IllegalArgumentException( "Property 'Resolution' requires value of type awt::Size", nullptr, 0 ); if( m_aPageResolution.Width!=aNewResolution.Width || m_aPageResolution.Height!=aNewResolution.Height ) { //set modified only when the new resolution is higher and points were skipped before bool bSetModified = m_bPointsWereSkipped && (m_aPageResolution.Widthmodified( lang::EventObject( static_cast< uno::XWeak* >( this ) ) ); } } else if( rPropertyName == "ZoomFactors" ) { //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% uno::Sequence< beans::PropertyValue > aZoomFactors; if( ! (rValue >>= aZoomFactors) ) throw lang::IllegalArgumentException( "Property 'ZoomFactors' requires value of type Sequence< PropertyValue >", nullptr, 0 ); sal_Int32 nFilterArgs = aZoomFactors.getLength(); const beans::PropertyValue* pDataValues = aZoomFactors.getConstArray(); while( nFilterArgs-- ) { if ( pDataValues->Name == "ScaleXNumerator" ) pDataValues->Value >>= m_nScaleXNumerator; else if ( pDataValues->Name == "ScaleXDenominator" ) pDataValues->Value >>= m_nScaleXDenominator; else if ( pDataValues->Name == "ScaleYNumerator" ) pDataValues->Value >>= m_nScaleYNumerator; else if ( pDataValues->Name == "ScaleYDenominator" ) pDataValues->Value >>= m_nScaleYDenominator; pDataValues++; } } else if( rPropertyName == "SdrViewIsInEditMode" ) { //#i77362 change notification for changes on additional shapes are missing if( ! (rValue >>= m_bSdrViewIsInEditMode) ) throw lang::IllegalArgumentException( "Property 'SdrViewIsInEditMode' requires value of type sal_Bool", nullptr, 0 ); } else throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard " + rPropertyName, nullptr ); } Any SAL_CALL ChartView::getPropertyValue( const OUString& rPropertyName ) { if( rPropertyName != "Resolution" ) throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard " + rPropertyName, nullptr ); return Any(m_aPageResolution); } void SAL_CALL ChartView::addPropertyChangeListener( const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ ) { OSL_FAIL("not implemented"); } void SAL_CALL ChartView::removePropertyChangeListener( const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ ) { OSL_FAIL("not implemented"); } void SAL_CALL ChartView::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) { OSL_FAIL("not implemented"); } void SAL_CALL ChartView::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) { OSL_FAIL("not implemented"); } // ____ XMultiServiceFactory ____ Reference< uno::XInterface > ChartView::createInstance( const OUString& aServiceSpecifier ) { SolarMutexGuard aSolarGuard; SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : nullptr ); if ( pModel ) { if ( aServiceSpecifier == "com.sun.star.drawing.DashTable" ) { if ( !m_xDashTable.is() ) { m_xDashTable = SvxUnoDashTable_createInstance( pModel ); } return m_xDashTable; } else if ( aServiceSpecifier == "com.sun.star.drawing.GradientTable" ) { if ( !m_xGradientTable.is() ) { m_xGradientTable = SvxUnoGradientTable_createInstance( pModel ); } return m_xGradientTable; } else if ( aServiceSpecifier == "com.sun.star.drawing.HatchTable" ) { if ( !m_xHatchTable.is() ) { m_xHatchTable = SvxUnoHatchTable_createInstance( pModel ); } return m_xHatchTable; } else if ( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" ) { if ( !m_xBitmapTable.is() ) { m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel ); } return m_xBitmapTable; } else if ( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" ) { if ( !m_xTransGradientTable.is() ) { m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel ); } return m_xTransGradientTable; } else if ( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" ) { if ( !m_xMarkerTable.is() ) { m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel ); } return m_xMarkerTable; } } return nullptr; } Reference< uno::XInterface > ChartView::createInstanceWithArguments( const OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments ) { OSL_ENSURE( Arguments.hasElements(), "ChartView::createInstanceWithArguments: arguments are ignored" ); return createInstance( ServiceSpecifier ); } uno::Sequence< OUString > ChartView::getAvailableServiceNames() { uno::Sequence< OUString > aServiceNames{ "com.sun.star.drawing.DashTable", "com.sun.star.drawing.GradientTable", "com.sun.star.drawing.HatchTable", "com.sun.star.drawing.BitmapTable", "com.sun.star.drawing.TransparencyGradientTable", "com.sun.star.drawing.MarkerTable" }; return aServiceNames; } OUString ChartView::dump() { #if HAVE_FEATURE_DESKTOP // Used for unit tests and in chartcontroller only, no need to drag in this when cross-compiling // for non-desktop impl_updateView(); sal_Int32 n = m_xDrawPage->getCount(); OUStringBuffer aBuffer; for(sal_Int32 i = 0; i < n; ++i) { uno::Reference< drawing::XShapes > xShape(m_xDrawPage->getByIndex(i), uno::UNO_QUERY); if(xShape.is()) { OUString aString = XShapeDumper::dump(uno::Reference(mxRootShape)); aBuffer.append(aString); } else { uno::Reference< drawing::XShape > xSingleShape(m_xDrawPage->getByIndex(i), uno::UNO_QUERY); if(!xSingleShape.is()) continue; OUString aString = XShapeDumper::dump(xSingleShape); aBuffer.append(aString); } aBuffer.append("\n\n"); } return aBuffer.makeStringAndClear(); #else return OUString(); #endif } void ChartView::dumpAsXml(xmlTextWriterPtr pWriter) const { (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartView")); (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); if (m_pDrawModelWrapper) { m_pDrawModelWrapper->dumpAsXml(pWriter); } (void)xmlTextWriterEndElement(pWriter); } void ChartView::setViewDirty() { osl::MutexGuard aGuard(maTimeMutex); m_bViewDirty = true; } IMPL_LINK_NOARG(ChartView, UpdateTimeBased, Timer *, void) { setViewDirty(); update(); } void ChartView::createShapes2D( const awt::Size& rPageSize ) { // todo: it would be nicer to just pass the page m_xDrawPage and format it, // but the draw page does not support XPropertySet formatPage( mrChartModel, rPageSize, mxRootShape ); CreateShapeParam2D aParam; aParam.maRemainingSpace.X = 0; aParam.maRemainingSpace.Y = 0; aParam.maRemainingSpace.Width = rPageSize.Width; aParam.maRemainingSpace.Height = rPageSize.Height; //create the group shape for diagram and axes first to have title and legends on top of it rtl::Reference< Diagram > xDiagram( mrChartModel.getFirstChartDiagram() ); bool bHasRelativeSize = false; if( xDiagram.is() && xDiagram->getPropertyValue("RelativeSize").hasValue() ) bHasRelativeSize = true; OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ) );//todo: other index if more than one diagram is possible rtl::Reference xDiagramPlusAxesPlusMarkHandlesGroup_Shapes = ShapeFactory::createGroup2D(mxRootShape,aDiagramCID); aParam.mxMarkHandles = ShapeFactory::createInvisibleRectangle( xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0)); ShapeFactory::setShapeName(aParam.mxMarkHandles, "MarkHandles"); aParam.mxPlotAreaWithAxes = ShapeFactory::createInvisibleRectangle( xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0, 0)); ShapeFactory::setShapeName(aParam.mxPlotAreaWithAxes, "PlotAreaIncludingAxes"); aParam.mxDiagramWithAxesShapes = ShapeFactory::createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes); bool bAutoPositionDummy = true; // create buttons lcl_createButtons(mxRootShape, mrChartModel, aParam.maRemainingSpace); lcl_createTitle( TitleHelper::MAIN_TITLE, mxRootShape, mrChartModel, aParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_TOP, bAutoPositionDummy); if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) return; lcl_createTitle( TitleHelper::SUB_TITLE, mxRootShape, mrChartModel, aParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_TOP, bAutoPositionDummy ); if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) return; aParam.mpSeriesPlotterContainer = std::make_shared(m_aVCooSysList); aParam.mpSeriesPlotterContainer->initializeCooSysAndSeriesPlotter( mrChartModel ); if(maTimeBased.bTimeBased && maTimeBased.nFrame != 0) { auto& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); size_t n = rSeriesPlotter.size(); for(size_t i = 0; i < n; ++i) { std::vector aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries(); std::vector< VDataSeries* >& rAllOldDataSeries = maTimeBased.m_aDataSeriesList[i]; size_t m = std::min(aAllNewDataSeries.size(), rAllOldDataSeries.size()); for(size_t j = 0; j < m; ++j) { aAllNewDataSeries[j]->setOldTimeBased( rAllOldDataSeries[j], (maTimeBased.nFrame % 60)/60.0); } } } lcl_createLegend( LegendHelper::getLegend( mrChartModel ), mxRootShape, m_xCC, aParam.maRemainingSpace, rPageSize, mrChartModel, aParam.mpSeriesPlotterContainer->getLegendEntryProviderList(), lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) ); if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) return; if (!createAxisTitleShapes2D(aParam, rPageSize, bHasRelativeSize)) return; bool bDummy = false; bool bIsVertical = DiagramHelper::getVertical(xDiagram, bDummy, bDummy); if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, xDiagram)) { awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent(aParam, rPageSize); if (aParam.mxPlotAreaWithAxes.is()) { aParam.mxPlotAreaWithAxes->setPosition(awt::Point(aUsedOuterRect.X, aUsedOuterRect.Y)); aParam.mxPlotAreaWithAxes->setSize(awt::Size(aUsedOuterRect.Width, aUsedOuterRect.Height)); } //correct axis title position awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect ); if (aParam.mbAutoPosTitleX) changePositionOfAxisTitle(aParam.mpVTitleX.get(), TitleAlignment::ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosTitleY) changePositionOfAxisTitle(aParam.mpVTitleY.get(), TitleAlignment::ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosTitleZ) changePositionOfAxisTitle(aParam.mpVTitleZ.get(), TitleAlignment::ALIGN_Z, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosSecondTitleX) changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? TitleAlignment::ALIGN_RIGHT : TitleAlignment::ALIGN_TOP, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosSecondTitleY) changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? TitleAlignment::ALIGN_TOP : TitleAlignment::ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize); } //cleanup: remove all empty group shapes to avoid grey border lines: lcl_removeEmptyGroupShapes( *mxRootShape->GetSdrObject() ); if(maTimeBased.bTimeBased && maTimeBased.nFrame % 60 == 0) { // create copy of the data for next frame auto& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); size_t n = rSeriesPlotter.size(); maTimeBased.m_aDataSeriesList.clear(); maTimeBased.m_aDataSeriesList.resize(n); for(size_t i = 0; i < n; ++i) { std::vector aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries(); std::vector& rAllOldDataSeries = maTimeBased.m_aDataSeriesList[i]; size_t m = aAllNewDataSeries.size(); for(size_t j = 0; j < m; ++j) { rAllOldDataSeries.push_back( aAllNewDataSeries[j]-> createCopyForTimeBased() ); } } maTimeBased.maTimer.Stop(); } if(maTimeBased.bTimeBased && !maTimeBased.maTimer.IsActive()) { maTimeBased.maTimer.SetTimeout(15); maTimeBased.maTimer.SetInvokeHandler(LINK(this, ChartView, UpdateTimeBased)); maTimeBased.maTimer.Start(); } } bool ChartView::createAxisTitleShapes2D( CreateShapeParam2D& rParam, const css::awt::Size& rPageSize, bool bHasRelativeSize ) { rtl::Reference xDiagram = mrChartModel.getFirstChartDiagram(); rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram ); if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) ) rParam.mpVTitleX = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, mxRootShape, mrChartModel , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_BOTTOM, rParam.mbAutoPosTitleX ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) ) rParam.mpVTitleY = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, mxRootShape, mrChartModel , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_LEFT, rParam.mbAutoPosTitleY ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) ) rParam.mpVTitleZ = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, mxRootShape, mrChartModel , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_RIGHT, rParam.mbAutoPosTitleZ ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; bool bDummy = false; bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) rParam.mpVTitleSecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, mxRootShape, mrChartModel , rParam.maRemainingSpace, rPageSize, bIsVertical? TitleAlignment::ALIGN_RIGHT : TitleAlignment::ALIGN_TOP, rParam.mbAutoPosSecondTitleX ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) rParam.mpVTitleSecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, mxRootShape, mrChartModel , rParam.maRemainingSpace, rPageSize, bIsVertical? TitleAlignment::ALIGN_TOP : TitleAlignment::ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; return true; } } //namespace chart extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_chart2_ChartView_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence const &) { rtl::Reference<::chart::ChartModel> pChartModel = new ::chart::ChartModel(context); return cppu::acquire(new ::chart::ChartView(context, *pChartModel)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */