diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2017-02-26 22:48:06 +0100 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2017-04-04 13:39:29 +0000 |
commit | 9009663deb8f0862f419fd99bf0b761c7f923eff (patch) | |
tree | ea25976de0919f9d2161037d83be0eace4c1070b /xmloff | |
parent | 1931b5b01c6fdaa204d26ec4b9675dad16373cf2 (diff) |
tdf#83257 [API-CHANGE] Pivot chart implementation
This is a squashed commit of the pivot chart implementation.
Some of the changes:
- Add pivot chart specific (pivot table) data provider which
provides the data from a pivot table to the associated chart.
- When inserting a chart and the cursor is in a pivot table,
in that case insert a pivot chart
- Modify the pivot chart when the pivot table changes
- Collect and set the number format for the values
- isDataFromSpreadsheet check for the creation wizard
- In ChartView (and VLegend) check if the data provider is a
pivot chart data provider and get the pivot table field names
to create the buttons on the UI.
- Adds the functionallity to show a filter pop-up (from calc)
when clicking on row / column / page field buttons.
- Remove (X)PopupRequest as we won't need it.
- Add ODF import/export for pivot charts:
+ Added loext:data-pilot-source attribute on chart:chart
which is the internal name of the pivot table with which the
pivot chart is associated with. If the element is present, then
the it means the chart is a pivot chart, else it is a normal
chart
+ Added service to create pivot chart data provider through UNO
+ Add new methods to XPivotChartDataProvider to create value and
label data sequences separately from the data source, which is
needed for pivot chart import
+ When importing defer setting the data provider until a later
time when we know if we are creating a chart od a pivot chart
- Pivot chart ODF round-trip test
- Add table pivot chart supplier API:
This adds the XTablePivotChartSupplier and related interfaces so
we can access, create, delete pivot charts from UNO in a sheet
document. With this we now distinguish between normal charts
and pivot charts. This was mainly needed because we can't extend
the "published" interfaces of TableChartSupplier.
- Added an extensive test, which uses the API to create a new
pivot chart when there was none, and checks that the pivot chart
updates when the pivot table updates.
Change-Id: Ia9ed96fd6b1d342e61c2f7f9fa33a5e03dda21af
Reviewed-on: https://gerrit.libreoffice.org/36023
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'xmloff')
-rw-r--r-- | xmloff/inc/SchXMLImport.hxx | 3 | ||||
-rw-r--r-- | xmloff/source/chart/SchXMLChartContext.cxx | 72 | ||||
-rw-r--r-- | xmloff/source/chart/SchXMLChartContext.hxx | 2 | ||||
-rw-r--r-- | xmloff/source/chart/SchXMLExport.cxx | 8 | ||||
-rw-r--r-- | xmloff/source/chart/SchXMLImport.cxx | 61 | ||||
-rw-r--r-- | xmloff/source/chart/SchXMLSeries2Context.cxx | 50 | ||||
-rw-r--r-- | xmloff/source/chart/SchXMLTools.cxx | 21 | ||||
-rw-r--r-- | xmloff/source/core/xmltoken.cxx | 1 | ||||
-rw-r--r-- | xmloff/source/token/tokens.txt | 3 |
9 files changed, 152 insertions, 69 deletions
diff --git a/xmloff/inc/SchXMLImport.hxx b/xmloff/inc/SchXMLImport.hxx index 233ecde5b6c9..a1c3f698dca3 100644 --- a/xmloff/inc/SchXMLImport.hxx +++ b/xmloff/inc/SchXMLImport.hxx @@ -97,7 +97,8 @@ enum SchXMLChartAttrMap XML_TOK_CHART_HEIGHT, XML_TOK_CHART_STYLE_NAME, XML_TOK_CHART_COL_MAPPING, - XML_TOK_CHART_ROW_MAPPING + XML_TOK_CHART_ROW_MAPPING, + XML_TOK_CHART_DATA_PILOT_SOURCE, }; enum SchXMLPlotAreaAttrTokenMap diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx index 4ce36805398c..1dc1c145e16e 100644 --- a/xmloff/source/chart/SchXMLChartContext.cxx +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -52,11 +52,15 @@ #include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/chart2/data/XDataSink.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart2/XDataSeriesContainer.hpp> #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> #include <com/sun/star/chart2/XChartTypeContainer.hpp> #include <com/sun/star/chart2/XTitled.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/chart2/data/XDataReceiver.hpp> + using namespace com::sun::star; using namespace ::xmloff::token; using com::sun::star::uno::Reference; @@ -237,10 +241,67 @@ SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper, SchXMLChartContext::~SchXMLChartContext() {} +void lcl_setDataProvider(uno::Reference<chart2::XChartDocument> const & xChartDoc, OUString const & sDataPilotSource) +{ + if (!xChartDoc.is()) + return; + + try + { + uno::Reference<container::XChild> xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference<chart2::data::XDataReceiver> xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) + { + bool bHasOwnData = true; + + Reference<lang::XMultiServiceFactory> xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) + { + if (!xChartDoc->getDataProvider().is()) + { + bool bHasDataPilotSource = !sDataPilotSource.isEmpty(); + OUString aDataProviderServiceName("com.sun.star.chart2.data.DataProvider"); + if (bHasDataPilotSource) + aDataProviderServiceName = "com.sun.star.chart2.data.PivotTableDataProvider"; + + const uno::Sequence<OUString> aServiceNames(xFact->getAvailableServiceNames()); + + if (std::find(aServiceNames.begin(), aServiceNames.end(), aDataProviderServiceName) != aServiceNames.end()) + { + Reference<chart2::data::XDataProvider> xProvider(xFact->createInstance(aDataProviderServiceName), uno::UNO_QUERY); + + if (xProvider.is()) + { + xDataReceiver->attachDataProvider(xProvider); + if (bHasDataPilotSource) + { + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xProvider, uno::UNO_QUERY); + xPivotTableDataProvider->setPivotTableName(sDataPilotSource); + } + bHasOwnData = false; + } + } + } + else + bHasOwnData = false; + } + // else we have no parent => we have our own data + + if (bHasOwnData && ! xChartDoc->hasInternalDataProvider()) + xChartDoc->createInternalDataProvider(false); + } + } + catch (const uno::Exception & rEx) + { + OString aBStr(OUStringToOString(rEx.Message, RTL_TEXTENCODING_ASCII_US)); + SAL_INFO("xmloff.chart", "SchXMLChartContext::StartElement(): Exception caught: " << aBStr); + } +} + void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) { // parse attributes - sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap(); uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY); @@ -264,10 +325,12 @@ void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttribut switch( rAttrTokenMap.Get( nPrefix, aLocalName )) { + case XML_TOK_CHART_DATA_PILOT_SOURCE: + msDataPilotSource = aValue; + break; case XML_TOK_CHART_HREF: m_aXLinkHRefAttributeToIndicateDataProvider = aValue; break; - case XML_TOK_CHART_CLASS: { OUString sClassName; @@ -328,6 +391,11 @@ void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttribut } } + uno::Reference<chart::XChartDocument> xDoc = mrImportHelper.GetChartDocument(); + uno::Reference<chart2::XChartDocument> xNewDoc(xDoc, uno::UNO_QUERY); + + lcl_setDataProvider(xNewDoc, msDataPilotSource); + if( aOldChartTypeName.isEmpty() ) { SAL_WARN("xmloff.chart", "need a charttype to create a diagram" ); diff --git a/xmloff/source/chart/SchXMLChartContext.hxx b/xmloff/source/chart/SchXMLChartContext.hxx index 649c9b6cc387..11b69987ac93 100644 --- a/xmloff/source/chart/SchXMLChartContext.hxx +++ b/xmloff/source/chart/SchXMLChartContext.hxx @@ -104,6 +104,8 @@ private: OUString msCategoriesAddress; OUString msChartAddress; + OUString msDataPilotSource; + SeriesDefaultsAndStyles maSeriesDefaultsAndStyles; tSchXMLLSequencesPerIndex maLSequencesPerIndex; diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx index 9b8c205fa038..de3e32c7cd58 100644 --- a/xmloff/source/chart/SchXMLExport.cxx +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -90,6 +90,7 @@ #include <com/sun/star/chart2/data/XDataReceiver.hpp> #include <com/sun/star/chart2/data/XDataProvider.hpp> #include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> #include <com/sun/star/chart2/data/XTextualDataSequence.hpp> #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp> @@ -1213,6 +1214,13 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); } + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xNewDoc->getDataProvider(), uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName(); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, sPivotTableName); + } + OUString sChartType( xDiagram->getDiagramType() ); // attributes diff --git a/xmloff/source/chart/SchXMLImport.cxx b/xmloff/source/chart/SchXMLImport.cxx index 5d33fc69301b..10d8fc105b39 100644 --- a/xmloff/source/chart/SchXMLImport.cxx +++ b/xmloff/source/chart/SchXMLImport.cxx @@ -249,6 +249,7 @@ const SvXMLTokenMap& SchXMLImportHelper::GetChartAttrTokenMap() { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_CHART_STYLE_NAME }, { XML_NAMESPACE_CHART, XML_COLUMN_MAPPING, XML_TOK_CHART_COL_MAPPING }, { XML_NAMESPACE_CHART, XML_ROW_MAPPING, XML_TOK_CHART_ROW_MAPPING }, + { XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, XML_TOK_CHART_DATA_PILOT_SOURCE }, XML_TOKEN_MAP_END }; @@ -574,65 +575,37 @@ SvXMLImportContext* SchXMLImport::CreateStylesContext( return pStylesCtxt; } -void SAL_CALL SchXMLImport::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc ) +void SAL_CALL SchXMLImport::setTargetDocument(const uno::Reference<lang::XComponent>& xDoc) { - uno::Reference< chart2::XChartDocument > xOldDoc( GetModel(), uno::UNO_QUERY ); - if( xOldDoc.is() && xOldDoc->hasControllersLocked() ) + uno::Reference<chart2::XChartDocument> xOldDoc(GetModel(), uno::UNO_QUERY); + if (xOldDoc.is() && xOldDoc->hasControllersLocked()) xOldDoc->unlockControllers(); - SvXMLImport::setTargetDocument( xDoc ); + SvXMLImport::setTargetDocument(xDoc); - //set data provider and number formatter - // try to get an XDataProvider and set it - // @todo: if we have our own data, we must not use the parent as data provider - uno::Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + uno::Reference<chart2::XChartDocument> xChartDoc(GetModel(), uno::UNO_QUERY); - if( xChartDoc.is() ) + if (xChartDoc.is()) try { - //prevent rebuild of view during load ( necesarry especially if loaded not via load api, which is the case for example if binary files are loaded ) + // prevent rebuild of view during load (necesarry especially if loaded not + // via load api, which is the case for example if binary files are loaded) xChartDoc->lockControllers(); - uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY ); - uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY ); - if( xChild.is() && xDataReceiver.is()) + uno::Reference<container::XChild> xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference<chart2::data::XDataReceiver> xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) { - bool bHasOwnData = true; - - Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY ); - if( xFact.is() ) + Reference<lang::XMultiServiceFactory> xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) { //if the parent has a number formatter we will use the numberformatter of the parent - Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xFact, uno::UNO_QUERY ); - xDataReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier ); - - if ( !xChartDoc->getDataProvider().is() ) - { - const OUString aDataProviderServiceName( "com.sun.star.chart2.data.DataProvider"); - const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames()); - const OUString * pBegin = aServiceNames.getConstArray(); - const OUString * pEnd = pBegin + aServiceNames.getLength(); - if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd ) - { - Reference< chart2::data::XDataProvider > xProvider( - xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY ); - if( xProvider.is()) - { - xDataReceiver->attachDataProvider( xProvider ); - bHasOwnData = false; - } - } - } - else - bHasOwnData = false; + Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(xFact, uno::UNO_QUERY); + xDataReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier); } -// else we have no parent => we have our own data - - if( bHasOwnData && ! xChartDoc->hasInternalDataProvider() ) - xChartDoc->createInternalDataProvider( false ); } } - catch( const uno::Exception & rEx ) + catch (const uno::Exception & rEx) { OString aBStr(OUStringToOString(rEx.Message, RTL_TEXTENCODING_ASCII_US)); SAL_INFO("xmloff.chart", "SchXMLChartContext::StartElement(): Exception caught: " << aBStr); diff --git a/xmloff/source/chart/SchXMLSeries2Context.cxx b/xmloff/source/chart/SchXMLSeries2Context.cxx index 70eda5253150..82e3a7c67da7 100644 --- a/xmloff/source/chart/SchXMLSeries2Context.cxx +++ b/xmloff/source/chart/SchXMLSeries2Context.cxx @@ -30,6 +30,7 @@ #include <com/sun/star/chart2/XRegressionCurveContainer.hpp> #include <com/sun/star/chart2/data/XDataSink.hpp> #include <com/sun/star/chart2/data/XDataReceiver.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart/ChartAxisAssign.hpp> #include <com/sun/star/chart/ChartSymbolType.hpp> @@ -407,20 +408,31 @@ void SchXMLSeries2Context::StartElement( const uno::Reference< xml::sax::XAttrib uno::makeAny( true )); } + Reference<chart2::data::XDataProvider> xDataProvider(mxNewDoc->getDataProvider()); + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + + Reference<chart2::data::XDataSequence> xSequenceValues; + // values - Reference< chart2::data::XDataSequence > xSeq; - if( bHasRange && !m_aSeriesRange.isEmpty() ) - xSeq = SchXMLTools::CreateDataSequence( m_aSeriesRange, mxNewDoc ); + if (xPivotTableDataProvider.is()) // is pivot chart + { + xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex)); + } + else + { + if (bHasRange && !m_aSeriesRange.isEmpty()) + xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc); + } - Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY ); - if( xSeqProp.is()) + Reference<beans::XPropertySet> xSeqProp(xSequenceValues, uno::UNO_QUERY); + if (xSeqProp.is()) { OUString aMainRole("values-y"); - if ( maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType" ) + if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType") aMainRole = "values-size"; - xSeqProp->setPropertyValue("Role", uno::makeAny( aMainRole )); + xSeqProp->setPropertyValue("Role", uno::makeAny(aMainRole)); } - xLabeledSeq->setValues( xSeq ); + xLabeledSeq->setValues(xSequenceValues); // register for setting local data if external data provider is not present maPostponedSequences.insert( @@ -428,18 +440,24 @@ void SchXMLSeries2Context::StartElement( const uno::Reference< xml::sax::XAttrib tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq )); // label - if( !aSeriesLabelRange.isEmpty() ) + Reference<chart2::data::XDataSequence> xSequenceLabel; + + if (xPivotTableDataProvider.is()) { - Reference< chart2::data::XDataSequence > xLabelSequence = - SchXMLTools::CreateDataSequence( aSeriesLabelRange, mxNewDoc ); - xLabeledSeq->setLabel( xLabelSequence ); + xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex)); } - else if( !aSeriesLabelString.isEmpty() ) + else { - Reference< chart2::data::XDataSequence > xLabelSequence = - SchXMLTools::CreateDataSequenceWithoutConvert( aSeriesLabelString, mxNewDoc ); - xLabeledSeq->setLabel( xLabelSequence ); + if (!aSeriesLabelRange.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc)); + } + else if (!aSeriesLabelString.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc)); + } } + xLabeledSeq->setLabel(xSequenceLabel); // Note: Even if we have no label, we have to register the label // for creation, because internal data always has labels. If diff --git a/xmloff/source/chart/SchXMLTools.cxx b/xmloff/source/chart/SchXMLTools.cxx index 31c1ac161b1a..f00ce12d94f3 100644 --- a/xmloff/source/chart/SchXMLTools.cxx +++ b/xmloff/source/chart/SchXMLTools.cxx @@ -36,6 +36,7 @@ #include <com/sun/star/chart2/data/XDataProvider.hpp> #include <com/sun/star/chart2/data/XDataReceiver.hpp> #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> #include <com/sun/star/chart2/XRegressionCurveContainer.hpp> @@ -488,11 +489,21 @@ void CreateCategories( bRangeConverted = true; } } - Reference< chart2::data::XDataSequence > xSeq( - xDataProvider->createDataSequenceByRangeRepresentation( aConvertedRange )); - xLabeledSeq->setValues( xSeq ); - if( bRangeConverted ) - setXMLRangePropertyAtDataSequence( xSeq, rRangeAddress ); + + Reference<chart2::data::XDataSequence> xSequence; + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + xSequence.set(xPivotTableDataProvider->createDataSequenceOfCategories()); + } + else + { + xSequence.set(xDataProvider->createDataSequenceByRangeRepresentation(aConvertedRange)); + if (bRangeConverted) + setXMLRangePropertyAtDataSequence(xSequence, rRangeAddress); + } + xLabeledSeq->setValues(xSequence); + } catch( const lang::IllegalArgumentException & ex ) { diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 5ee0ce8dfa84..166aa91b0a42 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -549,6 +549,7 @@ namespace xmloff { namespace token { TOKEN( "data-label-number", XML_DATA_LABEL_NUMBER ), TOKEN( "data-label-symbol", XML_DATA_LABEL_SYMBOL ), TOKEN( "data-label-text", XML_DATA_LABEL_TEXT ), + TOKEN( "data-pilot-source", XML_DATA_PILOT_SOURCE ), TOKEN( "data-pilot-field", XML_DATA_PILOT_FIELD ), TOKEN( "data-pilot-grand-total", XML_DATA_PILOT_GRAND_TOTAL ), TOKEN( "data-pilot-level", XML_DATA_PILOT_LEVEL ), diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index e8878d8ec6c1..70386737e4ed 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -471,6 +471,7 @@ data-cell-range-address data-label-number data-label-symbol data-label-text +data-pilot-source data-pilot-field data-pilot-grand-total data-pilot-level @@ -3050,4 +3051,4 @@ max-numerator-digits zeros-numerator-digits zeros-denominator-digits integer-fraction-delimiter -TOKEN_END_DUMMY
\ No newline at end of file +TOKEN_END_DUMMY |