/* -*- 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/. */ #pragma once #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 using namespace css; using namespace css::uno; namespace com::sun::star::chart2 { class XDataSeries; } namespace com::sun::star::chart2 { class XDiagram; } namespace com::sun::star::table { class XTableCharts; } namespace com::sun::star::table { class XTablePivotCharts; } class ChartTest : public UnoApiXmlTest { public: ChartTest(OUString path) : UnoApiXmlTest(path) { } uno::Sequence < OUString > getImpressChartColumnDescriptions(sal_Int32 nPage, sal_Int32 nShape); uno::Reference getChartDocFromDrawImpress( sal_Int32 nPage, sal_Int32 nShape ); uno::Reference getChartDocFromDrawImpressNamed( sal_Int32 nPage, std::u16string_view rName); uno::Reference getChartDocFromWriter( sal_Int32 nShape ); Sequence< OUString > getFormattedDateCategories( const Reference& xChartDoc ); awt::Size getPageSize( const Reference< chart2::XChartDocument > & xChartDoc ); awt::Size getSize(css::uno::Reference xDiagram, const awt::Size& rPageSize); }; Reference< lang::XComponent > getChartCompFromSheet( sal_Int32 nSheet, sal_Int32 nChart, uno::Reference< lang::XComponent > const & xComponent ) { // let us assume that we only have one chart per sheet uno::Reference< sheet::XSpreadsheetDocument > xDoc(xComponent, UNO_QUERY_THROW); uno::Reference< container::XIndexAccess > xIA(xDoc->getSheets(), UNO_QUERY_THROW); uno::Reference< table::XTableChartsSupplier > xChartSupplier( xIA->getByIndex(nSheet), UNO_QUERY_THROW); uno::Reference< table::XTableCharts > xCharts = xChartSupplier->getCharts(); CPPUNIT_ASSERT(xCharts.is()); uno::Reference< container::XIndexAccess > xIACharts(xCharts, UNO_QUERY_THROW); uno::Reference< table::XTableChart > xChart( xIACharts->getByIndex(nChart), UNO_QUERY_THROW); uno::Reference< document::XEmbeddedObjectSupplier > xEmbObjectSupplier(xChart, UNO_QUERY_THROW); uno::Reference< lang::XComponent > xChartComp( xEmbObjectSupplier->getEmbeddedObject(), UNO_SET_THROW ); return xChartComp; } Reference< chart2::XChartDocument > getChartDocFromSheet( sal_Int32 nSheet, uno::Reference< lang::XComponent > const & xComponent ) { uno::Reference< chart2::XChartDocument > xChartDoc ( getChartCompFromSheet(nSheet, 0, xComponent), UNO_QUERY_THROW ); // Update the chart view, so that its draw page is updated and ready for the test css::uno::Reference xModel(xChartDoc, css::uno::UNO_QUERY_THROW); ChartHelper::updateChart(xModel); return xChartDoc; } uno::Reference getTablePivotChartsFromSheet(sal_Int32 nSheet, uno::Reference const & xComponent) { uno::Reference xDoc(xComponent, UNO_QUERY_THROW); uno::Reference xIA(xDoc->getSheets(), UNO_QUERY_THROW); uno::Reference xChartSupplier(xIA->getByIndex(nSheet), UNO_QUERY_THROW); uno::Reference xTablePivotCharts = xChartSupplier->getPivotCharts(); CPPUNIT_ASSERT(xTablePivotCharts.is()); return xTablePivotCharts; } Reference getPivotChartCompFromSheet(sal_Int32 nSheet, uno::Reference const & xComponent) { uno::Reference xTablePivotCharts = getTablePivotChartsFromSheet(nSheet, xComponent); uno::Reference xIACharts(xTablePivotCharts, UNO_QUERY_THROW); uno::Reference xTablePivotChart(xIACharts->getByIndex(0), UNO_QUERY_THROW); uno::Reference xEmbObjectSupplier(xTablePivotChart, UNO_QUERY_THROW); uno::Reference xChartComp(xEmbObjectSupplier->getEmbeddedObject(), UNO_SET_THROW); return xChartComp; } Reference getPivotChartDocFromSheet(sal_Int32 nSheet, uno::Reference const & xComponent) { uno::Reference xChartDoc(getPivotChartCompFromSheet(nSheet, xComponent), UNO_QUERY_THROW); return xChartDoc; } Reference getPivotChartDocFromSheet(uno::Reference const & xTablePivotCharts, sal_Int32 nIndex) { uno::Reference xIACharts(xTablePivotCharts, UNO_QUERY_THROW); uno::Reference xTablePivotChart(xIACharts->getByIndex(nIndex), UNO_QUERY_THROW); uno::Reference xEmbObjectSupplier(xTablePivotChart, UNO_QUERY_THROW); uno::Reference xChartComp(xEmbObjectSupplier->getEmbeddedObject(), UNO_SET_THROW); uno::Reference xChartDoc(xChartComp, UNO_QUERY_THROW); return xChartDoc; } Reference< chart2::XChartType > getChartTypeFromDoc( Reference< chart2::XChartDocument > const & xChartDoc, sal_Int32 nChartType, sal_Int32 nCooSys = 0 ) { CPPUNIT_ASSERT( xChartDoc.is() ); Reference xDiagram = xChartDoc->getFirstDiagram(); CPPUNIT_ASSERT( xDiagram.is() ); Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, UNO_QUERY_THROW ); Sequence< Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems()); CPPUNIT_ASSERT( xCooSysSequence.getLength() > nCooSys ); Reference< chart2::XChartTypeContainer > xChartTypeContainer( xCooSysSequence[nCooSys], UNO_QUERY_THROW ); Sequence< Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() ); CPPUNIT_ASSERT( xChartTypeSequence.getLength() > nChartType ); return xChartTypeSequence[nChartType]; } Reference getAxisFromDoc( const Reference& xChartDoc, sal_Int32 nCooSys, sal_Int32 nAxisDim, sal_Int32 nAxisIndex ) { Reference xDiagram = xChartDoc->getFirstDiagram(); CPPUNIT_ASSERT(xDiagram.is()); Reference xCooSysContainer(xDiagram, UNO_QUERY_THROW); Sequence > xCooSysSequence = xCooSysContainer->getCoordinateSystems(); CPPUNIT_ASSERT(xCooSysSequence.getLength() > nCooSys); Reference xCoord = xCooSysSequence[nCooSys]; CPPUNIT_ASSERT(xCoord.is()); Reference xAxis = xCoord->getAxisByDimension(nAxisDim, nAxisIndex); CPPUNIT_ASSERT(xAxis.is()); return xAxis; } sal_Int32 getNumberOfDataSeries(uno::Reference const & xChartDoc, sal_Int32 nChartType = 0, sal_Int32 nCooSys = 0) { Reference xChartType = getChartTypeFromDoc(xChartDoc, nChartType, nCooSys); Reference xDataSeriesContainer(xChartType, UNO_QUERY_THROW); uno::Sequence> xSeriesSequence(xDataSeriesContainer->getDataSeries()); return xSeriesSequence.getLength(); } Reference< chart2::XDataSeries > getDataSeriesFromDoc(uno::Reference const & xChartDoc, sal_Int32 nDataSeries, sal_Int32 nChartType = 0, sal_Int32 nCooSys = 0) { Reference< chart2::XChartType > xChartType = getChartTypeFromDoc( xChartDoc, nChartType, nCooSys ); Reference< chart2::XDataSeriesContainer > xDataSeriesContainer( xChartType, UNO_QUERY_THROW ); Sequence< Reference< chart2::XDataSeries > > xSeriesSequence( xDataSeriesContainer->getDataSeries() ); CPPUNIT_ASSERT( xSeriesSequence.getLength() > nDataSeries ); Reference< chart2::XDataSeries > xSeries = xSeriesSequence[nDataSeries]; return xSeries; } Reference< chart2::data::XDataSequence > getLabelDataSequenceFromDoc( Reference< chart2::XChartDocument > const & xChartDoc, sal_Int32 nDataSeries = 0, sal_Int32 nChartType = 0 ) { Reference< chart2::XDataSeries > xDataSeries = getDataSeriesFromDoc( xChartDoc, nDataSeries, nChartType ); CPPUNIT_ASSERT(xDataSeries.is()); Reference< chart2::data::XDataSource > xDataSource( xDataSeries, uno::UNO_QUERY_THROW ); const Sequence< Reference< chart2::data::XLabeledDataSequence > > xDataSequences = xDataSource->getDataSequences(); for(auto const & lds : xDataSequences) { Reference< chart2::data::XDataSequence> xLabelSeq = lds->getLabel(); if(!xLabelSeq.is()) continue; return xLabelSeq; } CPPUNIT_FAIL("no Label sequence found"); } Reference< chart2::data::XDataSequence > getDataSequenceFromDocByRole( Reference< chart2::XChartDocument > const & xChartDoc, std::u16string_view rRole, sal_Int32 nDataSeries = 0, sal_Int32 nChartType = 0 ) { Reference< chart2::XDataSeries > xDataSeries = getDataSeriesFromDoc( xChartDoc, nDataSeries, nChartType ); CPPUNIT_ASSERT(xDataSeries.is()); Reference< chart2::data::XDataSource > xDataSource( xDataSeries, uno::UNO_QUERY_THROW ); const Sequence< Reference< chart2::data::XLabeledDataSequence > > xDataSequences = xDataSource->getDataSequences(); for(auto const & lds : xDataSequences) { Reference< chart2::data::XDataSequence> xLabelSeq = lds->getValues(); uno::Reference< beans::XPropertySet > xProps(xLabelSeq, uno::UNO_QUERY); if(!xProps.is()) continue; OUString aRoleName = xProps->getPropertyValue("Role").get(); if(aRoleName == rRole) return xLabelSeq; } return Reference< chart2::data::XDataSequence > (); } uno::Sequence < OUString > getWriterChartColumnDescriptions( Reference< lang::XComponent > const & mxComponent ) { uno::Reference xDrawPageSupplier(mxComponent, uno::UNO_QUERY); uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); uno::Reference xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); CPPUNIT_ASSERT( xShape.is() ); uno::Reference xPropertySet(xShape, uno::UNO_QUERY); uno::Reference< chart2::XChartDocument > xChartDoc; xChartDoc.set( xPropertySet->getPropertyValue( "Model" ), uno::UNO_QUERY ); CPPUNIT_ASSERT( xChartDoc.is() ); CPPUNIT_ASSERT( xChartDoc->getDataProvider().is() ); uno::Reference< chart2::XAnyDescriptionAccess > xAnyDescriptionAccess ( xChartDoc->getDataProvider(), uno::UNO_QUERY_THROW ); uno::Sequence< OUString > seriesList = xAnyDescriptionAccess->getColumnDescriptions(); return seriesList; } std::vector > getDataSeriesYValuesFromChartType( const Reference& xCT ) { Reference xDSCont(xCT, uno::UNO_QUERY); CPPUNIT_ASSERT(xDSCont.is()); const Sequence > aDataSeriesSeq = xDSCont->getDataSeries(); std::vector > aRet; for (uno::Reference const & ds : aDataSeriesSeq) { uno::Reference xDSrc(ds, uno::UNO_QUERY); CPPUNIT_ASSERT(xDSrc.is()); const uno::Sequence > aDataSeqs = xDSrc->getDataSequences(); for (auto const & lds : aDataSeqs) { Reference xValues = lds->getValues(); CPPUNIT_ASSERT(xValues.is()); Reference xPropSet(xValues, uno::UNO_QUERY); if (!xPropSet.is()) continue; OUString aRoleName; xPropSet->getPropertyValue("Role") >>= aRoleName; if (aRoleName == "values-y") { const uno::Sequence aData = xValues->getData(); std::vector aValues; aValues.reserve(aData.getLength()); for (uno::Any const & any : aData) { double fVal; if (any >>= fVal) aValues.push_back(fVal); else aValues.push_back(std::numeric_limits::quiet_NaN()); } aRet.push_back(aValues); } } } return aRet; } std::vector > getDataSeriesLabelsFromChartType( const Reference& xCT ) { OUString aLabelRole = xCT->getRoleOfSequenceForSeriesLabel(); Reference xDSCont(xCT, uno::UNO_QUERY); CPPUNIT_ASSERT(xDSCont.is()); const Sequence > aDataSeriesSeq = xDSCont->getDataSeries(); std::vector > aRet; for (auto const & ds : aDataSeriesSeq) { uno::Reference xDSrc(ds, uno::UNO_QUERY); CPPUNIT_ASSERT(xDSrc.is()); const uno::Sequence > aDataSeqs = xDSrc->getDataSequences(); for (auto const & lds : aDataSeqs) { Reference xValues = lds->getValues(); CPPUNIT_ASSERT(xValues.is()); Reference xPropSet(xValues, uno::UNO_QUERY); if (!xPropSet.is()) continue; OUString aRoleName; xPropSet->getPropertyValue("Role") >>= aRoleName; if (aRoleName == aLabelRole) { Reference xLabel = lds; CPPUNIT_ASSERT(xLabel.is()); Reference xDS2 = xLabel->getLabel(); CPPUNIT_ASSERT(xDS2.is()); uno::Sequence aData = xDS2->getData(); aRet.push_back(aData); } } } return aRet; } uno::Reference ChartTest::getChartDocFromDrawImpress( sal_Int32 nPage, sal_Int32 nShape ) { uno::Reference xEmpty; uno::Reference xPages(mxComponent, uno::UNO_QUERY); if (!xPages.is()) return xEmpty; uno::Reference xPage( xPages->getDrawPages()->getByIndex(nPage), uno::UNO_QUERY_THROW); uno::Reference xShapeProps(xPage->getByIndex(nShape), uno::UNO_QUERY); if (!xShapeProps.is()) return xEmpty; uno::Reference xDocModel; xShapeProps->getPropertyValue("Model") >>= xDocModel; if (!xDocModel.is()) return xEmpty; uno::Reference xChartDoc(xDocModel, uno::UNO_QUERY); return xChartDoc; } uno::Reference ChartTest::getChartDocFromDrawImpressNamed(sal_Int32 nPage, std::u16string_view rName) { uno::Reference xChart; uno::Reference xPages(mxComponent, uno::UNO_QUERY); if (!xPages.is()) return xChart; uno::Reference xPage(xPages->getDrawPages()->getByIndex(nPage), uno::UNO_QUERY); if (!xPage.is()) return xChart; for (sal_Int32 i=0; i < xPage->getCount(); ++i) { uno::Reference xNamedShape(xPage->getByIndex(i), uno::UNO_QUERY); if (!xNamedShape.is()) continue; if (xNamedShape->getName() != rName) continue; uno::Reference xShapeProps(xNamedShape, uno::UNO_QUERY); if (!xShapeProps.is()) continue; uno::Reference xDocModel; xShapeProps->getPropertyValue("Model") >>= xDocModel; if (!xDocModel.is()) continue; return uno::Reference(xDocModel, uno::UNO_QUERY); } return xChart; } uno::Reference ChartTest::getChartDocFromWriter( sal_Int32 nShape ) { // DO NOT use XDrawPageSupplier since SwVirtFlyDrawObj are not created // during import, only in layout! Reference xEOS(mxComponent, uno::UNO_QUERY); CPPUNIT_ASSERT(xEOS.is()); Reference xEmbeddeds(xEOS->getEmbeddedObjects(), uno::UNO_QUERY); CPPUNIT_ASSERT(xEmbeddeds.is()); Reference xShapeProps(xEmbeddeds->getByIndex(nShape), uno::UNO_QUERY); CPPUNIT_ASSERT(xShapeProps.is()); Reference xDocModel; xShapeProps->getPropertyValue("Model") >>= xDocModel; CPPUNIT_ASSERT(xDocModel.is()); uno::Reference xChartDoc(xDocModel, uno::UNO_QUERY); return xChartDoc; } uno::Sequence < OUString > ChartTest::getImpressChartColumnDescriptions(sal_Int32 nPage, sal_Int32 nShape) { uno::Reference< chart::XChartDocument > xChartDoc = getChartDocFromDrawImpress( nPage, nShape ); uno::Reference< chart::XChartDataArray > xChartData ( xChartDoc->getData(), uno::UNO_QUERY_THROW); uno::Sequence < OUString > seriesList = xChartData->getColumnDescriptions(); return seriesList; } OUString getTitleString( const Reference& xTitled ) { uno::Reference xTitle = xTitled->getTitleObject(); CPPUNIT_ASSERT(xTitle.is()); const uno::Sequence > aFSSeq = xTitle->getText(); OUString aText; for (auto const & fs : aFSSeq) aText += fs->getString(); return aText; } sal_Int32 getNumberFormat( const Reference& xChartDoc, const OUString& sFormat ) { Reference xNFS(xChartDoc, uno::UNO_QUERY_THROW); Reference xNumberFormats = xNFS->getNumberFormats(); CPPUNIT_ASSERT(xNumberFormats.is()); return xNumberFormats->queryKey(sFormat, css::lang::Locale(), false); } sal_Int32 getNumberFormatFromAxis( const Reference& xAxis ) { Reference xPS(xAxis, uno::UNO_QUERY); CPPUNIT_ASSERT(xPS.is()); sal_Int32 nNumberFormat = -1; bool bSuccess = xPS->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormat; CPPUNIT_ASSERT(bSuccess); return nNumberFormat; } sal_Int16 getNumberFormatType( const Reference& xChartDoc, sal_Int32 nNumberFormat ) { Reference xNFS(xChartDoc, uno::UNO_QUERY_THROW); Reference xNumberFormats = xNFS->getNumberFormats(); CPPUNIT_ASSERT(xNumberFormats.is()); Reference xNumPS = xNumberFormats->getByKey(nNumberFormat); CPPUNIT_ASSERT(xNumPS.is()); sal_Int16 nType = util::NumberFormat::UNDEFINED; xNumPS->getPropertyValue("Type") >>= nType; return nType; } Sequence< double > getDateCategories(const Reference& xChartDoc) { CPPUNIT_ASSERT(xChartDoc->hasInternalDataProvider()); uno::Reference< chart2::XInternalDataProvider > xDataProvider( xChartDoc->getDataProvider(), uno::UNO_QUERY_THROW ); uno::Reference< chart::XDateCategories > xDateCategories( xDataProvider, uno::UNO_QUERY_THROW ); CPPUNIT_ASSERT(xDateCategories.is()); return xDateCategories->getDateCategories(); } Sequence< OUString > ChartTest::getFormattedDateCategories( const Reference& xChartDoc ) { Reference xNFS(xChartDoc, uno::UNO_QUERY_THROW); Reference< util::XNumberFormatter > xNumFormatter( util::NumberFormatter::create(comphelper::getComponentContext(m_xSFactory)), uno::UNO_QUERY_THROW ); xNumFormatter->attachNumberFormatsSupplier(xNFS); Reference xAxisX = getAxisFromDoc(xChartDoc, 0, 0, 0); chart2::ScaleData aScaleData = xAxisX->getScaleData(); CPPUNIT_ASSERT_EQUAL(chart2::AxisType::DATE, aScaleData.AxisType); sal_Int32 nNumFmt = getNumberFormatFromAxis(xAxisX); Sequence aDateSeq = getDateCategories(xChartDoc); const sal_Int32 nNumCategories = aDateSeq.getLength(); Sequence aFormattedDates(nNumCategories); auto aFormattedDatesRange = asNonConstRange(aFormattedDates); for (sal_Int32 nIdx = 0; nIdx < nNumCategories; ++nIdx) aFormattedDatesRange[nIdx] = xNumFormatter->convertNumberToString(nNumFmt, aDateSeq[nIdx]); return aFormattedDates; } awt::Size ChartTest::getPageSize( const Reference< chart2::XChartDocument > & xChartDoc ) { awt::Size aSize( 0, 0 ); uno::Reference< com::sun::star::embed::XVisualObject > xVisualObject( xChartDoc, uno::UNO_QUERY ); CPPUNIT_ASSERT( xVisualObject.is() ); aSize = xVisualObject->getVisualAreaSize( com::sun::star::embed::Aspects::MSOLE_CONTENT ); return aSize; } awt::Size ChartTest::getSize(css::uno::Reference xDiagram, const awt::Size& rPageSize) { Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY); chart2::RelativeSize aRelativeSize; xProp->getPropertyValue( "RelativeSize" ) >>= aRelativeSize; double fX = aRelativeSize.Primary * rPageSize.Width; double fY = aRelativeSize.Secondary * rPageSize.Height; awt::Size aSize; aSize.Width = static_cast< sal_Int32 >( ::rtl::math::round( fX ) ); aSize.Height = static_cast< sal_Int32 >( ::rtl::math::round( fY ) ); return aSize; } uno::Reference getShapeByName(const uno::Reference& rShapes, const OUString& rName, const std::function&)>& pCondition = nullptr) { for (sal_Int32 i = 0; i < rShapes->getCount(); ++i) { uno::Reference xShapes(rShapes->getByIndex(i), uno::UNO_QUERY); if (xShapes.is()) { uno::Reference xRet = getShapeByName(xShapes, rName, pCondition); if (xRet.is()) return xRet; } uno::Reference xNamedShape(rShapes->getByIndex(i), uno::UNO_QUERY); if (xNamedShape->getName() == rName) { uno::Reference xShape(xNamedShape, uno::UNO_QUERY); if (pCondition == nullptr || pCondition(xShape)) return xShape; } } return uno::Reference(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */