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>
diff --git a/chart2/CppunitTest_chart2_pivot_chart_test.mk b/chart2/CppunitTest_chart2_pivot_chart_test.mk
new file mode 100644
index 0000000..418db1a
--- /dev/null
+++ b/chart2/CppunitTest_chart2_pivot_chart_test.mk
@@ -0,0 +1,131 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#*************************************************************************
#
# 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/.
#
#*************************************************************************

$(eval $(call gb_CppunitTest_CppunitTest,chart2_pivot_chart_test))

$(eval $(call gb_CppunitTest_use_externals,chart2_pivot_chart_test, \
	boost_headers \
	libxml2 \
))

$(eval $(call gb_CppunitTest_add_exception_objects,chart2_pivot_chart_test, \
    chart2/qa/extras/PivotChartTest \
))

$(eval $(call gb_CppunitTest_use_libraries,chart2_pivot_chart_test, \
    basegfx \
    comphelper \
    cppu \
    cppuhelper \
    drawinglayer \
    editeng \
    for \
    forui \
    i18nlangtag \
    msfilter \
    vcl \
    oox \
    sal \
    salhelper \
    sax \
    sb \
    sc \
    sw \
    sd \
    sfx \
    sot \
    svl \
    svt \
    svx \
    svxcore \
    test \
    tl \
    tk \
    ucbhelper \
    unotest \
    utl \
    vbahelper \
    xo \
    sw \
    $(gb_UWINAPI) \
))

$(eval $(call gb_CppunitTest_set_include,chart2_pivot_chart_test,\
    -I$(SRCDIR)/chart2/inc \
    $$(INCLUDE) \
))

$(eval $(call gb_CppunitTest_use_sdk_api,chart2_pivot_chart_test))
$(eval $(call gb_CppunitTest_use_ure,chart2_pivot_chart_test))
$(eval $(call gb_CppunitTest_use_vcl,chart2_pivot_chart_test))

$(eval $(call gb_CppunitTest_use_components,chart2_pivot_chart_test,\
    basic/util/sb \
    animations/source/animcore/animcore \
    chart2/source/controller/chartcontroller \
    chart2/source/chartcore \
    comphelper/util/comphelp \
    configmgr/source/configmgr \
    dtrans/util/mcnttype \
    dbaccess/util/dba \
    embeddedobj/util/embobj \
    eventattacher/source/evtatt \
    filter/source/config/cache/filterconfig1 \
    filter/source/odfflatxml/odfflatxml \
    filter/source/storagefilterdetect/storagefd \
    filter/source/xmlfilteradaptor/xmlfa \
    filter/source/xmlfilterdetect/xmlfd \
    forms/util/frm \
    framework/util/fwk \
    i18npool/util/i18npool \
    linguistic/source/lng \
    oox/util/oox \
    package/source/xstor/xstor \
    package/util/package2 \
    sax/source/expatwrap/expwrap \
    sc/util/sc \
    sc/util/scd \
    sc/util/scfilt \
    sw/util/sw \
    sw/util/swd \
    sw/util/msword \
    sd/util/sd \
    sd/util/sdfilt \
    sd/util/sdd \
    $(call gb_Helper_optional,SCRIPTING, \
	    sc/util/vbaobj) \
    scaddins/source/analysis/analysis \
    scaddins/source/datefunc/date \
    scripting/source/basprov/basprov \
    scripting/util/scriptframe \
    sfx2/util/sfx \
    sot/util/sot \
    svl/source/fsstor/fsstorage \
    svl/util/svl \
	svtools/util/svt \
    svx/util/svx \
    svx/util/svxcore \
    toolkit/util/tk \
    ucb/source/core/ucb1 \
    ucb/source/ucp/file/ucpfile1 \
    ucb/source/ucp/tdoc/ucptdoc1 \
    unotools/util/utl \
    unoxml/source/rdf/unordf \
    unoxml/source/service/unoxml \
    uui/util/uui \
    writerfilter/util/writerfilter \
    xmloff/util/xo \
    xmlscript/util/xmlscript \
))

$(eval $(call gb_CppunitTest_use_configuration,chart2_pivot_chart_test))

# vim: set noet sw=4 ts=4:
diff --git a/chart2/Module_chart2.mk b/chart2/Module_chart2.mk
index f39140d..3273055d 100644
--- a/chart2/Module_chart2.mk
+++ b/chart2/Module_chart2.mk
@@ -34,6 +34,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,chart2,\
    CppunitTest_chart2_import \
    CppunitTest_chart2_trendcalculators \
    CppunitTest_chart2_dump \
    CppunitTest_chart2_pivot_chart_test \
))

ifeq ($(ENABLE_CHART_TESTS),TRUE)
diff --git a/chart2/inc/ChartModel.hxx b/chart2/inc/ChartModel.hxx
index 29b764b..63bd126 100644
--- a/chart2/inc/ChartModel.hxx
+++ b/chart2/inc/ChartModel.hxx
@@ -45,6 +45,7 @@
#include <com/sun/star/chart2/XChartTypeTemplate.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/qa/XDumper.hpp>
#include <com/sun/star/awt/XRequestCallback.hpp>

// public API
#include <com/sun/star/chart2/data/XDataProvider.hpp>
@@ -143,7 +144,7 @@ private:
    css::awt::Size                                     m_aVisualAreaSize;
    css::uno::Reference< css::frame::XModel >          m_xParent;
    css::uno::Reference< css::chart2::data::XRangeHighlighter > m_xRangeHighlighter;
    css::uno::Reference<css::chart2::data::XPopupRequest> m_xPopupRequest;
    css::uno::Reference<css::awt::XRequestCallback>    m_xPopupRequest;
    std::vector< GraphicObject >                            m_aGraphicObjectVector;

    css::uno::Reference< css::chart2::data::XDataProvider >   m_xDataProvider;
@@ -383,7 +384,7 @@ public:
    virtual void SAL_CALL attachNumberFormatsSupplier( const css::uno::Reference<
        css::util::XNumberFormatsSupplier >& xSupplier ) override;
    virtual css::uno::Reference< css::chart2::data::XRangeHighlighter > SAL_CALL getRangeHighlighter() override;
    virtual css::uno::Reference< css::chart2::data::XPopupRequest > SAL_CALL getPopupRequest() override;
    virtual css::uno::Reference<css::awt::XRequestCallback> SAL_CALL getPopupRequest() override;

    // ____ XTitled ____
    virtual css::uno::Reference< css::chart2::XTitle > SAL_CALL getTitleObject() override;
@@ -469,6 +470,10 @@ public:

    void setTimeBasedRange(sal_Int32 nStart, sal_Int32 nEnd);

    bool isDataFromSpreadsheet();

    bool isDataFromPivotTable();

#if HAVE_FEATURE_OPENGL
    OpenGLWindow* getOpenGLWindow() { return mpOpenGLWindow;}
#endif
diff --git a/chart2/qa/extras/PivotChartTest.cxx b/chart2/qa/extras/PivotChartTest.cxx
new file mode 100644
index 0000000..8d1c11d
--- /dev/null
+++ b/chart2/qa/extras/PivotChartTest.cxx
@@ -0,0 +1,298 @@
/* -*- 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/.
 */

#include "charttest.hxx"

#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
#include <com/sun/star/sheet/XDataPilotTable.hpp>
#include <com/sun/star/sheet/XDataPilotDescriptor.hpp>
#include <com/sun/star/sheet/XDataPilotTables.hpp>
#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp>
#include <com/sun/star/sheet/XSpreadsheet.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/sheet/XSpreadsheets.hpp>
#include <com/sun/star/table/XTablePivotChart.hpp>
#include <com/sun/star/table/XTablePivotCharts.hpp>
#include <com/sun/star/table/XTablePivotChartsSupplier.hpp>

#include <rtl/strbuf.hxx>

#include <algorithm>

class PivotChartTest : public ChartTest
{
public:
    PivotChartTest() : ChartTest()
    {}

    void testRoundtrip();
    void testChangePivotTable();

    CPPUNIT_TEST_SUITE(PivotChartTest);
    CPPUNIT_TEST(testRoundtrip);
    CPPUNIT_TEST(testChangePivotTable);
    CPPUNIT_TEST_SUITE_END();
};

namespace
{

void lclModifyOrientation(uno::Reference<sheet::XDataPilotDescriptor> const & xDescriptor,
                          OUString const & sFieldName,
                          sheet::DataPilotFieldOrientation eOrientation)
{
    uno::Reference<container::XIndexAccess> xPilotIndexAccess(xDescriptor->getDataPilotFields(), UNO_QUERY_THROW);
    sal_Int32 nCount = xPilotIndexAccess->getCount();
    for (sal_Int32 i = 0; i < nCount; ++i)
    {
        uno::Reference<container::XNamed> xNamed(xPilotIndexAccess->getByIndex(i), UNO_QUERY_THROW);
        OUString aName = xNamed->getName();
        uno::Reference<beans::XPropertySet> xPropSet(xNamed, UNO_QUERY_THROW);
        if (aName == sFieldName)
            xPropSet->setPropertyValue("Orientation", uno::makeAny(eOrientation));
    }
}

bool lclCheckSequence(std::vector<double> const & reference,
                      uno::Sequence<uno::Any> const & values,
                      double delta)
{
    if (reference.size() != size_t(values.getLength()))
    {
        printf ("Sequence size differs - reference is %ld but actual is %ld\n",
                reference.size(), size_t(values.getLength()));
        return false;
    }

    for (size_t i = 0; i < reference.size(); ++i)
    {
        double value = values[i].get<double>();

        if (std::fabs(reference[i] - value) > delta)
        {
            printf ("Value %f is not the same as reference %f (delta %f)\n", value, reference[i], delta);
            return false;
        }
    }
    return true;
}

OUString lclGetLabel(Reference<chart2::XChartDocument> const & xChartDoc, sal_Int32 nSeriesIndex)
{
    Reference<chart2::data::XDataSequence> xLabelDataSequence = getLabelDataSequenceFromDoc(xChartDoc, nSeriesIndex);
    return xLabelDataSequence->getData()[0].get<OUString>();
}

uno::Reference<sheet::XDataPilotTable> lclGetPivotTableByName(sal_Int32 nIndex, OUString const & sPivotTableName,
                                                           uno::Reference<lang::XComponent> const & xComponent)
{
    uno::Reference<sheet::XSpreadsheetDocument> xDoc(xComponent, UNO_QUERY_THROW);
    uno::Reference<container::XIndexAccess> xSheetIndexAccess(xDoc->getSheets(), UNO_QUERY_THROW);
    uno::Any aAny = xSheetIndexAccess->getByIndex(nIndex);
    uno::Reference<sheet::XSpreadsheet> xSheet;
    CPPUNIT_ASSERT(aAny >>= xSheet);
    uno::Reference<sheet::XDataPilotTablesSupplier> xDataPilotTablesSupplier(xSheet, uno::UNO_QUERY_THROW);
    uno::Reference<sheet::XDataPilotTables> xDataPilotTables = xDataPilotTablesSupplier->getDataPilotTables();
    return uno::Reference<sheet::XDataPilotTable>(xDataPilotTables->getByName(sPivotTableName), UNO_QUERY_THROW);
}

} // end anonymous namespace

void PivotChartTest::testRoundtrip()
{
    uno::Sequence<uno::Any> xSequence;
    Reference<chart2::XChartDocument> xChartDoc;

    std::vector<double> aReference1 { 10162.033139, 16614.523063, 27944.146101 };
    OUString aExpectedLabel1("Exp.");

    std::vector<double> aReference2 { 101879.458079, 178636.929704, 314626.484864 };
    OUString aExpectedLabel2("Rev.");

    load("/chart2/qa/extras/data/ods/", "PivotChartRoundTrip.ods");

    xChartDoc = getPivotChartDocFromSheet(1, mxComponent);
    CPPUNIT_ASSERT(xChartDoc.is());

    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), getNumberOfDataSeries(xChartDoc));

    // Check the data series
    {
        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 0)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference1, xSequence, 1E-4));
        CPPUNIT_ASSERT_EQUAL(aExpectedLabel1, lclGetLabel(xChartDoc, 0));
    }
    {
        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 1)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference2, xSequence, 1E-4));
        CPPUNIT_ASSERT_EQUAL(aExpectedLabel2, lclGetLabel(xChartDoc, 1));
    }

    // Modify the pivot table
    {
        uno::Reference<sheet::XDataPilotTable> xDataPilotTable = lclGetPivotTableByName(1, "DataPilot1", mxComponent);
        uno::Reference<sheet::XDataPilotDescriptor> xDataPilotDescriptor(xDataPilotTable, UNO_QUERY_THROW);

        lclModifyOrientation(xDataPilotDescriptor, "Exp.", sheet::DataPilotFieldOrientation_HIDDEN);
    }

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), getNumberOfDataSeries(xChartDoc));

    // Check again the data series
    {
        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 0)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference2, xSequence, 1E-4));
        CPPUNIT_ASSERT_EQUAL(OUString(""), lclGetLabel(xChartDoc, 0));
    }

    reload("calc8");

    xChartDoc = getPivotChartDocFromSheet(1, mxComponent);
    CPPUNIT_ASSERT(xChartDoc.is());

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), getNumberOfDataSeries(xChartDoc));

    // Check again the data series
    {
        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 0)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference2, xSequence, 1E-4));
        CPPUNIT_ASSERT_EQUAL(OUString(""), lclGetLabel(xChartDoc, 0));
    }
}

void PivotChartTest::testChangePivotTable()
{
    uno::Sequence<uno::Any> xSequence;
    Reference<chart2::XChartDocument> xChartDoc;

    load("/chart2/qa/extras/data/ods/", "PivotTableExample.ods");

    // Check that we don't have any pivot chart in the document
    uno::Reference<table::XTablePivotCharts> xTablePivotCharts = getTablePivotChartsFromSheet(1, mxComponent);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTablePivotCharts, UNO_QUERY_THROW);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xIndexAccess->getCount());

    // Create a new pivot chart
    xTablePivotCharts->addNewByName("Chart", awt::Rectangle{0, 0, 9000, 9000}, "DataPilot1");
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    // Get the pivot chart document so we ca access its data
    xChartDoc.set(getPivotChartDocFromSheet(xTablePivotCharts, 0));

    CPPUNIT_ASSERT(xChartDoc.is());

    // Check first data series
    {
        std::vector<double> aReference { 10162.033139, 16614.523063, 27944.146101 };
        OUString aExpectedLabel("Exp.");

        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 0)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-4));

        CPPUNIT_ASSERT_EQUAL(aExpectedLabel, lclGetLabel(xChartDoc, 0));
    }

    // Check second data series
    {
        std::vector<double> aReference { 101879.458079, 178636.929704, 314626.484864 };
        OUString aExpectedLabel("Rev.");

        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 1)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-4));

        CPPUNIT_ASSERT_EQUAL(aExpectedLabel, lclGetLabel(xChartDoc, 1));
    }

    // Modify the pivot table
    {
        uno::Reference<sheet::XDataPilotTable> xDataPilotTable = lclGetPivotTableByName(1, "DataPilot1", mxComponent);
        uno::Reference<sheet::XDataPilotDescriptor> xDataPilotDescriptor(xDataPilotTable, UNO_QUERY_THROW);

        lclModifyOrientation(xDataPilotDescriptor, "Service Month", sheet::DataPilotFieldOrientation_ROW);
        lclModifyOrientation(xDataPilotDescriptor, "Group Segment", sheet::DataPilotFieldOrientation_COLUMN);
        lclModifyOrientation(xDataPilotDescriptor, "Rev.", sheet::DataPilotFieldOrientation_HIDDEN);
    }

    // Check the pivot chart again as we expect it has been updated when we updated the pivot table

    CPPUNIT_ASSERT(xChartDoc.is());

    // Check the first data series
    {
        std::vector<double> aReference { 2855.559, 1780.326, 2208.713, 2130.064, 1187.371 };
        OUString aExpectedLabel("Big");

        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 0)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-3));

        CPPUNIT_ASSERT_EQUAL(aExpectedLabel, lclGetLabel(xChartDoc, 0));
    }

    // Check the second data series
    {
        std::vector<double> aReference { 4098.908, 2527.286, 4299.716, 2362.225, 3326.389 };
        OUString aExpectedLabel("Medium");

        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 1)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-3));

        CPPUNIT_ASSERT_EQUAL(aExpectedLabel, lclGetLabel(xChartDoc, 1));
    }

    // Check the third data series
    {
        std::vector<double> aReference { 4926.303, 5684.060, 4201.398, 7290.795, 5841.591 };
        OUString aExpectedLabel("Small");

        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 2)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-3));

        CPPUNIT_ASSERT_EQUAL(aExpectedLabel, lclGetLabel(xChartDoc, 2));
    }

    // Modify the pivot table
    {
        uno::Reference<sheet::XDataPilotTable> xDataPilotTable = lclGetPivotTableByName(1, "DataPilot1", mxComponent);
        uno::Reference<sheet::XDataPilotDescriptor> xDataPilotDescriptor(xDataPilotTable, UNO_QUERY_THROW);

        lclModifyOrientation(xDataPilotDescriptor, "Service Month", sheet::DataPilotFieldOrientation_HIDDEN);
    }

    // Check the pivot chart again as we expect it has been updated when we updated the pivot table

    CPPUNIT_ASSERT(xChartDoc.is());

    // Check the first data series
    {
        std::vector<double> aReference { 10162.033139 };
        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 0)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-3));
        CPPUNIT_ASSERT_EQUAL(OUString("Big"), lclGetLabel(xChartDoc, 0));
    }
    // Check the second data series
    {
        std::vector<double> aReference { 16614.523063 };
        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 1)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-3));
        CPPUNIT_ASSERT_EQUAL(OUString("Medium"), lclGetLabel(xChartDoc, 1));
    }
    // Check the third data series
    {
        std::vector<double> aReference { 27944.146101 };
        xSequence = getDataSequenceFromDocByRole(xChartDoc, "values-y", 2)->getData();
        CPPUNIT_ASSERT(lclCheckSequence(aReference, xSequence, 1E-3));
        CPPUNIT_ASSERT_EQUAL(OUString("Small"), lclGetLabel(xChartDoc, 2));
    }
}

CPPUNIT_TEST_SUITE_REGISTRATION(PivotChartTest);

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/qa/extras/charttest.hxx b/chart2/qa/extras/charttest.hxx
index 1d2f4af..b75dac6 100644
--- a/chart2/qa/extras/charttest.hxx
+++ b/chart2/qa/extras/charttest.hxx
@@ -24,6 +24,9 @@
#include <com/sun/star/table/XTableChartsSupplier.hpp>
#include <com/sun/star/table/XTableCharts.hpp>
#include <com/sun/star/table/XTableChart.hpp>
#include <com/sun/star/table/XTablePivotChartsSupplier.hpp>
#include <com/sun/star/table/XTablePivotCharts.hpp>
#include <com/sun/star/table/XTablePivotChart.hpp>
#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/frame/XStorable.hpp>
@@ -213,6 +216,64 @@ Reference< chart2::XChartDocument > getChartDocFromSheet( sal_Int32 nSheet, uno:
    return xChartDoc;
}

uno::Reference<table::XTablePivotCharts> getTablePivotChartsFromSheet(sal_Int32 nSheet, uno::Reference<lang::XComponent> const & xComponent)
{
    uno::Reference<sheet::XSpreadsheetDocument> xDoc(xComponent, UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xDoc.is());

    uno::Reference<container::XIndexAccess> xIA(xDoc->getSheets(), UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xIA.is());

    uno::Reference<table::XTablePivotChartsSupplier> xChartSupplier(xIA->getByIndex(nSheet), UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xChartSupplier.is());

    uno::Reference<table::XTablePivotCharts> xTablePivotCharts = xChartSupplier->getPivotCharts();
    CPPUNIT_ASSERT(xTablePivotCharts.is());

    return xTablePivotCharts;
}

Reference<lang::XComponent> getPivotChartCompFromSheet(sal_Int32 nSheet, uno::Reference<lang::XComponent> const & xComponent)
{
    uno::Reference<table::XTablePivotCharts> xTablePivotCharts = getTablePivotChartsFromSheet(nSheet, xComponent);

    uno::Reference<container::XIndexAccess> xIACharts(xTablePivotCharts, UNO_QUERY_THROW);
    uno::Reference<table::XTablePivotChart> xTablePivotChart(xIACharts->getByIndex(0), UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xTablePivotChart.is());

    uno::Reference<document::XEmbeddedObjectSupplier> xEmbObjectSupplier(xTablePivotChart, UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xEmbObjectSupplier.is());

    uno::Reference<lang::XComponent> xChartComp(xEmbObjectSupplier->getEmbeddedObject(), UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xChartComp.is());

    return xChartComp;
}

Reference<chart2::XChartDocument> getPivotChartDocFromSheet(sal_Int32 nSheet, uno::Reference<lang::XComponent> const & xComponent)
{
    uno::Reference<chart2::XChartDocument> xChartDoc(getPivotChartCompFromSheet(nSheet, xComponent), UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xChartDoc.is());
    return xChartDoc;
}

Reference<chart2::XChartDocument> getPivotChartDocFromSheet(uno::Reference<table::XTablePivotCharts> const & xTablePivotCharts, sal_Int32 nIndex)
{
    uno::Reference<container::XIndexAccess> xIACharts(xTablePivotCharts, UNO_QUERY_THROW);
    uno::Reference<table::XTablePivotChart> xTablePivotChart(xIACharts->getByIndex(nIndex), UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xTablePivotChart.is());

    uno::Reference<document::XEmbeddedObjectSupplier> xEmbObjectSupplier(xTablePivotChart, UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xEmbObjectSupplier.is());

    uno::Reference<lang::XComponent> xChartComp(xEmbObjectSupplier->getEmbeddedObject(), UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xChartComp.is());

    uno::Reference<chart2::XChartDocument> xChartDoc(xChartComp, UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xChartDoc.is());
    return xChartDoc;
}

Reference< chart2::XChartType > getChartTypeFromDoc( Reference< chart2::XChartDocument > const & xChartDoc,
                                                                sal_Int32 nChartType, sal_Int32 nCooSys = 0 )
{
@@ -257,8 +318,20 @@ Reference<chart2::XAxis> getAxisFromDoc(
    return xAxis;
}

Reference< chart2::XDataSeries > getDataSeriesFromDoc( uno::Reference< chart2::XChartDocument > const & xChartDoc,
                                                                sal_Int32 nDataSeries, sal_Int32 nChartType = 0, sal_Int32 nCooSys = 0 )
sal_Int32 getNumberOfDataSeries(uno::Reference<chart2::XChartDocument> const & xChartDoc,
                                sal_Int32 nChartType = 0, sal_Int32 nCooSys = 0)
{
    Reference<chart2::XChartType> xChartType = getChartTypeFromDoc(xChartDoc, nChartType, nCooSys);
    Reference<chart2::XDataSeriesContainer> xDataSeriesContainer(xChartType, UNO_QUERY_THROW);
    CPPUNIT_ASSERT(xDataSeriesContainer.is());

    uno::Sequence<uno::Reference<chart2::XDataSeries>> xSeriesSequence(xDataSeriesContainer->getDataSeries());
    return xSeriesSequence.getLength();
}

Reference< chart2::XDataSeries > getDataSeriesFromDoc(uno::Reference<chart2::XChartDocument> 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 );
diff --git a/chart2/qa/extras/data/ods/PivotChartRoundTrip.ods b/chart2/qa/extras/data/ods/PivotChartRoundTrip.ods
new file mode 100644
index 0000000..c34521e
--- /dev/null
+++ b/chart2/qa/extras/data/ods/PivotChartRoundTrip.ods
Binary files differ
diff --git a/chart2/qa/extras/data/ods/PivotTableExample.ods b/chart2/qa/extras/data/ods/PivotTableExample.ods
new file mode 100644
index 0000000..bc8df81
--- /dev/null
+++ b/chart2/qa/extras/data/ods/PivotTableExample.ods
Binary files differ
diff --git a/chart2/source/controller/dialogs/DialogModel.hxx b/chart2/source/controller/dialogs/DialogModel.hxx
index 55251b1..722ce26 100644
--- a/chart2/source/controller/dialogs/DialogModel.hxx
+++ b/chart2/source/controller/dialogs/DialogModel.hxx
@@ -146,6 +146,8 @@ public:
    // relative ordering, to get e.g. x-values and y-values in the right order
    static sal_Int32 GetRoleIndexForSorting( const OUString & rInternalRoleString );

    ChartModel& getModel() const;

private:
    css::uno::Reference< css::chart2::XChartDocument >
        m_xChartDocument;
@@ -168,7 +170,6 @@ private:

    sal_Int32 countSeries() const;

    ChartModel& getModel() const;
    mutable DialogModelTimeBasedInfo maTimeBasedInfo;
};

diff --git a/chart2/source/controller/dialogs/dlg_CreationWizard.cxx b/chart2/source/controller/dialogs/dlg_CreationWizard.cxx
index 501272f..b4beb73 100644
--- a/chart2/source/controller/dialogs/dlg_CreationWizard.cxx
+++ b/chart2/source/controller/dialogs/dlg_CreationWizard.cxx
@@ -33,10 +33,10 @@
#define CHART_WIZARD_PAGEWIDTH  250
#define CHART_WIZARD_PAGEHEIGHT 170

using namespace css;

namespace chart
{
using namespace ::com::sun::star;

#define PATH_FULL   1
#define STATE_FIRST        0
#define STATE_CHARTTYPE    STATE_FIRST
@@ -45,41 +45,42 @@ using namespace ::com::sun::star;
#define STATE_OBJECTS      3
#define STATE_LAST         STATE_OBJECTS

CreationWizard::CreationWizard( vcl::Window* pParent, const uno::Reference< frame::XModel >& xChartModel
                               , const uno::Reference< uno::XComponentContext >& xContext )
                : svt::RoadmapWizard( pParent )
CreationWizard::CreationWizard(vcl::Window* pParent, const uno::Reference<frame::XModel>& xChartModel,
                               const uno::Reference<uno::XComponentContext>& xContext)
                : svt::RoadmapWizard(pParent)
                , m_xChartModel(xChartModel,uno::UNO_QUERY)
                , m_xCC( xContext )
                , m_xComponentContext(xContext)
                , m_pTemplateProvider(nullptr)
                , m_nLastState(STATE_LAST)
                , m_aTimerTriggeredControllerLock( xChartModel )
                , m_bCanTravel( true )
                , m_aTimerTriggeredControllerLock(xChartModel)
                , m_bCanTravel(true)
{
    m_pDialogModel.reset( new DialogModel( m_xChartModel, m_xCC ));
    defaultButton( WizardButtonFlags::FINISH );
    m_pDialogModel.reset(new DialogModel(m_xChartModel, m_xComponentContext));
    defaultButton(WizardButtonFlags::FINISH);

    this->setTitleBase(SCH_RESSTR(STR_DLG_CHART_WIZARD));

    declarePath( PATH_FULL
        , {STATE_CHARTTYPE
        , STATE_SIMPLE_RANGE
        , STATE_DATA_SERIES
        , STATE_OBJECTS}
    );
    this->SetRoadmapHelpId( HID_SCH_WIZARD_ROADMAP );
    this->SetRoadmapInteractive( true );
    Size aAdditionalRoadmapSize( LogicToPixel( Size( 85, 0 ), MapUnit::MapAppFont ) );
    WizardPath aPath = {
        STATE_CHARTTYPE,
        STATE_SIMPLE_RANGE,
        STATE_DATA_SERIES,
        STATE_OBJECTS
    };

    declarePath(PATH_FULL, aPath);

    this->SetRoadmapHelpId(HID_SCH_WIZARD_ROADMAP);
    this->SetRoadmapInteractive(true);

    Size aAdditionalRoadmapSize(LogicToPixel(Size(85, 0), MapUnit::MapAppFont));
    Size aSize(LogicToPixel(Size(CHART_WIZARD_PAGEWIDTH, CHART_WIZARD_PAGEHEIGHT), MapUnit::MapAppFont));
    aSize.Width() += aAdditionalRoadmapSize.Width();
    this->SetSizePixel( aSize );
    this->SetSizePixel(aSize);

    uno::Reference< chart2::XChartDocument > xChartDoc( m_xChartModel, uno::UNO_QUERY );
    bool bHasOwnData = (xChartDoc.is() && xChartDoc->hasInternalDataProvider());

    if( bHasOwnData )
    if (!m_pDialogModel->getModel().isDataFromSpreadsheet())
    {
        this->enableState( STATE_SIMPLE_RANGE, false );
        this->enableState( STATE_DATA_SERIES, false );
        enableState(STATE_SIMPLE_RANGE, false);
        enableState(STATE_DATA_SERIES, false);
    }

    // Call ActivatePage, to create and activate the first page
@@ -117,15 +118,17 @@ VclPtr<TabPage> CreationWizard::createPage(WizardState nState)
        break;
    case STATE_OBJECTS:
        {
        pRet  = VclPtr<TitlesAndObjectsTabPage>::Create(this,m_xChartModel,m_xCC);
        pRet  = VclPtr<TitlesAndObjectsTabPage>::Create(this,m_xChartModel, m_xComponentContext);
        m_aTimerTriggeredControllerLock.startTimer();
        }
        break;
    default:
        break;
    }
    if(pRet)
        pRet->SetText(OUString());//remove title of pages to not get them in the wizard title

    if (pRet)
        pRet->SetText(OUString()); //remove title of pages to not get them in the wizard title

    return pRet;
}

diff --git a/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx b/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx
index 47932bb..c1005f5 100644
--- a/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx
+++ b/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx
@@ -182,8 +182,13 @@ SdrObject* DrawViewWrapper::getHitObject( const Point& rPnt ) const

    if( pRet )
    {
        //ignore some special shapes
        // ignore some special shapes
        OUString aShapeName = pRet->GetName();

        // return right away if it is a field button
        if (aShapeName.startsWith("FieldButton"))
            return pRet;

        if( aShapeName.match("PlotAreaIncludingAxes") || aShapeName.match("PlotAreaExcludingAxes") )
        {
            pRet->SetMarkProtect( true );
diff --git a/chart2/source/controller/inc/ChartController.hxx b/chart2/source/controller/inc/ChartController.hxx
index ae579cf..d69a7a2 100644
--- a/chart2/source/controller/inc/ChartController.hxx
+++ b/chart2/source/controller/inc/ChartController.hxx
@@ -487,6 +487,8 @@ private:
    void executeDispatch_ToggleGridHorizontal();
    void executeDispatch_ToggleGridVertical();

    void sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle);

    void impl_ShapeControllerDispatch( const css::util::URL& rURL,
        const css::uno::Sequence< css::beans::PropertyValue >& rArgs );

diff --git a/chart2/source/controller/inc/dlg_CreationWizard.hxx b/chart2/source/controller/inc/dlg_CreationWizard.hxx
index fed0190..a1fed3c 100644
--- a/chart2/source/controller/inc/dlg_CreationWizard.hxx
+++ b/chart2/source/controller/inc/dlg_CreationWizard.hxx
@@ -24,57 +24,56 @@
#include "TabPageNotifiable.hxx"

#include <com/sun/star/chart2/XChartDocument.hpp>
#include <svtools/roadmapwizard.hxx>
#include <com/sun/star/uno/XComponentContext.hpp>

#include <svtools/roadmapwizard.hxx>

#include <memory>

namespace chart
{

class RangeChooserTabPage;
class DataSourceTabPage;
class DialogModel;
class ChartTypeTemplateProvider;

class CreationWizard : public svt::RoadmapWizard, public TabPageNotifiable
{
public:
    CreationWizard( vcl::Window* pParent,
        const css::uno::Reference< css::frame::XModel >& xChartModel
        , const css::uno::Reference< css::uno::XComponentContext >& xContext );
    CreationWizard(vcl::Window* pParent,
        const css::uno::Reference<css::frame::XModel>& xChartModel,
        const css::uno::Reference<css::uno::XComponentContext>& xContext);

    CreationWizard() = delete;
    virtual ~CreationWizard() override;

    // TabPageNotifiable
    virtual void setInvalidPage( TabPage * pTabPage ) override;
    virtual void setValidPage( TabPage * pTabPage ) override;
    virtual void setInvalidPage(TabPage * pTabPage) override;
    virtual void setValidPage(TabPage * pTabPage) override;

protected:
    virtual bool            leaveState( WizardState _nState ) override;
    virtual WizardState     determineNextState(WizardState nCurrentState) const override;
    virtual void            enterState(WizardState nState) override;
    virtual bool leaveState( WizardState _nState ) override;
    virtual WizardState determineNextState(WizardState nCurrentState) const override;
    virtual void enterState(WizardState nState) override;

    virtual OUString        getStateDisplayName( WizardState nState ) const override;
    virtual OUString getStateDisplayName(WizardState nState) const override;

private:
    virtual VclPtr<TabPage> createPage(WizardState nState) override;

    css::uno::Reference< css::chart2::XChartDocument >   m_xChartModel;
    css::uno::Reference< css::uno::XComponentContext>    m_xCC;
    ChartTypeTemplateProvider*   m_pTemplateProvider;
    css::uno::Reference<css::chart2::XChartDocument> m_xChartModel;
    css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
    ChartTypeTemplateProvider* m_pTemplateProvider;
    std::unique_ptr<DialogModel> m_pDialogModel;

    WizardState m_nLastState;

    TimerTriggeredControllerLock   m_aTimerTriggeredControllerLock;
    TimerTriggeredControllerLock m_aTimerTriggeredControllerLock;

//     RangeChooserTabPage * m_pRangeChooserTabPage;
//     DataSourceTabPage *   m_pDataSourceTabPage;
    bool                  m_bCanTravel;
    bool m_bCanTravel;
};

} //namespace chart

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_Window.cxx b/chart2/source/controller/main/ChartController_Window.cxx
index 11dd2d8..441e8da 100644
--- a/chart2/source/controller/main/ChartController_Window.cxx
+++ b/chart2/source/controller/main/ChartController_Window.cxx
@@ -45,18 +45,23 @@
#include "LegendHelper.hxx"
#include "servicenames_charttypes.hxx"
#include "DrawCommandDispatch.hxx"
#include "PopupRequest.hxx"

#include <com/sun/star/chart2/RelativePosition.hpp>
#include <com/sun/star/chart2/RelativeSize.hpp>
#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>

#include <com/sun/star/awt/PopupMenuDirection.hpp>
#include <com/sun/star/frame/DispatchHelper.hpp>
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#include <com/sun/star/frame/XPopupMenuController.hpp>
#include <com/sun/star/util/XUpdatable.hpp>
#include <com/sun/star/awt/Rectangle.hpp>

#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequence.hxx>

#include <toolkit/awt/vclxmenu.hxx>

@@ -556,7 +561,16 @@ void ChartController::execute_MouseButtonDown( const MouseEvent& rMEvt )
    if(!pChartWindow || !pDrawViewWrapper )
        return;

    Point   aMPos   = pChartWindow->PixelToLogic(rMEvt.GetPosPixel());
    Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel());

    // Check if button was clicked
    SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos);
    if (pObject)
    {
        OUString aCID = pObject->GetName();
        if (aCID.startsWith("FieldButton"))
            return; // Don't take any action if button was clicked
    }

    if ( MOUSE_LEFT == rMEvt.GetButtons() )
    {
@@ -722,7 +736,19 @@ void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt )
        if(!pChartWindow || !pDrawViewWrapper)
            return;

        Point   aMPos   = pChartWindow->PixelToLogic(rMEvt.GetPosPixel());
        Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel());

        // Check if button was clicked
        SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos);
        if (pObject)
        {
            OUString aCID = pObject->GetName();
            if (aCID.startsWith("FieldButton"))
            {
                sendPopupRequest(aCID, pObject->GetCurrentBoundRect());
                return;
            }
        }

        if(pDrawViewWrapper->IsTextEdit())
        {
@@ -1958,6 +1984,47 @@ css::uno::Reference<css::uno::XInterface> const & ChartController::getChartView(
    return m_xChartView;
}

void ChartController::sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle)
{
    ChartModel* pChartModel = dynamic_cast<ChartModel*>(m_aModel->getModel().get());
    if (!pChartModel)
        return;

    uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
    xPivotTableDataProvider.set(pChartModel->getDataProvider(), uno::UNO_QUERY);
    if (!xPivotTableDataProvider.is())
        return;

    OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName();

    PopupRequest* pPopupRequest = dynamic_cast<PopupRequest*>(pChartModel->getPopupRequest().get());
    if (!pPopupRequest)
        return;

    // Get dimension index from CID
    sal_Int32 nStartPos = rCID.lastIndexOf('.');
    nStartPos++;
    sal_Int32 nEndPos = rCID.getLength();
    OUString sDimensionIndex = rCID.copy(nStartPos, nEndPos - nStartPos);
    sal_Int32 nDimensionIndex = sDimensionIndex.toInt32();

    awt::Rectangle xRectangle {
        sal_Int32(aRectangle.Left()),
        sal_Int32(aRectangle.Top()),
        sal_Int32(aRectangle.GetWidth()),
        sal_Int32(aRectangle.GetHeight())
    };

    uno::Sequence<beans::PropertyValue> aCallbackData = comphelper::InitPropertySequence(
    {
        {"Rectangle",      uno::makeAny<awt::Rectangle>(xRectangle)},
        {"DimensionIndex", uno::makeAny<sal_Int32>(nDimensionIndex)},
        {"PivotTableName", uno::makeAny<OUString>(sPivotTableName)},
    });

    pPopupRequest->getCallback()->notify(uno::makeAny(aCallbackData));
}

} //namespace chart

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/inc/PopupRequest.hxx b/chart2/source/inc/PopupRequest.hxx
index e564003..fb98d3d 100644
--- a/chart2/source/inc/PopupRequest.hxx
+++ b/chart2/source/inc/PopupRequest.hxx
@@ -12,8 +12,8 @@

#include "MutexContainer.hxx"
#include <cppuhelper/compbase.hxx>
#include <com/sun/star/chart2/data/XPopupRequest.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/XRequestCallback.hpp>

namespace chart
{
@@ -21,16 +21,21 @@ namespace chart
namespace impl
{

typedef cppu::WeakComponentImplHelper<css::chart2::data::XPopupRequest> PopupRequest_Base;
typedef cppu::WeakComponentImplHelper<css::awt::XRequestCallback> PopupRequest_Base;

}

class PopupRequest : public MutexContainer, public impl::PopupRequest_Base
class OOO_DLLPUBLIC_CHARTTOOLS PopupRequest : public MutexContainer, public impl::PopupRequest_Base
{
public:
    explicit PopupRequest();
    virtual ~PopupRequest() override;

    css::uno::Reference<css::awt::XCallback> getCallback()
    {
        return m_xCallback;
    }

protected:
    // ____ XRequestCallback ____
    virtual void SAL_CALL addCallback(const css::uno::Reference< ::css::awt::XCallback >& xCallback,
diff --git a/chart2/source/model/main/ChartModel.cxx b/chart2/source/model/main/ChartModel.cxx
index 814bd31..579a9c3 100644
--- a/chart2/source/model/main/ChartModel.cxx
+++ b/chart2/source/model/main/ChartModel.cxx
@@ -38,6 +38,7 @@
#include <vcl/openglwin.hxx>

#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>

#include <comphelper/processfactory.hxx>
#include <cppuhelper/supportsservice.hxx>
@@ -63,6 +64,7 @@
#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/document/DocumentProperties.hpp>
#include <com/sun/star/chart2/XTimeBased.hpp>
#include <com/sun/star/util/XModifyBroadcaster.hpp>

#include <svl/zforlist.hxx>

@@ -744,7 +746,7 @@ Reference< chart2::data::XDataSource > ChartModel::impl_createDefaultData()
                xIni->initialize(aArgs);
            }
            //create data
            uno::Sequence< beans::PropertyValue > aArgs( 4 );
            uno::Sequence<beans::PropertyValue> aArgs(4);
            aArgs[0] = beans::PropertyValue(
                "CellRangeRepresentation", -1,
                uno::Any( OUString("all") ), beans::PropertyState_DIRECT_VALUE );
@@ -816,6 +818,12 @@ void SAL_CALL ChartModel::attachDataProvider( const uno::Reference< chart2::data
            }
        }

        uno::Reference<util::XModifyBroadcaster> xModifyBroadcaster(xDataProvider, uno::UNO_QUERY);
        if (xModifyBroadcaster.is())
        {
            xModifyBroadcaster->addModifyListener(this);
        }

        m_xDataProvider.set( xDataProvider );
        m_xInternalDataProvider.clear();

@@ -911,7 +919,7 @@ Reference< chart2::data::XRangeHighlighter > SAL_CALL ChartModel::getRangeHighli
    return m_xRangeHighlighter;
}

Reference<chart2::data::XPopupRequest> SAL_CALL ChartModel::getPopupRequest()
Reference<awt::XRequestCallback> SAL_CALL ChartModel::getPopupRequest()
{
    if (!m_xPopupRequest.is())
        m_xPopupRequest.set(new PopupRequest);
@@ -1348,6 +1356,17 @@ void ChartModel::update()
#endif
}

bool ChartModel::isDataFromSpreadsheet()
{
    return !isDataFromPivotTable() && !hasInternalDataProvider();
}

bool ChartModel::isDataFromPivotTable()
{
    uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(m_xDataProvider, uno::UNO_QUERY);
    return xPivotTableDataProvider.is();
}

}  // namespace chart

extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
diff --git a/chart2/source/model/main/ChartModel_Persistence.cxx b/chart2/source/model/main/ChartModel_Persistence.cxx
index c19aeaf..5858501 100644
--- a/chart2/source/model/main/ChartModel_Persistence.cxx
+++ b/chart2/source/model/main/ChartModel_Persistence.cxx
@@ -22,8 +22,10 @@
#include "macros.hxx"
#include "ChartViewHelper.hxx"
#include "ChartModelHelper.hxx"
#include "DataSourceHelper.hxx"
#include "AxisHelper.hxx"
#include "ThreeDHelper.hxx"
#include "DiagramHelper.hxx"

#include <com/sun/star/chart2/LegendPosition.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
@@ -44,11 +46,14 @@
#include <com/sun/star/io/XSeekable.hpp>
#include <com/sun/star/ucb/CommandFailedException.hpp>

#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>

#include <ucbhelper/content.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <vcl/cvtgrf.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/storagehelper.hxx>
#include <comphelper/sequence.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>

@@ -704,10 +709,35 @@ void SAL_CALL ChartModel::removeModifyListener(
}

// util::XModifyListener
void SAL_CALL ChartModel::modified( const lang::EventObject& )
void SAL_CALL ChartModel::modified( const lang::EventObject& rEvenObject)
{
    if( m_nInLoad == 0 )
        setModified( true );
    uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rEvenObject.Source, uno::UNO_QUERY);
    if (xPivotTableDataProvider.is())
    {
        lockControllers();
        uno::Reference<chart2::data::XDataProvider> xDataProvider(xPivotTableDataProvider, uno::UNO_QUERY);
        try
        {
            uno::Sequence<beans::PropertyValue> aArguments =
                DataSourceHelper::createArguments("PivotChart", uno::Sequence<sal_Int32>(), true, true, true);

            Reference<chart2::data::XDataSource> xDataSource(xDataProvider->createDataSource(aArguments));
            Reference<lang::XMultiServiceFactory> xFactory(getChartTypeManager(), uno::UNO_QUERY);
            Reference<chart2::XDiagram> xDiagram(getFirstDiagram());

            DiagramHelper::tTemplateWithServiceName aTemplateAndService = DiagramHelper::getTemplateForDiagram(xDiagram, xFactory);
            css::uno::Reference<css::chart2::XChartTypeTemplate> xChartTypeTemplate(aTemplateAndService.first);
            xChartTypeTemplate->changeDiagramData(xDiagram, xDataSource, aArguments);
        }
        catch (const uno::Exception & ex)
        {
            ASSERT_EXCEPTION(ex);
        }
        unlockControllers();
    }

    if (m_nInLoad == 0)
        setModified(true);
}

// lang::XEventListener (base of util::XModifyListener)
diff --git a/chart2/source/view/main/ChartView.cxx b/chart2/source/view/main/ChartView.cxx
index 2053ab0..6dccabf 100644
--- a/chart2/source/view/main/ChartView.cxx
+++ b/chart2/source/view/main/ChartView.cxx
@@ -90,6 +90,8 @@
#include <com/sun/star/chart2/XTitled.hpp>
#include <com/sun/star/chart2/RelativePosition.hpp>
#include <com/sun/star/chart2/RelativeSize.hpp>
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
#include <com/sun/star/chart2/data/PivotTableFieldEntry.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/GraphicExportFilter.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
@@ -114,6 +116,7 @@
#include <comphelper/classids.hxx>
#include "servicenames_charttypes.hxx"


#include <rtl/strbuf.hxx>
#include <rtl/ustring.hxx>

@@ -2490,78 +2493,63 @@ void lcl_createButtons(const uno::Reference< drawing::XShapes>& xPageShapes,
                       ChartModel& rModel,
                       awt::Rectangle& rRemainingSpace)
{
    uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY);
    if (!xPivotTableDataProvider.is())
        return;

    uno::Reference<beans::XPropertySet> xModelPage(rModel.getPageBackground());

// TODO: Get this from the PivotTable
    std::vector<OUString> aPageFields {
//        "Subdivision", "Subdivision2"
    };
    std::vector<OUString> aDataFields {
//        "Sum - Revenue", "Sum - Expenses"
    };
    std::vector<OUString> aColumnFields {
//        "Group Segment", "Group Segment 2"
    };

    awt::Size aSize(3000, 700); // size of the button

    long x = 0;
    int nCIDIndex = 0;

    if (!aPageFields.empty())
    if (xPivotTableDataProvider->getPageFields().hasElements())
    {
        x = 0;
        nCIDIndex = 0;

        for (OUString const & aPageField : aPageFields)
        for (css::chart2::data::PivotTableFieldEntry const & rPageFieldEntry : xPivotTableDataProvider->getPageFields())
        {
            std::unique_ptr<VButton> pButton(new VButton);
            pButton->init(xPageShapes, xShapeFactory);
            awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100);
            pButton->setLabel(aPageField);
            pButton->setCID("PageFieldButton." + OUString::number(nCIDIndex));
            pButton->setLabel(rPageFieldEntry.Name);
            pButton->setCID("FieldButton.Page." + OUString::number(rPageFieldEntry.DimensionIndex));
            pButton->createShapes(aNewPosition, aSize, xModelPage);
            x += aSize.Width + 100;
            nCIDIndex += 1;
        }
        rRemainingSpace.Y += (aSize.Height + 100 + 100);
        rRemainingSpace.Height -= (aSize.Height + 100 + 100);
    }

    if (!aDataFields.empty())
    if (xPivotTableDataProvider->getDataFields().hasElements())
    {
        x = 200;
        nCIDIndex = 0;
        for (OUString const & aDataField : aDataFields)
        for (css::chart2::data::PivotTableFieldEntry const & rDataFieldEntry : xPivotTableDataProvider->getDataFields())
        {
            std::unique_ptr<VButton> pButton(new VButton);
            pButton->init(xPageShapes, xShapeFactory);
            awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100);
            pButton->setLabel(aDataField);
            pButton->setCID("DataFieldButton." + OUString::number(nCIDIndex));
            pButton->setLabel(rDataFieldEntry.Name);
            pButton->setCID("FieldButton.Data." + OUString::number(rDataFieldEntry.DimensionIndex));
            pButton->createShapes(aNewPosition, aSize, xModelPage);
            x += aSize.Width + 100;
            nCIDIndex += 1;
        }
        rRemainingSpace.Y += (aSize.Height + 100 + 100);
        rRemainingSpace.Height -= (aSize.Height + 100 + 100);
    }

    if (!aColumnFields.empty())
    if (xPivotTableDataProvider->getRowFields().hasElements())
    {
        x = 200;
        nCIDIndex = 0;
        for (OUString const & aColumnField : aColumnFields)
        for (css::chart2::data::PivotTableFieldEntry const & rRowFieldEntry : xPivotTableDataProvider->getRowFields())
        {
            std::unique_ptr<VButton> pButton(new VButton);
            pButton->init(xPageShapes, xShapeFactory);
            awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100,
                                                 rRemainingSpace.Y + rRemainingSpace.Height - aSize.Height - 100);
            pButton->setLabel(aColumnField);
            pButton->setCID("ColumnFieldButton." + OUString::number(nCIDIndex));
            pButton->setLabel(rRowFieldEntry.Name);
            pButton->setCID("FieldButton.Row." + OUString::number(rRowFieldEntry.DimensionIndex));
            pButton->createShapes(aNewPosition, aSize, xModelPage);
            x += aSize.Width + 100;
            nCIDIndex += 1;
        }
        rRemainingSpace.Height -= (aSize.Height + 100 + 100);
    }
diff --git a/chart2/source/view/main/VLegend.cxx b/chart2/source/view/main/VLegend.cxx
index 698f7fc..e2d9b735c 100644
--- a/chart2/source/view/main/VLegend.cxx
+++ b/chart2/source/view/main/VLegend.cxx
@@ -37,9 +37,12 @@
#include <com/sun/star/chart/ChartLegendExpansion.hpp>
#include <com/sun/star/chart2/LegendPosition.hpp>
#include <com/sun/star/chart2/RelativePosition.hpp>
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
#include <com/sun/star/chart2/data/PivotTableFieldEntry.hpp>
#include <rtl/ustrbuf.hxx>
#include <svl/languageoptions.hxx>


#include <vector>
#include <algorithm>

@@ -766,33 +769,31 @@ std::vector<std::shared_ptr<VButton>> lcl_createButtons(
                       const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory,
                       ChartModel& rModel, long& nUsedHeight)
{
// TODO: get this info from the Pivot Table
    std::vector<OUString> aRowFields {
//        "Service Months"
    };

    std::vector<std::shared_ptr<VButton>> aButtons;

    if (aRowFields.empty())
    uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY);
    if (!xPivotTableDataProvider.is())
        return aButtons;

    if (!xPivotTableDataProvider->getColumnFields().hasElements())
        return aButtons;

    uno::Reference<beans::XPropertySet> xModelPage(rModel.getPageBackground());

    int nCIDIndex = 0;
    awt::Size aSize(2000, 700);

    for (OUString const & sRowField : aRowFields)
    int y = 100;
    for (chart2::data::PivotTableFieldEntry const & sColumnFieldEntry : xPivotTableDataProvider->getColumnFields())
    {
        std::shared_ptr<VButton> pButton(new VButton);
        aButtons.push_back(pButton);
        pButton->init(xLegendContainer, xShapeFactory);
        awt::Point aNewPosition = awt::Point(100, 100);
        pButton->setLabel(sRowField);
        pButton->setCID("RowFieldButton." + OUString::number(nCIDIndex));
        awt::Point aNewPosition = awt::Point(100, y);
        pButton->setLabel(sColumnFieldEntry.Name);
        pButton->setCID("FieldButton.Column." + OUString::number(sColumnFieldEntry.DimensionIndex));
        pButton->createShapes(aNewPosition, aSize, xModelPage);
        nCIDIndex += 1;
        y += aSize.Height + 100;;
    }
    nUsedHeight += aSize.Height + 100;
    nUsedHeight += y + 100;

    return aButtons;
}
diff --git a/include/xmloff/xmlnmspe.hxx b/include/xmloff/xmlnmspe.hxx
index ae588d2..7675b55 100644
--- a/include/xmloff/xmlnmspe.hxx
+++ b/include/xmloff/xmlnmspe.hxx
@@ -89,7 +89,6 @@ XML_NAMESPACE_EXT( LO,          42U )
// namespaces used in the technical preview (SO 5.2)
XML_OLD_NAMESPACE( FO,      0U )
XML_OLD_NAMESPACE( XLINK,   1U )

XML_OLD_NAMESPACE( OFFICE,  2U )
XML_OLD_NAMESPACE( STYLE,   3U )
XML_OLD_NAMESPACE( TEXT,    4U )
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 4430d29..9ab65ab 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -547,6 +547,7 @@ namespace xmloff { namespace token {
        XML_DATA_LABEL_NUMBER,
        XML_DATA_LABEL_SYMBOL,
        XML_DATA_LABEL_TEXT,
        XML_DATA_PILOT_SOURCE,
        XML_DATA_PILOT_FIELD,
        XML_DATA_PILOT_GRAND_TOTAL,
        XML_DATA_PILOT_LEVEL,
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 49602b9..ded4b70 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -88,6 +88,7 @@ $(eval $(call gb_UnoApi_add_idlfiles_nohdl,offapi,com/sun/star/chart2,\
$(eval $(call gb_UnoApi_add_idlfiles_nohdl,offapi,com/sun/star/chart2/data,\
	DatabaseDataProvider \
    LabeledDataSequence \
    PivotTableFieldEntry \
))
$(eval $(call gb_UnoApi_add_idlfiles_nohdl,offapi,com/sun/star/configuration,\
    ReadOnlyAccess \
@@ -658,7 +659,6 @@ $(eval $(call gb_UnoApi_add_idlfiles_noheader,offapi,com/sun/star/chart2/data,\
	DataSequence \
	DataSink \
	DataSource \
	PopupRequest \
	RangeHighlighter \
	RangeHighlightListener \
	TabularDataProviderArguments \
@@ -2058,7 +2058,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/chart2/data,\
	XLabeledDataSequence \
	XLabeledDataSequence2 \
	XNumericalDataSequence \
	XPopupRequest \
	XPivotTableDataProvider \
	XRangeHighlighter \
	XRangeXMLConversion \
	XSheetDataProvider \
@@ -3639,6 +3639,9 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/table,\
	XTableChart \
	XTableCharts \
	XTableChartsSupplier \
	XTablePivotChart \
	XTablePivotCharts \
	XTablePivotChartsSupplier \
	XTableColumns \
	XTableRows \
))
diff --git a/offapi/com/sun/star/chart2/data/XPopupRequest.idl b/offapi/com/sun/star/chart2/data/PivotTableFieldEntry.idl
similarity index 62%
rename from offapi/com/sun/star/chart2/data/XPopupRequest.idl
rename to offapi/com/sun/star/chart2/data/PivotTableFieldEntry.idl
index 0711678..4d8973f 100644
--- a/offapi/com/sun/star/chart2/data/XPopupRequest.idl
+++ b/offapi/com/sun/star/chart2/data/PivotTableFieldEntry.idl
@@ -7,11 +7,8 @@
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#ifndef com_sun_star_chart2_data_XPopupRequest_idl
#define com_sun_star_chart2_data_XPopupRequest_idl

#include <com/sun/star/uno/XInterface.idl>
#ifndef com_sun_star_chart2_data_PivotTableFieldEntry_idl
#define com_sun_star_chart2_data_PivotTableFieldEntry_idl

module com
{
@@ -25,17 +22,21 @@ module data
{

/**
    @since LibreOffice 5.4
 *
 * @since LibreOffice 5.4
 */
interface XPopupRequest : com::sun::star::awt::XRequestCallback
struct PivotTableFieldEntry
{
    string Name;

    long DimensionIndex;
};

} ; // data
} ; // chart2
} ; // com
} ; // sun
} ; // star
}; // data
}; // chart2
}; // com
}; // sun
}; // star

#endif

diff --git a/offapi/com/sun/star/chart2/data/PopupRequest.idl b/offapi/com/sun/star/chart2/data/PopupRequest.idl
deleted file mode 100644
index f83ccc0..0000000
--- a/offapi/com/sun/star/chart2/data/PopupRequest.idl
+++ /dev/null
@@ -1,44 +0,0 @@
/* -*- 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/.
 *
 */

#ifndef com_sun_star_chart2_data_PopupRequest_idl
#define com_sun_star_chart2_data_PopupRequest_idl

#include <com/sun/star/chart2/data/XPopupRequest.idl>

module com
{
module sun
{
module star
{
module chart2
{
module data
{

/** @since LibreOffice 5.4
 */
service PopupRequest
{
    /**
     */
    interface XPopupRequest;
};

} ; // data
} ; // chart2
} ; // com
} ; // sun
} ; // star

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/offapi/com/sun/star/chart2/data/XDataReceiver.idl b/offapi/com/sun/star/chart2/data/XDataReceiver.idl
index abfbc83..a7c853b 100644
--- a/offapi/com/sun/star/chart2/data/XDataReceiver.idl
+++ b/offapi/com/sun/star/chart2/data/XDataReceiver.idl
@@ -92,7 +92,7 @@ interface XDataReceiver : ::com::sun::star::uno::XInterface

        @since LibreOffice 5.4
    */
    XPopupRequest getPopupRequest();
    com::sun::star::awt::XRequestCallback getPopupRequest();
};

} ; // data
diff --git a/offapi/com/sun/star/chart2/data/XPivotTableDataProvider.idl b/offapi/com/sun/star/chart2/data/XPivotTableDataProvider.idl
new file mode 100644
index 0000000..731988b
--- /dev/null
+++ b/offapi/com/sun/star/chart2/data/XPivotTableDataProvider.idl
@@ -0,0 +1,90 @@
/* -*- 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/.
 */

#ifndef com_sun_star_chart2_data_XPivotTableDataProvider_idl
#define com_sun_star_chart2_data_XPivotTableDataProvider_idl

#include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/chart2/data/PivotTableFieldEntry.idl>

module com { module sun { module star { module chart2 { module data {

/**
 * Data provider specific for pivot chart data.
 *
 * @since LibreOffice 5.4
 */
interface XPivotTableDataProvider : com::sun::star::uno::XInterface
{
    /** names of column fields from the associated pivot table
     *
     * @since LibreOffice 5.4
     */
    sequence<com::sun::star::chart2::data::PivotTableFieldEntry> getColumnFields();

    /** names of row fields from the associated pivot table
     *
     * @since LibreOffice 5.4
     */
    sequence<com::sun::star::chart2::data::PivotTableFieldEntry> getRowFields();

    /** names of page fields from the associated pivot table
     *
     * @since LibreOffice 5.4
     */
    sequence<com::sun::star::chart2::data::PivotTableFieldEntry> getPageFields();

    /** names of data fields from the associated pivot table
     *
     * @since LibreOffice 5.4
     */
    sequence<com::sun::star::chart2::data::PivotTableFieldEntry> getDataFields();

    /** get the associated pivot table name
     *
     * @since LibreOffice 5.4
     */
    string getPivotTableName();

    /** set the associated pivot table name
     *
     * @since LibreOffice 5.4
     */
     void setPivotTableName([in] string sPivotTableName);

    /** creates a single data sequence of values for the given data series index.
     *
     *  @param nIndex
     *      index of the data series
     *
     *  @since LibreOffice 5.4
     */
    XDataSequence createDataSequenceOfValuesByIndex([in] long nIndex);

    /** creates a single data sequence of label(s) for the given data series index.
     *
     *  @param nIndex
     *      index of the data series
     *
     *  @since LibreOffice 5.4
     */
     XDataSequence createDataSequenceOfLabelsByIndex([in] long nIndex);

    /** creates a single data sequence of categories.
     *
     *  @since LibreOffice 5.4
     */
    XDataSequence createDataSequenceOfCategories();
};

};};};};};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/offapi/com/sun/star/table/XTablePivotChart.idl b/offapi/com/sun/star/table/XTablePivotChart.idl
new file mode 100644
index 0000000..b6c53d6
--- /dev/null
+++ b/offapi/com/sun/star/table/XTablePivotChart.idl
@@ -0,0 +1,36 @@
/* -*- 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/.
 */

#ifndef __com_sun_star_table_XTablePivotChart_idl__
#define __com_sun_star_table_XTablePivotChart_idl__

#include <com/sun/star/uno/XInterface.idl>

module com {  module sun {  module star {  module table {


/** provides access to the settings of a pivot chart object in a
    table or spreadsheet.

    @since LibreOffice 5.4
 */
interface XTablePivotChart: com::sun::star::uno::XInterface
{
    /** returns the pivot table name of the associated pivot table

        @since LibreOffice 5.4
    */
    string getPivotTableName();
};

}; }; }; };

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/offapi/com/sun/star/table/XTablePivotCharts.idl b/offapi/com/sun/star/table/XTablePivotCharts.idl
new file mode 100644
index 0000000..e16b74b
--- /dev/null
+++ b/offapi/com/sun/star/table/XTablePivotCharts.idl
@@ -0,0 +1,63 @@
/* -*- 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/.
 */

#ifndef __com_sun_star_table_XTablePivotCharts_idl__
#define __com_sun_star_table_XTablePivotCharts_idl__

#include <com/sun/star/container/XNameAccess.idl>
#include <com/sun/star/awt/Rectangle.idl>


module com {  module sun {  module star {  module table {


/** provides methods to access pivot charts via name and to insert
    and remove pivot charts.

    @since LibreOffice 5.4
 */
interface XTablePivotCharts: com::sun::star::container::XNameAccess
{

    /** creates a pivot chart and adds it to the collection.

        @param aName
            is the name of the chart. This name is used to reference the
            chart in the collection.

        @param aRect
            contains the rectangular location of the chart within the table
            (in 1/100th mm).

        @param aPivotTableName
            the name of the pivot table (data pilot) to associate the pivot chart with

        @since LibreOffice 5.4
     */
    void addNewByName(
            [in] string aName,
            [in] com::sun::star::awt::Rectangle aRect,
            [in] string aPivotTableName);


    /** removes a pivot chart from the collection.

        @param aName
            is the name of the chart to remove.

        @since LibreOffice 5.4
     */
    void removeByName([in] string aName);
};

}; }; }; };

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/offapi/com/sun/star/table/XTablePivotChartsSupplier.idl b/offapi/com/sun/star/table/XTablePivotChartsSupplier.idl
new file mode 100644
index 0000000..4401741
--- /dev/null
+++ b/offapi/com/sun/star/table/XTablePivotChartsSupplier.idl
@@ -0,0 +1,41 @@
/* -*- 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/.
 */

#ifndef __com_sun_star_table_XTablePivotChartsSupplier_idl__
#define __com_sun_star_table_XTablePivotChartsSupplier_idl__

#include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/table/XTablePivotCharts.idl>


module com {  module sun {  module star {  module table {


/** provides a method to access a collection of pivot charts in a table
    or spreadsheet.

    @since LibreOffice 5.4
 */
interface XTablePivotChartsSupplier: com::sun::star::uno::XInterface
{

    /** returns the collection of pivot charts.

        @since LibreOffice 5.4
     */
    com::sun::star::table::XTablePivotCharts getPivotCharts();

};


}; }; }; };

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 9068e50..0a888ee 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -573,6 +573,12 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
    sc/source/ui/unoobj/notesuno \
    sc/source/ui/unoobj/optuno \
    sc/source/ui/unoobj/pageuno \
    sc/source/ui/unoobj/PivotTableDataProvider \
    sc/source/ui/unoobj/PivotTableDataSource \
    sc/source/ui/unoobj/PivotTableDataSequence \
    sc/source/ui/unoobj/TablePivotCharts \
    sc/source/ui/unoobj/TablePivotChart \
    sc/source/ui/unoobj/ChartTools \
    sc/source/ui/unoobj/servuno \
    sc/source/ui/unoobj/shapeuno \
    sc/source/ui/unoobj/srchuno \
diff --git a/sc/inc/ChartTools.hxx b/sc/inc/ChartTools.hxx
new file mode 100644
index 0000000..dc9a5c5
--- /dev/null
+++ b/sc/inc/ChartTools.hxx
@@ -0,0 +1,50 @@
/* -*- 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/.
 *
 */

#ifndef INCLUDED_SC_INC_CHARTTOOLS_HXX
#define INCLUDED_SC_INC_CHARTTOOLS_HXX

#include <svx/svdoole2.hxx>
#include <svx/svditer.hxx>

#include "docsh.hxx"
#include "drwlayer.hxx"

namespace sc {
namespace tools {

enum class ChartSourceType
{
    CELL_RANGE,
    PIVOT_TABLE
};

class ChartIterator
{
private:
    std::unique_ptr<SdrObjListIter> m_pIterator;
    ChartSourceType m_eChartSourceType;
public:
    ChartIterator(ScDocShell* pDocShell, SCTAB nTab, ChartSourceType eChartSourceType);
    SdrOle2Obj* next();
};

SdrOle2Obj* findChartsByName(ScDocShell* pDocShell, SCTAB nTab,
                             OUString const & rName,
                             ChartSourceType eChartSourceType);

SdrOle2Obj* getChartByIndex(ScDocShell* pDocShell, SCTAB nTab,
                            long nIndex, ChartSourceType eChartSourceType);

}} // end sc::tools

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/PivotTableDataProvider.hxx b/sc/inc/PivotTableDataProvider.hxx
new file mode 100644
index 0000000..8135cba
--- /dev/null
+++ b/sc/inc/PivotTableDataProvider.hxx
@@ -0,0 +1,190 @@
/* -*- 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/.
 */

#ifndef INCLUDED_SC_INC_PIVOTTABLEDATAPROVIDER_HXX
#define INCLUDED_SC_INC_PIVOTTABLEDATAPROVIDER_HXX

#include "cellsuno.hxx"
#include "externalrefmgr.hxx"
#include "types.hxx"

#include <com/sun/star/chart2/data/XDataProvider.hpp>
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
#include <com/sun/star/chart2/data/XDataSource.hpp>
#include <com/sun/star/chart2/data/XDataSequence.hpp>
#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
#include <com/sun/star/chart2/data/PivotTableFieldEntry.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/util/XCloneable.hpp>
#include <com/sun/star/util/XModifyBroadcaster.hpp>

#include <svl/lstner.hxx>
#include <cppuhelper/implbase.hxx>
#include <rtl/ustring.hxx>
#include <svl/itemprop.hxx>

#include <memory>
#include <vector>

namespace sc
{

struct ValueAndFormat;

typedef cppu::WeakImplHelper<css::chart2::data::XDataProvider,
                             css::chart2::data::XPivotTableDataProvider,
                             css::beans::XPropertySet,
                             css::lang::XServiceInfo,
                             css::util::XModifyBroadcaster>
            PivotTableDataProvider_Base;

class PivotTableDataProvider : public PivotTableDataProvider_Base, public SfxListener
{
public:

    explicit PivotTableDataProvider(ScDocument* pDoc);
    virtual ~PivotTableDataProvider() override;
    virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;

    // XDataProvider
    virtual sal_Bool SAL_CALL
        createDataSourcePossible(const css::uno::Sequence<css::beans::PropertyValue>& aArguments) override;

    virtual css::uno::Reference<css::chart2::data::XDataSource> SAL_CALL
        createDataSource(const css::uno::Sequence<css::beans::PropertyValue>& aArguments) override;

    virtual css::uno::Sequence<css::beans::PropertyValue> SAL_CALL
        detectArguments(const css::uno::Reference<css::chart2::data::XDataSource>& xDataSource) override;

    virtual sal_Bool SAL_CALL
        createDataSequenceByRangeRepresentationPossible(const OUString& aRangeRepresentation) override;

    virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
            createDataSequenceByRangeRepresentation(const OUString& aRangeRepresentation) override;

    virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
        createDataSequenceByValueArray(const OUString& aRole, const OUString& aRangeRepresentation) override;

    virtual css::uno::Reference<css::sheet::XRangeSelection> SAL_CALL getRangeSelection() override;

    // XPivotTableDataProvider
    virtual css::uno::Sequence<css::chart2::data::PivotTableFieldEntry> SAL_CALL
        getColumnFields() override;
    virtual css::uno::Sequence<css::chart2::data::PivotTableFieldEntry> SAL_CALL
        getRowFields() override;
    virtual css::uno::Sequence<css::chart2::data::PivotTableFieldEntry> SAL_CALL
        getPageFields() override;
    virtual css::uno::Sequence<css::chart2::data::PivotTableFieldEntry> SAL_CALL
        getDataFields() override;

    virtual OUString SAL_CALL getPivotTableName() override;

    virtual void SAL_CALL setPivotTableName(const OUString& sPivotTableName) override;

    virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
        createDataSequenceOfValuesByIndex(sal_Int32 nIndex) override;
    virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
        createDataSequenceOfLabelsByIndex(sal_Int32 nIndex) override;
    virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
        createDataSequenceOfCategories() override;

    // XPropertySet
    virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;

    virtual void SAL_CALL
        setPropertyValue(const OUString& rPropertyName, const css::uno::Any& rValue) override;

    virtual css::uno::Any SAL_CALL
        getPropertyValue(const OUString& rPropertyName) override;

    virtual void SAL_CALL addPropertyChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference<css::beans::XPropertyChangeListener>& xListener) override;

    virtual void SAL_CALL removePropertyChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference<css::beans::XPropertyChangeListener>& rListener) override;

    virtual void SAL_CALL addVetoableChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference<css::beans::XVetoableChangeListener>& rListener) override;

    virtual void SAL_CALL removeVetoableChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference<css::beans::XVetoableChangeListener>& rListener) override;

    // XModifyBroadcaster
    virtual void SAL_CALL
        addModifyListener(const css::uno::Reference<css::util::XModifyListener>& aListener) override;

    virtual void SAL_CALL
        removeModifyListener(const css::uno::Reference<css::util::XModifyListener>& aListener) override;

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override;

    virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;

    virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;

private:

    css::uno::Reference<css::chart2::data::XDataSource>
        createValuesDataSource(OUString const & aRangeRepresentation);
    css::uno::Reference<css::chart2::data::XDataSource>
        createCategoriesDataSource(OUString const & aRangeRepresentation, bool bOrientationIsColumn);

    css::uno::Reference<css::chart2::data::XLabeledDataSequence> newLabeledDataSequence();

    void setLabeledDataSequenceValues(css::uno::Reference<css::chart2::data::XLabeledDataSequence> & xResult,
                                      OUString const & sRoleValues, OUString const & sIdValues,
                                      std::vector<ValueAndFormat> const & rValues);

    void setLabeledDataSequence(css::uno::Reference<css::chart2::data::XLabeledDataSequence> & xResult,
                                OUString const & sRoleValues, OUString const & sIdValues,
                                std::vector<ValueAndFormat> const & rValues,
                                OUString const & sRoleLabel,  OUString const & sIdLabel,
                                std::vector<ValueAndFormat> const & rLabel);

    void assignLabelsToDataSequence(css::uno::Reference<css::chart2::data::XDataSequence> & rDataSequence,
                                    size_t nIndex);

    void assignValuesToDataSequence(css::uno::Reference<css::chart2::data::XDataSequence> & rDataSequence,
                                    size_t nIndex);

    void collectPivotTableData();

    ScDocument*        m_pDocument;
    OUString           m_sPivotTableName;
    SfxItemPropertySet m_aPropSet;
    bool               m_bIncludeHiddenCells;

    std::vector<std::vector<ValueAndFormat>> m_aCategoriesColumnOrientation;
    std::vector<std::vector<ValueAndFormat>> m_aCategoriesRowOrientation;
    std::vector<std::vector<ValueAndFormat>> m_aLabels;
    std::vector<std::vector<ValueAndFormat>> m_aDataRowVector;

    std::vector<css::chart2::data::PivotTableFieldEntry> m_aColumnFields;
    std::vector<css::chart2::data::PivotTableFieldEntry> m_aRowFields;
    std::vector<css::chart2::data::PivotTableFieldEntry> m_aPageFields;
    std::vector<css::chart2::data::PivotTableFieldEntry> m_aDataFields;

    bool m_bNeedsUpdate;

    css::uno::Reference<css::uno::XComponentContext> m_xContext;

    std::vector<css::uno::Reference<css::util::XModifyListener>> m_aValueListeners;
};

}

#endif // INCLUDED_SC_INC_PIVOTTABLEDATAPROVIDER_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/PivotTableDataSequence.hxx b/sc/inc/PivotTableDataSequence.hxx
new file mode 100644
index 0000000..f5e508e
--- /dev/null
+++ b/sc/inc/PivotTableDataSequence.hxx
@@ -0,0 +1,170 @@
/* -*- 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/.
 */

#ifndef INCLUDED_SC_INC_PIVOTTABLEDATASEQUENCE_HXX
#define INCLUDED_SC_INC_PIVOTTABLEDATASEQUENCE_HXX

#include <com/sun/star/chart2/data/XDataProvider.hpp>
#include <com/sun/star/chart2/data/XDataSequence.hpp>
#include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
#include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
#include <com/sun/star/chart2/data/DataSequenceRole.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/util/XCloneable.hpp>
#include <com/sun/star/util/XModifyBroadcaster.hpp>

#include <com/sun/star/sheet/XDataPilotResults.hpp>

#include <svl/lstner.hxx>
#include <svl/itemprop.hxx>
#include <cppuhelper/implbase.hxx>
#include <rtl/math.hxx>

#include "unonames.hxx"
#include "document.hxx"

#include "dpsave.hxx"

namespace sc
{

typedef cppu::WeakImplHelper<css::chart2::data::XDataSequence,
                             css::chart2::data::XTextualDataSequence,
                             css::chart2::data::XNumericalDataSequence,
                             css::util::XCloneable,
                             css::util::XModifyBroadcaster,
                             css::beans::XPropertySet,
                             css::lang::XServiceInfo>
        PivotTableDataSequence_Base;

struct ValueAndFormat
{
    double m_fValue;
    OUString m_aString;
    bool m_bIsValue;
    sal_uInt32 m_nNumberFormat;

    explicit ValueAndFormat()
        : m_fValue(0.0)
        , m_aString()
        , m_bIsValue(true)
        , m_nNumberFormat(0)
    {
        rtl::math::setNan(&m_fValue);
    }

    explicit ValueAndFormat(double fValue, sal_uInt32 nNumberFormat)
        : m_fValue(fValue)
        , m_aString()
        , m_bIsValue(true)
        , m_nNumberFormat(nNumberFormat)
    {}

    explicit ValueAndFormat(OUString const & rString)
        : m_fValue(0.0)
        , m_aString(rString)
        , m_bIsValue(false)
        , m_nNumberFormat(0)
    {
        rtl::math::setNan(&m_fValue);
    }
};

class PivotTableDataSequence : public PivotTableDataSequence_Base, public SfxListener
{
public:
    explicit PivotTableDataSequence(ScDocument* pDocument, OUString const & sPivotTableName,
                                    OUString const & sID, std::vector<ValueAndFormat> const & rData);

    virtual ~PivotTableDataSequence() override;
    PivotTableDataSequence(const PivotTableDataSequence&) = delete;
    PivotTableDataSequence& operator=(const PivotTableDataSequence&) = delete;

    virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;

    // XDataSequence
    virtual css::uno::Sequence<css::uno::Any> SAL_CALL getData() override;
    virtual OUString SAL_CALL getSourceRangeRepresentation() override;
    virtual css::uno::Sequence<OUString> SAL_CALL
        generateLabel(css::chart2::data::LabelOrigin nOrigin) override;

    virtual sal_Int32 SAL_CALL getNumberFormatKeyByIndex(sal_Int32 nIndex) override;

    // XNumericalDataSequence
    virtual css::uno::Sequence<double> SAL_CALL getNumericalData() override;

    // XTextualDataSequence
    virtual css::uno::Sequence<OUString> SAL_CALL getTextualData() override;

    // XPropertySet
    virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL
        getPropertySetInfo() override;

    virtual void SAL_CALL setPropertyValue(const OUString& rPropertyName,
                                           const css::uno::Any& rValue) override;

    virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& rPropertyName) override;

    virtual void SAL_CALL addPropertyChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference< css::beans::XPropertyChangeListener>& xListener) override;

    virtual void SAL_CALL removePropertyChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference< css::beans::XPropertyChangeListener>& rListener) override;

    virtual void SAL_CALL addVetoableChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference< css::beans::XVetoableChangeListener>& rListener) override;

    virtual void SAL_CALL removeVetoableChangeListener(
            const OUString& rPropertyName,
            const css::uno::Reference<  css::beans::XVetoableChangeListener>& rListener) override;

    // XCloneable
    virtual css::uno::Reference<css::util::XCloneable> SAL_CALL createClone() override;

    // XModifyBroadcaster
    virtual void SAL_CALL addModifyListener(
        const css::uno::Reference<css::util::XModifyListener>& aListener) override;

    virtual void SAL_CALL removeModifyListener(
        const css::uno::Reference<css::util::XModifyListener>& aListener) override;

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override;

    virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;

    virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;

    // Other

    void setRole(css::chart2::data::DataSequenceRole const & aRole)
    {
        m_aRole = aRole;
    }

private:
    ScDocument* m_pDocument;
    OUString m_sPivotTableName;
    OUString m_aID;
    std::vector<ValueAndFormat> m_aData;
    SfxItemPropertySet m_aPropSet;
    css::chart2::data::DataSequenceRole m_aRole;
    std::vector<css::uno::Reference<css::util::XModifyListener>> m_aValueListeners;
};

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/PivotTableDataSource.hxx b/sc/inc/PivotTableDataSource.hxx
new file mode 100644
index 0000000..326f7c3
--- /dev/null
+++ b/sc/inc/PivotTableDataSource.hxx
@@ -0,0 +1,59 @@
/* -*- 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/.
 */

#ifndef INCLUDED_SC_INC_PIVOTTABLEDATASOURCE_HXX
#define INCLUDED_SC_INC_PIVOTTABLEDATASOURCE_HXX

#include <com/sun/star/chart2/data/XDataSource.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>

#include <svl/lstner.hxx>
#include <cppuhelper/implbase.hxx>

#include "document.hxx"

#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>

namespace sc
{

typedef cppu::WeakImplHelper<css::chart2::data::XDataSource,
                             css::lang::XServiceInfo>
            PivotTableDataSource_Base;

class PivotTableDataSource : public PivotTableDataSource_Base, public SfxListener
{
public:
    explicit PivotTableDataSource(OUString const & aRangeRepresentation,
                                  std::vector<css::uno::Reference<css::chart2::data::XLabeledDataSequence>>& xLabeledSequence);
    virtual ~PivotTableDataSource() override;
    virtual void Notify(SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override;

    // XDataSource
    virtual css::uno::Sequence<css::uno::Reference<css::chart2::data::XLabeledDataSequence>> SAL_CALL
        getDataSequences() override;

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override;

    virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;

    virtual css::uno::Sequence<OUString> SAL_CALL
        getSupportedServiceNames() override;

private:
    std::vector<css::uno::Reference<css::chart2::data::XLabeledDataSequence>> m_xLabeledSequence;
    OUString m_aRangeRepresentation;
};

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/TablePivotChart.hxx b/sc/inc/TablePivotChart.hxx
new file mode 100644
index 0000000..dce05e7
--- /dev/null
+++ b/sc/inc/TablePivotChart.hxx
@@ -0,0 +1,74 @@
/* -*- 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/.
 */

#ifndef INCLUDED_SC_INC_TABLEPIVOTCHART_HXX
#define INCLUDED_SC_INC_TABLEPIVOTCHART_HXX

#include <com/sun/star/table/XTablePivotChart.hpp>
#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/container/XNamed.hpp>

#include <svl/lstner.hxx>
#include <cppuhelper/compbase.hxx>
#include <cppuhelper/implbase.hxx>

#include "types.hxx"

class ScDocShell;

namespace sc
{

typedef cppu::WeakComponentImplHelper<css::table::XTablePivotChart,
                                      css::document::XEmbeddedObjectSupplier,
                                      css::container::XNamed,
                                      css::lang::XServiceInfo>
        TablePivotChart_Base;

class TablePivotChart : public cppu::BaseMutex,
                        public TablePivotChart_Base,
                        public SfxListener
{
private:
    ScDocShell* m_pDocShell;
    SCTAB m_nTab; // Charts are per sheet
    OUString m_aChartName;

public:
    TablePivotChart(ScDocShell* pDocShell, SCTAB nTab, OUString const & rName);
    virtual ~TablePivotChart() override;

    virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;

    // XComponent
    using TablePivotChart_Base::disposing;

    // XEmbeddedObjectSupplier
    virtual css::uno::Reference<css::lang::XComponent> SAL_CALL
        getEmbeddedObject() override;

    // XNamed
    virtual OUString SAL_CALL getName() override;
    virtual void SAL_CALL setName(OUString const & aName) override;

    // XTablePivotChart
    virtual OUString SAL_CALL getPivotTableName() override;

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override;
    virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
    virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
};

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/TablePivotCharts.hxx b/sc/inc/TablePivotCharts.hxx
new file mode 100644
index 0000000..f60726e
--- /dev/null
+++ b/sc/inc/TablePivotCharts.hxx
@@ -0,0 +1,76 @@
/* -*- 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/.
 */

#ifndef INCLUDED_SC_INC_TABLEPIVOTCHARTS_HXX
#define INCLUDED_SC_INC_TABLEPIVOTCHARTS_HXX

#include <com/sun/star/table/XTablePivotCharts.hpp>
#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>

#include <svl/lstner.hxx>
#include <cppuhelper/compbase.hxx>
#include <cppuhelper/implbase.hxx>

#include "types.hxx"

class ScDocShell;

namespace sc
{
typedef cppu::WeakImplHelper<css::table::XTablePivotCharts,
                             css::container::XIndexAccess,
                             css::lang::XServiceInfo>
        TablePivotCharts_Base;

class TablePivotCharts : public TablePivotCharts_Base, public SfxListener
{
private:
    ScDocShell* m_pDocShell;
    SCTAB m_nTab;

public:
    TablePivotCharts(ScDocShell* pDocShell, SCTAB nTab);

    virtual ~TablePivotCharts() override;

    virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;

    // XTablePivotCharts
    virtual void SAL_CALL addNewByName(OUString const & aName,
                                       const css::awt::Rectangle& aRect,
                                       OUString const & aDataPilotName) override;
    virtual void SAL_CALL removeByName(OUString const & aName) override;

    // XNameAccess
    virtual css::uno::Any SAL_CALL getByName(OUString const & aName) override;
    virtual css::uno::Sequence<OUString> SAL_CALL getElementNames() override;
    virtual sal_Bool SAL_CALL hasByName(OUString const & aName) override;

    // XIndexAccess
    virtual sal_Int32 SAL_CALL getCount() override;
    virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override;

    // XElementAccess
    virtual css::uno::Type SAL_CALL getElementType() override;
    virtual sal_Bool SAL_CALL hasElements() override;

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override;
    virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
    virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
};

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/cellsuno.hxx b/sc/inc/cellsuno.hxx
index aded180f..95cef41 100644
--- a/sc/inc/cellsuno.hxx
+++ b/sc/inc/cellsuno.hxx
@@ -31,6 +31,7 @@
#include <svl/listener.hxx>
#include <svl/itemprop.hxx>
#include <com/sun/star/table/XTableChartsSupplier.hpp>
#include <com/sun/star/table/XTablePivotChartsSupplier.hpp>
#include <com/sun/star/chart/XChartDataArray.hpp>
#include <com/sun/star/text/XTextFieldsSupplier.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
@@ -771,6 +772,7 @@ class ScTableSheetObj : public ScCellRangeObj,
                        public css::sheet::XSheetPageBreak,
                        public css::sheet::XCellRangeMovement,
                        public css::table::XTableChartsSupplier,
                        public css::table::XTablePivotChartsSupplier,
                        public css::sheet::XDataPilotTablesSupplier,
                        public css::sheet::XScenariosSupplier,
                        public css::sheet::XSheetAnnotationsSupplier,
@@ -856,6 +858,10 @@ public:
    virtual css::uno::Reference< css::table::XTableCharts > SAL_CALL
                            getCharts() override;

                            // XTablePivotChartsSupplier
    virtual css::uno::Reference<css::table::XTablePivotCharts> SAL_CALL
                            getPivotCharts() override;

                            // XDataPilotTablesSupplier
    virtual css::uno::Reference< css::sheet::XDataPilotTables > SAL_CALL
                            getDataPilotTables() override;
diff --git a/sc/inc/servuno.hxx b/sc/inc/servuno.hxx
index 44049dd..e814632 100644
--- a/sc/inc/servuno.hxx
+++ b/sc/inc/servuno.hxx
@@ -50,7 +50,7 @@ public:
        SHEETDOCSET ,

        // BM
        CHDATAPROV ,
        CHDATAPROV , CHART_PIVOTTABLE_DATAPROVIDER,
        // formula parser
        FORMULAPARS , OPCODEMAPPER ,
        // VBA specific
diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx
index 469183d..6e10454 100644
--- a/sc/inc/unonames.hxx
+++ b/sc/inc/unonames.hxx
@@ -32,6 +32,7 @@

#define SC_SERVICENAME_CHDATAPROV       "com.sun.star.chart2.data.DataProvider"
#define SC_SERVICENAME_CHRANGEHILIGHT   "com.sun.star.chart2.data.RangeHighlightListener"
#define SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER "com.sun.star.chart2.data.PivotTableDataProvider"

//  document
#define SC_UNO_AREALINKS            "AreaLinks"
diff --git a/sc/source/ui/drawfunc/fuins2.cxx b/sc/source/ui/drawfunc/fuins2.cxx
index 7f35185..f6cf018 100644
--- a/sc/source/ui/drawfunc/fuins2.cxx
+++ b/sc/source/ui/drawfunc/fuins2.cxx
@@ -63,8 +63,7 @@
#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <cppuhelper/bootstrap.hxx>

using namespace ::com::sun::star;

#include "PivotTableDataProvider.hxx"
#include "chart2uno.hxx"
#include "fuinsert.hxx"
#include "tabvwsh.hxx"
@@ -79,18 +78,23 @@ using namespace ::com::sun::star;
#include "drawview.hxx"
#include "markdata.hxx"
#include "gridwin.hxx"
#include "dpobject.hxx"
#include <memory>

namespace {
using namespace css;

void lcl_ChartInit( const uno::Reference < embed::XEmbeddedObject >& xObj, ScViewData* pViewData,
                    const OUString& rRangeParam )
namespace
{

void lcl_ChartInit(const uno::Reference <embed::XEmbeddedObject>& xObj, ScViewData* pViewData,
                   const OUString& rRangeParam, bool bRangeIsPivotTable)
{
    ScDocShell* pDocShell = pViewData->GetDocShell();
    ScDocument& rScDoc = pDocShell->GetDocument();

    OUString aRangeString( rRangeParam );
    if ( aRangeString.isEmpty() )
    OUString aRangeString(rRangeParam);

    if (aRangeString.isEmpty() && !bRangeIsPivotTable)
    {
        SCCOL nCol1 = 0;
        SCROW nRow1 = 0;
@@ -118,7 +122,7 @@ void lcl_ChartInit( const uno::Reference < embed::XEmbeddedObject >& xObj, ScVie
        }
    }

    if ( !aRangeString.isEmpty() )
    if (!aRangeString.isEmpty())
    {
        // connect to Calc data (if no range string, leave chart alone, with its own data)

@@ -129,8 +133,19 @@ void lcl_ChartInit( const uno::Reference < embed::XEmbeddedObject >& xObj, ScVie
        OSL_ASSERT( xReceiver.is());
        if( xReceiver.is() )
        {
            uno::Reference< chart2::data::XDataProvider > xDataProvider = new ScChart2DataProvider( &rScDoc );
            xReceiver->attachDataProvider( xDataProvider );
            uno::Reference<chart2::data::XDataProvider> xDataProvider;
            if (bRangeIsPivotTable)
            {
                std::unique_ptr<sc::PivotTableDataProvider> pPivotTableDataProvider(new sc::PivotTableDataProvider(&rScDoc));
                pPivotTableDataProvider->setPivotTableName(aRangeString);
                xDataProvider.set(pPivotTableDataProvider.release());
            }
            else
            {
                xDataProvider.set(new ScChart2DataProvider(&rScDoc));
            }

            xReceiver->attachDataProvider(xDataProvider);

            uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( pDocShell->GetModel(), uno::UNO_QUERY );
            xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
@@ -329,7 +344,7 @@ FuInsertOLE::FuInsertOLE(ScTabViewShell* pViewSh, vcl::Window* pWin, ScDrawView*

            //  Chart initialisieren ?
            if ( SvtModuleOptions().IsChart() && SotExchange::IsChart( SvGlobalName( xObj->getClassID() ) ) )
                lcl_ChartInit( xObj, &pViewSh->GetViewData(), OUString() );
                lcl_ChartInit(xObj, &pViewSh->GetViewData(), OUString(), false);

            ScViewData& rData = pViewSh->GetViewData();

@@ -393,7 +408,7 @@ FuInsertChart::FuInsertChart(ScTabViewShell* pViewSh, vcl::Window* pWin, ScDrawV
           SdrModel* pDoc, SfxRequest& rReq)
    : FuPoor(pViewSh, pWin, pViewP, pDoc, rReq)
{
    const SfxItemSet*   pReqArgs    = rReq.GetArgs();
    const SfxItemSet* pReqArgs = rReq.GetArgs();

    if( ! rReq.IsAPI() )
        rReq.Done();
@@ -405,6 +420,7 @@ FuInsertChart::FuInsertChart(ScTabViewShell* pViewSh, vcl::Window* pWin, ScDrawV

    // get range
    OUString aRangeString;
    bool bRangeIsPivotTable = false;
    ScRange aPositionRange;             // cell range for chart positioning
    ScMarkData aMark = pViewSh->GetViewData().GetMarkData();
    if( pReqArgs )
@@ -417,35 +433,46 @@ FuInsertChart::FuInsertChart(ScTabViewShell* pViewSh, vcl::Window* pWin, ScDrawV
    }
    else
    {
        bool bAutomaticMark = false;
        if ( !aMark.IsMarked() && !aMark.IsMultiMarked() )
        {
            pViewSh->GetViewData().GetView()->MarkDataArea();
            bAutomaticMark = true;
        }

        ScMarkData aMultiMark( aMark );
        aMultiMark.MarkToMulti();

        ScRangeList aRanges;
        aMultiMark.FillRangeListWithMarks( &aRanges, false );
        OUString aStr;
        ScDocument* pDocument = pViewSh->GetViewData().GetDocument();
        aRanges.Format( aStr, ScRefFlags::RANGE_ABS_3D, pDocument, pDocument->GetAddressConvention() );
        aRangeString = aStr;

        // get "total" range for positioning
        if ( !aRanges.empty() )
        ScDPObject* pObject = pDocument->GetDPAtCursor(pViewSh->GetViewData().GetCurX(),
                                                       pViewSh->GetViewData().GetCurY(),
                                                       pViewSh->GetViewData().GetTabNo());
        if (pObject)
        {
            aPositionRange = *aRanges[ 0 ];
            for ( size_t i = 1, nCount = aRanges.size(); i < nCount; ++i )
            {
                aPositionRange.ExtendTo( *aRanges[ i ] );
            }
            aRangeString = pObject->GetName();
            bRangeIsPivotTable = true;
        }
        else
        {
            bool bAutomaticMark = false;
            if ( !aMark.IsMarked() && !aMark.IsMultiMarked() )
            {
                pViewSh->GetViewData().GetView()->MarkDataArea();
                bAutomaticMark = true;
            }

        if(bAutomaticMark)
            pViewSh->GetViewData().GetView()->Unmark();
            ScMarkData aMultiMark( aMark );
            aMultiMark.MarkToMulti();

            ScRangeList aRanges;
            aMultiMark.FillRangeListWithMarks( &aRanges, false );
            OUString aStr;
            aRanges.Format( aStr, ScRefFlags::RANGE_ABS_3D, pDocument, pDocument->GetAddressConvention() );
            aRangeString = aStr;

            // get "total" range for positioning
            if ( !aRanges.empty() )
            {
                aPositionRange = *aRanges[ 0 ];
                for ( size_t i = 1, nCount = aRanges.size(); i < nCount; ++i )
                {
                    aPositionRange.ExtendTo( *aRanges[ i ] );
                }
            }

            if(bAutomaticMark)
                pViewSh->GetViewData().GetView()->Unmark();
        }
    }

    // adapted old code
@@ -568,7 +595,7 @@ FuInsertChart::FuInsertChart(ScTabViewShell* pViewSh, vcl::Window* pWin, ScDrawV
        }
    }

    lcl_ChartInit( xObj, &rData, aRangeString );         // set source range, auto-detect column/row headers
    lcl_ChartInit(xObj, &rData, aRangeString, bRangeIsPivotTable);         // set source range, auto-detect column/row headers

    //  Objekt-Position

diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index b217c5b..a9cccb1 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -487,7 +487,7 @@ public:
    void            ClearHighlightRanges();

    void            DoChartSelection( const css::uno::Sequence< css::chart2::data::HighlightedRange > & rHilightRanges );
    void            DoDPFieldPopup(Point aPoint, Size aSize);
    void            DoDPFieldPopup(OUString const & rPivotTableName, sal_Int32 nDimensionIndex, Point aPoint, Size aSize);

    long            GetGridWidth( ScHSplitPos eWhich );
    long            GetGridHeight( ScVSplitPos eWhich );
diff --git a/sc/source/ui/unoobj/ChartTools.cxx b/sc/source/ui/unoobj/ChartTools.cxx
new file mode 100644
index 0000000..7781872
--- /dev/null
+++ b/sc/source/ui/unoobj/ChartTools.cxx
@@ -0,0 +1,127 @@
/* -*- 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/.
 *
 */

#include "ChartTools.hxx"

#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>

#include <svx/svditer.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdundo.hxx>
#include <sfx2/app.hxx>
#include <unotools/moduleoptions.hxx>
#include <comphelper/classids.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <tools/globname.hxx>
#include <svx/charthelper.hxx>
#include <svtools/embedhlp.hxx>

using namespace css;

namespace sc {
namespace tools {

ChartIterator::ChartIterator(ScDocShell* pDocShell, SCTAB nTab, ChartSourceType eChartSourceType)
    : m_eChartSourceType(eChartSourceType)
{
    if (!pDocShell)
        return;
    ScDocument& rDoc = pDocShell->GetDocument();
    ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
    if (!pDrawLayer)
        return;
    SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(nTab));
    if (!pPage)
        return;
    m_pIterator.reset(new SdrObjListIter(*pPage, SdrIterMode::DeepNoGroups));
}

SdrOle2Obj* ChartIterator::next()
{
    if (!m_pIterator)
        return nullptr;

    SdrObject* pObject = m_pIterator->Next();
    while (pObject)
    {
        if (pObject->GetObjIdentifier() == OBJ_OLE2 && ScDocument::IsChart(pObject))
        {
            SdrOle2Obj* pOleObject = static_cast<SdrOle2Obj*>(pObject);
            uno::Reference<embed::XEmbeddedObject> xObject = pOleObject->GetObjRef();
            if (xObject.is())
            {
                uno::Reference<chart2::XChartDocument> xChartDoc(xObject->getComponent(), uno::UNO_QUERY);
                if (xChartDoc.is())
                {
                    uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xChartDoc->getDataProvider(), uno::UNO_QUERY);
                    if (xPivotTableDataProvider.is() && m_eChartSourceType == ChartSourceType::PIVOT_TABLE)
                    {
                        return pOleObject;
                    }
                    else if (!xPivotTableDataProvider.is() && m_eChartSourceType == ChartSourceType::CELL_RANGE)
                    {
                        return pOleObject;
                    }
                }
            }
        }
        pObject = m_pIterator->Next();
    }
    return nullptr;
}

SdrOle2Obj* findChartsByName(ScDocShell* pDocShell, SCTAB nTab, OUString const & rName, ChartSourceType eChartSourceType)
{
    if (!pDocShell)
        return nullptr;

    ChartIterator aIterator(pDocShell, nTab, eChartSourceType);

    SdrOle2Obj* pObject = aIterator.next();
    while (pObject)
    {
        uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
        if (xObject.is())
        {
            OUString aObjectName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
            if (aObjectName == rName)
                return pObject;
        }
        pObject = aIterator.next();
    }
    return nullptr;
}

SdrOle2Obj* getChartByIndex(ScDocShell* pDocShell, SCTAB nTab, long nIndex, ChartSourceType eChartSourceType)
{
    if (!pDocShell)
        return nullptr;

    ChartIterator aIterator(pDocShell, nTab, eChartSourceType);

    SdrOle2Obj* pObject = aIterator.next();
    long i = 0;
    while (pObject)
    {
        if (i == nIndex)
        {
            return pObject;
        }

        i++;
        pObject = aIterator.next();
    }
    return nullptr;
}

}} // end sc::tools

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataProvider.cxx b/sc/source/ui/unoobj/PivotTableDataProvider.cxx
new file mode 100644
index 0000000..84eb756
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataProvider.cxx
@@ -0,0 +1,843 @@
/* -*- 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/.
 */

#include <sal/config.h>

#include "PivotTableDataProvider.hxx"
#include "PivotTableDataSource.hxx"
#include "PivotTableDataSequence.hxx"

#include <vcl/svapp.hxx>

#include "miscuno.hxx"
#include "document.hxx"
#include "unonames.hxx"
#include "docsh.hxx"

#include <sfx2/objsh.hxx>
#include <comphelper/sequence.hxx>

#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
#include <com/sun/star/chart/ChartDataRowSource.hpp>

#include <com/sun/star/sheet/XDataPilotResults.hpp>
#include <com/sun/star/sheet/DataResultFlags.hpp>

#include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
#include <com/sun/star/sheet/XLevelsSupplier.hpp>
#include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
#include <com/sun/star/sheet/MemberResultFlags.hpp>

#include "dpobject.hxx"

#include "hints.hxx"

#include <com/sun/star/chart/ChartDataChangeEvent.hpp>

#include <unordered_map>

using namespace css;

namespace sc
{
namespace
{

const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
{
    static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
    {
        { OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, cppu::UnoType<bool>::get(), 0, 0 },
        { OUString(SC_UNONAME_USE_INTERNAL_DATA_PROVIDER), 0, cppu::UnoType<bool>::get(), 0, 0 },
        { OUString(), 0, css::uno::Type(), 0, 0 }
    };
    return aDataProviderPropertyMap_Impl;
}

uno::Reference<frame::XModel> lcl_GetXModel(ScDocument * pDoc)
{
    uno::Reference<frame::XModel> xModel;
    SfxObjectShell* pObjSh(pDoc ? pDoc->GetDocumentShell() : nullptr);
    if (pObjSh)
        xModel.set(pObjSh->GetModel());
    return xModel;
}

OUString lcl_identifierForData(sal_Int32 index)
{
    return "Data " + OUString::number(index + 1);
}

OUString lcl_identifierForLabel(sal_Int32 index)
{
    return "Label " + OUString::number(index + 1);
}

} // end anonymous namespace

SC_SIMPLE_SERVICE_INFO(PivotTableDataProvider, "PivotTableDataProvider", SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER)

// DataProvider ==============================================================

PivotTableDataProvider::PivotTableDataProvider(ScDocument* pDoc)
    : m_pDocument(pDoc)
    , m_aPropSet(lcl_GetDataProviderPropertyMap())
    , m_bIncludeHiddenCells(true)
    , m_bNeedsUpdate(true)
    , m_xContext(comphelper::getProcessComponentContext())
{
    if (m_pDocument)
        m_pDocument->AddUnoObject(*this);
}

PivotTableDataProvider::~PivotTableDataProvider()
{
    SolarMutexGuard g;

    if (m_pDocument)
        m_pDocument->RemoveUnoObject( *this);
}

void PivotTableDataProvider::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
{
    if (rHint.GetId() == SfxHintId::Dying)
    {
        m_pDocument = nullptr;
    }
    else if (dynamic_cast<const ScDataPilotModifiedHint*>(&rHint))
    {
        if (m_pDocument)
        {
            OUString sPivotTableName = static_cast<const ScDataPilotModifiedHint&>(rHint).GetName();
            if (sPivotTableName == m_sPivotTableName)
            {
                m_bNeedsUpdate = true;
                for (uno::Reference<util::XModifyListener> const & xListener : m_aValueListeners)
                {
                    css::chart::ChartDataChangeEvent aEvent(static_cast<cppu::OWeakObject*>(this),
                                                            css::chart::ChartDataChangeType_ALL,
                                                            0, 0, 0, 0);
                    xListener->modified(aEvent);
                }
            }
        }
    }
}

sal_Bool SAL_CALL PivotTableDataProvider::createDataSourcePossible(const uno::Sequence<beans::PropertyValue>& /*aArguments*/)
{
    SolarMutexGuard aGuard;
    if (!m_pDocument)
        return false;

    if (m_sPivotTableName.isEmpty())
        return false;

    ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
    return bool(pDPCollection->GetByName(m_sPivotTableName));
}

uno::Reference<chart2::data::XDataSource> SAL_CALL
    PivotTableDataProvider::createDataSource(const uno::Sequence<beans::PropertyValue>& aArguments)
{
    SolarMutexGuard aGuard;
    if (!m_pDocument)
        throw uno::RuntimeException();

    bool bLabel = true;
    bool bCategories = false;
    bool bOrientCol = true;
    OUString aRangeRepresentation;
    OUString sPivotTable;
    uno::Sequence<sal_Int32> aSequenceMapping;
    bool bTimeBased = false;

    for (beans::PropertyValue const & rProperty : aArguments)
    {
        if (rProperty.Name == "DataRowSource")
        {
            chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
            if (!(rProperty.Value >>= eSource))
            {
                sal_Int32 nSource(0);
                if (rProperty.Value >>= nSource)
                    eSource = chart::ChartDataRowSource(nSource);
            }
            bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
        }
        else if (rProperty.Name == "FirstCellAsLabel")
            rProperty.Value >>= bLabel;
        else if (rProperty.Name == "HasCategories")
            rProperty.Value >>= bCategories;
        else if (rProperty.Name == "CellRangeRepresentation")
            rProperty.Value >>= aRangeRepresentation;
        else if (rProperty.Name == "SequenceMapping")
            rProperty.Value >>= aSequenceMapping;
        else if (rProperty.Name == "TimeBased")
            rProperty.Value >>= bTimeBased;
        else if (rProperty.Name == "ConnectedPivotTable")
            rProperty.Value >>= sPivotTable;
    }

    uno::Reference<chart2::data::XDataSource> xResult;

    if (aRangeRepresentation == "Categories")
        xResult = createCategoriesDataSource(aRangeRepresentation, bOrientCol);
    else
        xResult = createValuesDataSource(aRangeRepresentation);

    return xResult;
}

uno::Reference<chart2::data::XLabeledDataSequence>
    PivotTableDataProvider::newLabeledDataSequence()
{
    uno::Reference<chart2::data::XLabeledDataSequence> xResult;
    if (!m_xContext.is())
        return xResult;
    xResult.set(chart2::data::LabeledDataSequence::create(m_xContext), uno::UNO_QUERY_THROW);
    return xResult;
}

void PivotTableDataProvider::setLabeledDataSequenceValues(uno::Reference<chart2::data::XLabeledDataSequence> & xResult,
                                                          OUString const & sRoleValues, OUString const & sIdValues,
                                                          std::vector<ValueAndFormat> const & rValues)
{
    std::unique_ptr<PivotTableDataSequence> pSequence(
        new PivotTableDataSequence(m_pDocument, m_sPivotTableName, sIdValues, rValues));
    pSequence->setRole(sRoleValues);
    xResult->setValues(uno::Reference<chart2::data::XDataSequence>(pSequence.release()));
}

void PivotTableDataProvider::setLabeledDataSequence(uno::Reference<chart2::data::XLabeledDataSequence> & xResult,
                                                    OUString const & sRoleValues, OUString const & sIdValues,
                                                    std::vector<ValueAndFormat> const & rValues,
                                                    OUString const & sRoleLabel,  OUString const & sIdLabel,
                                                    std::vector<ValueAndFormat> const & rLabel)
{
    setLabeledDataSequenceValues(xResult, sRoleValues, sIdValues, rValues);

    std::unique_ptr<PivotTableDataSequence> pLabelSequence(
        new PivotTableDataSequence(m_pDocument, m_sPivotTableName, sIdLabel, rLabel));
    pLabelSequence->setRole(sRoleLabel);
    xResult->setLabel(uno::Reference<chart2::data::XDataSequence>(pLabelSequence.release()));
}

uno::Reference<chart2::data::XDataSource>
PivotTableDataProvider::createCategoriesDataSource(OUString const & rRangeRepresentation,
                                                   bool bOrientationIsColumn)
{
    if (m_bNeedsUpdate)
        collectPivotTableData();

    uno::Reference<chart2::data::XDataSource> xDataSource;
    std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;

    if (bOrientationIsColumn)
    {
        for (std::vector<ValueAndFormat> const & rCategories : m_aCategoriesColumnOrientation)
        {
            uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
            setLabeledDataSequenceValues(xResult, "categories", "Categories", rCategories);
            aLabeledSequences.push_back(xResult);
        }
    }
    else
    {
        for (std::vector<ValueAndFormat> const & rCategories : m_aCategoriesRowOrientation)
        {
            uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
            setLabeledDataSequenceValues(xResult, "categories", "Categories", rCategories);
            aLabeledSequences.push_back(xResult);
        }
    }

    xDataSource.set(new PivotTableDataSource(rRangeRepresentation, aLabeledSequences));
    return xDataSource;
}

void PivotTableDataProvider::collectPivotTableData()
{
    ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
    ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);

    uno::Reference<sheet::XDataPilotResults> xDPResults(pDPObject->GetSource(), uno::UNO_QUERY);
    uno::Sequence<uno::Sequence<sheet::DataResult>> xDataResultsSequence = xDPResults->getResults();

    m_aCategoriesColumnOrientation.clear();
    m_aCategoriesRowOrientation.clear();
    m_aLabels.clear();
    m_aDataRowVector.clear();
    m_aColumnFields.clear();
    m_aRowFields.clear();
    m_aPageFields.clear();
    m_aDataFields.clear();

    double fNan;
    rtl::math::setNan(&fNan);

    for (uno::Sequence<sheet::DataResult> const & xDataResults : xDataResultsSequence)
    {
        size_t nIndex = 0;
        for (sheet::DataResult const & rDataResult : xDataResults)
        {
            if (rDataResult.Flags == 0 || rDataResult.Flags & css::sheet::DataResultFlags::HASDATA)
            {
                if (nIndex >= m_aDataRowVector.size())
                    m_aDataRowVector.resize(nIndex + 1);
                m_aDataRowVector[nIndex].push_back(ValueAndFormat(rDataResult.Flags ? rDataResult.Value : fNan, 0));
            }
            nIndex++;
        }
    }

    uno::Reference<sheet::XDimensionsSupplier> xDimensionsSupplier(pDPObject->GetSource());
    uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions());

    std::unordered_map<OUString, sal_Int32, OUStringHash> aDataFieldNumberFormatMap;
    std::vector<OUString> aDataFieldNamesVectors;

    std::unordered_map<OUString, OUString, OUStringHash> aDataFieldCaptionNames;
    std::vector<std::pair<OUString, sal_Int32>> aDataFieldPairs;

    sheet::DataPilotFieldOrientation eDataFieldOrientation = sheet::DataPilotFieldOrientation_HIDDEN;

    for (sal_Int32 nDim = 0; nDim < xDims->getCount(); nDim++)
    {
        uno::Reference<uno::XInterface> xDim = ScUnoHelpFunctions::AnyToInterface(xDims->getByIndex(nDim));
        uno::Reference<beans::XPropertySet> xDimProp(xDim, uno::UNO_QUERY);
        uno::Reference<container::XNamed> xDimName(xDim, uno::UNO_QUERY);
        uno::Reference<sheet::XHierarchiesSupplier> xDimSupp(xDim, uno::UNO_QUERY);

        if (!xDimProp.is() || !xDimSupp.is())
            continue;

        sheet::DataPilotFieldOrientation eDimOrient = sheet::DataPilotFieldOrientation(
            ScUnoHelpFunctions::GetEnumProperty(xDimProp, SC_UNO_DP_ORIENTATION,
                                                sheet::DataPilotFieldOrientation_HIDDEN));

        if (eDimOrient == sheet::DataPilotFieldOrientation_HIDDEN)
            continue;

        uno::Reference<container::XIndexAccess> xHierarchies = new ScNameToIndexAccess(xDimSupp->getHierarchies());
        sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_USEDHIERARCHY);
        if (nHierarchy >= xHierarchies->getCount())
            nHierarchy = 0;

        uno::Reference<uno::XInterface> xHierarchy = ScUnoHelpFunctions::AnyToInterface(xHierarchies->getByIndex(nHierarchy));

        uno::Reference<sheet::XLevelsSupplier> xLevelsSupplier(xHierarchy, uno::UNO_QUERY);

        if (!xLevelsSupplier.is())
            continue;

        uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess(xLevelsSupplier->getLevels());

        for (long nLevel = 0; nLevel < xLevels->getCount(); nLevel++)
        {
            uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(xLevels->getByIndex(nLevel));
            uno::Reference<container::XNamed> xLevelName(xLevel, uno::UNO_QUERY);
            uno::Reference<sheet::XDataPilotMemberResults> xLevelResult(xLevel, uno::UNO_QUERY );

            bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_ISDATALAYOUT);
            long nDimPos = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_POSITION);
            sal_Int32 nNumberFormat = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_NUMBERFO);

            if (xLevelName.is() && xLevelResult.is())
            {
                switch (eDimOrient)
                {
                    case sheet::DataPilotFieldOrientation_COLUMN:
                    {
                        m_aColumnFields.push_back(chart2::data::PivotTableFieldEntry{xLevelName->getName(), nDim});

                        uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
                        size_t i = 0;
                        OUString sCaption;
                        OUString sName;
                        m_aLabels.resize(aSequence.getLength());
                        for (sheet::MemberResult & rMember : aSequence)
                        {
                            if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER ||
                                rMember.Flags & sheet::MemberResultFlags::CONTINUE)
                            {
                                if (!(rMember.Flags & sheet::MemberResultFlags::CONTINUE))
                                {
                                    sCaption = rMember.Caption;
                                    sName = rMember.Name;
                                }

                                if (size_t(nDimPos) >= m_aLabels[i].size())
                                    m_aLabels[i].resize(nDimPos + 1);
                                m_aLabels[i][nDimPos] = ValueAndFormat(sCaption);

                                if (bIsDataLayout)
                                {
                                    // Remember data fields to determine the number format of data
                                    aDataFieldNamesVectors.push_back(sName);
                                    eDataFieldOrientation = sheet::DataPilotFieldOrientation_COLUMN;
                                    // Remember the caption name
                                    aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
                                }
                                i++;
                            }
                        }
                    }
                    break;

                    case sheet::DataPilotFieldOrientation_ROW:
                    {
                        m_aRowFields.push_back(chart2::data::PivotTableFieldEntry{xLevelName->getName(), nDim});

                        uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
                        m_aCategoriesRowOrientation.resize(aSequence.getLength());
                        size_t i = 0;
                        for (sheet::MemberResult & rMember : aSequence)
                        {
                            bool bHasContinueFlag = rMember.Flags & sheet::MemberResultFlags::CONTINUE;

                            if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER || bHasContinueFlag)
                            {
                                std::unique_ptr<ValueAndFormat> pItem;

                                double fValue = rMember.Value;

                                if (rtl::math::isNan(fValue))
                                {
                                    OUString sStringValue = bHasContinueFlag ? "" : rMember.Caption;
                                    pItem.reset(new ValueAndFormat(sStringValue));
                                }
                                else
                                {
                                    if (bHasContinueFlag)
                                        pItem.reset(new ValueAndFormat());
                                    else
                                        pItem.reset(new ValueAndFormat(fValue, nNumberFormat));
                                }

                                if (size_t(nDimPos) >= m_aCategoriesColumnOrientation.size())
                                    m_aCategoriesColumnOrientation.resize(nDimPos + 1);
                                m_aCategoriesColumnOrientation[nDimPos].push_back(*pItem);

                                if (size_t(nDimPos) >= m_aCategoriesRowOrientation[i].size())
                                    m_aCategoriesRowOrientation[i].resize(nDimPos + 1);
                                m_aCategoriesRowOrientation[i][nDimPos] = *pItem;

                                if (bIsDataLayout)
                                {
                                    // Remember data fields to determine the number format of data
                                    aDataFieldNamesVectors.push_back(rMember.Name);
                                    eDataFieldOrientation = sheet::DataPilotFieldOrientation_ROW;

                                    // Remember the caption name
                                    aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
                                }
                                i++;
                            }
                        }
                    }
                    break;

                    case sheet::DataPilotFieldOrientation_PAGE:
                    {
                        m_aPageFields.push_back(chart2::data::PivotTableFieldEntry{xLevelName->getName(), nDim});
                    }
                    break;

                    case sheet::DataPilotFieldOrientation_DATA:
                    {
                        aDataFieldNumberFormatMap[xLevelName->getName()] = nNumberFormat;
                        aDataFieldPairs.push_back(std::pair<OUString, sal_Int32>(xLevelName->getName(), nDim));
                    }
                    break;

                    default:
                        break;
                }
            }
        }
    }

    // Fill data field entry info
    for (std::pair<OUString, sal_Int32> & rPair : aDataFieldPairs)
    {
        m_aDataFields.push_back(chart2::data::PivotTableFieldEntry{
                                    aDataFieldCaptionNames[rPair.first],
                                    rPair.second});
    }

    // Apply number format to the data
    if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_ROW)
    {
        for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
        {
            size_t i = 0;
            for (ValueAndFormat & rItem : rDataRow)
            {
                OUString sName = aDataFieldNamesVectors[i];
                sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
                rItem.m_nNumberFormat = nNumberFormat;
                i++;
            }
        }
    }
    else if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_COLUMN)
    {
        size_t i = 0;
        for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
        {
            OUString sName = aDataFieldNamesVectors[i];
            sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
            for (ValueAndFormat & rItem : rDataRow)
            {
                rItem.m_nNumberFormat = nNumberFormat;
            }
            i++;
        }
    }

    m_bNeedsUpdate = false;
}

void PivotTableDataProvider::assignValuesToDataSequence(uno::Reference<chart2::data::XDataSequence> & rDataSequence,
                                                        size_t nIndex)
{
    if (nIndex >= m_aDataRowVector.size())
        return;

    OUString sDataID = lcl_identifierForData(nIndex);

    std::vector<ValueAndFormat> const & rRowOfData = m_aDataRowVector[size_t(nIndex)];
    std::unique_ptr<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument, m_sPivotTableName,
                                                                                 sDataID, rRowOfData));
    pSequence->setRole("values-y");
    rDataSequence.set(uno::Reference<chart2::data::XDataSequence>(pSequence.release()));
}

void PivotTableDataProvider::assignLabelsToDataSequence(uno::Reference<chart2::data::XDataSequence> & rDataSequence,
                                                        size_t nIndex)
{
    if (nIndex >= m_aLabels.size())
        return;

    OUString sLabelID = lcl_identifierForLabel(nIndex);

    OUString aLabel;
    bool bFirst = true;
    for (ValueAndFormat const & rItem : m_aLabels[size_t(nIndex)])
    {
        if (bFirst)
        {
            aLabel += rItem.m_aString;
            bFirst = false;
        }
        else
        {
            aLabel += " - " + rItem.m_aString;
        }
    }

    std::vector<ValueAndFormat> aLabelVector { ValueAndFormat(aLabel) };

    std::unique_ptr<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument, m_sPivotTableName,
                                                                                 sLabelID, aLabelVector));
    pSequence->setRole("values-y");
    rDataSequence.set(uno::Reference<chart2::data::XDataSequence>(pSequence.release()));
}

uno::Reference<chart2::data::XDataSource>
    PivotTableDataProvider::createValuesDataSource(OUString const & rRangeRepresentation)
{
    if (m_bNeedsUpdate)
        collectPivotTableData();

    uno::Reference<chart2::data::XDataSource> xDataSource;
    std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;

    {
        std::vector<ValueAndFormat> aFirstCategories;
        if (!m_aCategoriesColumnOrientation.empty())
        {
            std::copy(m_aCategoriesColumnOrientation[0].begin(),
                      m_aCategoriesColumnOrientation[0].end(),
                      std::back_inserter(aFirstCategories));
        }
        uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
        setLabeledDataSequenceValues(xResult, "categories", "Categories", aFirstCategories);
        aLabeledSequences.push_back(xResult);
    }

    {
        int i = 0;
        for (std::vector<ValueAndFormat> const & rRowOfData : m_aDataRowVector)
        {
            OUString aValuesId = lcl_identifierForData(i);
            OUString aLabelsId = lcl_identifierForLabel(i);

            OUString aLabel;
            bool bFirst = true;
            for (ValueAndFormat const & rItem : m_aLabels[i])
            {
                if (bFirst)
                {
                    aLabel += rItem.m_aString;
                    bFirst = false;
                }
                else
                {
                    aLabel += " - " + rItem.m_aString;
                }
            }

            std::vector<ValueAndFormat> aLabelVector { ValueAndFormat(aLabel) };

            uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
            setLabeledDataSequence(xResult, "values-y", aValuesId, rRowOfData,
                                            "values-y", aLabelsId, aLabelVector);
            aLabeledSequences.push_back(xResult);
            i++;
        }
    }

    xDataSource.set(new PivotTableDataSource(rRangeRepresentation, aLabeledSequences));
    return xDataSource;
}


uno::Sequence<beans::PropertyValue> SAL_CALL PivotTableDataProvider::detectArguments(
            const uno::Reference<chart2::data::XDataSource> & xDataSource)
{
    uno::Sequence<beans::PropertyValue> aArguments;

    if (!m_pDocument ||!xDataSource.is())
        return aArguments;

    aArguments.realloc(4);

    aArguments[0] = beans::PropertyValue("CellRangeRepresentation", -1, uno::Any(OUString("PivotChart")),
                    beans::PropertyState_DIRECT_VALUE);

    aArguments[1] = beans::PropertyValue("DataRowSource", -1, uno::Any(chart::ChartDataRowSource_COLUMNS),
                    beans::PropertyState_DIRECT_VALUE);

    aArguments[2] = beans::PropertyValue("FirstCellAsLabel", -1, uno::Any(false),
                    beans::PropertyState_DIRECT_VALUE);

    aArguments[3] = beans::PropertyValue("HasCategories", -1, uno::Any(true),
                    beans::PropertyState_DIRECT_VALUE);

    return aArguments;
}

sal_Bool SAL_CALL PivotTableDataProvider::createDataSequenceByRangeRepresentationPossible(const OUString& /*aRangeRepresentation*/)
{
    SolarMutexGuard aGuard;
    return false;
}

uno::Reference<chart2::data::XDataSequence> SAL_CALL
    PivotTableDataProvider::createDataSequenceByRangeRepresentation(const OUString& /*rRangeRepresentation*/)
{
    SolarMutexGuard aGuard;
    uno::Reference<chart2::data::XDataSequence> xDataSequence;
    return xDataSequence;
}

uno::Reference<chart2::data::XDataSequence> SAL_CALL
    PivotTableDataProvider::createDataSequenceByValueArray(const OUString& /*aRole*/,
                                                           const OUString& /*aRangeRepresentation*/)
{
    return uno::Reference<chart2::data::XDataSequence>();
}

uno::Reference<sheet::XRangeSelection> SAL_CALL PivotTableDataProvider::getRangeSelection()
{
    uno::Reference<sheet::XRangeSelection> xResult;

    uno::Reference<frame::XModel> xModel(lcl_GetXModel(m_pDocument));
    if (xModel.is())
        xResult.set(xModel->getCurrentController(), uno::UNO_QUERY);

    return xResult;
}

uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getColumnFields()
{
    return comphelper::containerToSequence(m_aColumnFields);
}

uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getRowFields()
{
    return comphelper::containerToSequence(m_aRowFields);
}

uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getPageFields()
{
    return comphelper::containerToSequence(m_aPageFields);
}

uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getDataFields()
{
    return comphelper::containerToSequence(m_aDataFields);
}

OUString PivotTableDataProvider::getPivotTableName()
{
    return m_sPivotTableName;
}

void PivotTableDataProvider::setPivotTableName(const OUString& sPivotTableName)
{
    ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
    ScDPObject* pDPObject = pDPCollection->GetByName(sPivotTableName);
    if (pDPObject)
        m_sPivotTableName = sPivotTableName;
}

uno::Reference<chart2::data::XDataSequence>
    PivotTableDataProvider::createDataSequenceOfValuesByIndex(sal_Int32 nIndex)
{
    SolarMutexGuard aGuard;

    if (m_bNeedsUpdate)
        collectPivotTableData();

    uno::Reference<chart2::data::XDataSequence> xDataSequence;
    assignValuesToDataSequence(xDataSequence, size_t(nIndex));
    return xDataSequence;
}

uno::Reference<css::chart2::data::XDataSequence>
    PivotTableDataProvider::createDataSequenceOfLabelsByIndex(sal_Int32 nIndex)
{
    SolarMutexGuard aGuard;

    if (m_bNeedsUpdate)
        collectPivotTableData();

    uno::Reference<chart2::data::XDataSequence> xDataSequence;
    assignLabelsToDataSequence(xDataSequence, size_t(nIndex));
    return xDataSequence;
}

uno::Reference<css::chart2::data::XDataSequence>
    PivotTableDataProvider::createDataSequenceOfCategories()
{
    SolarMutexGuard aGuard;

    if (m_bNeedsUpdate)
        collectPivotTableData();

    uno::Reference<chart2::data::XDataSequence> xDataSequence;

    if (m_aCategoriesColumnOrientation.empty())
        return xDataSequence;

    std::vector<ValueAndFormat> const & rCategories = m_aCategoriesColumnOrientation[0];

    std::unique_ptr<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument, m_sPivotTableName,
                                                                                 "Categories", rCategories));
    pSequence->setRole("categories");
    xDataSequence.set(uno::Reference<chart2::data::XDataSequence>(pSequence.release()));

    return xDataSequence;
}

// XModifyBroadcaster ========================================================

void SAL_CALL PivotTableDataProvider::addModifyListener(const uno::Reference< util::XModifyListener>& aListener)
{
    SolarMutexGuard aGuard;

    m_aValueListeners.push_back(uno::Reference<util::XModifyListener>(aListener));
}

void SAL_CALL PivotTableDataProvider::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener )
{
    SolarMutexGuard aGuard;

    sal_uInt16 nCount = m_aValueListeners.size();
    for (sal_uInt16 n = nCount; n--;)
    {
        uno::Reference<util::XModifyListener>& rObject = m_aValueListeners[n];
        if (rObject == aListener)
        {
            m_aValueListeners.erase(m_aValueListeners.begin() + n);
        }
    }
}

// DataProvider XPropertySet -------------------------------------------------

uno::Reference< beans::XPropertySetInfo> SAL_CALL
    PivotTableDataProvider::getPropertySetInfo()
{
    SolarMutexGuard aGuard;
    static uno::Reference<beans::XPropertySetInfo> aRef =
        new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
    return aRef;
}

void SAL_CALL PivotTableDataProvider::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
{
    if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
    {
        if (!(rValue >>= m_bIncludeHiddenCells))
            throw lang::IllegalArgumentException();
    }
    else
        throw beans::UnknownPropertyException();
}

uno::Any SAL_CALL PivotTableDataProvider::getPropertyValue(const OUString& rPropertyName)
{
    uno::Any aRet;
    if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
        aRet <<= m_bIncludeHiddenCells;
    else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
    {
        // This is a read-only property.
        aRet <<= m_pDocument->PastingDrawFromOtherDoc();
    }
    else
        throw beans::UnknownPropertyException();
    return aRet;
}

void SAL_CALL PivotTableDataProvider::addPropertyChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/)
{
    OSL_FAIL("Not yet implemented");
}

void SAL_CALL PivotTableDataProvider::removePropertyChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference<beans::XPropertyChangeListener>& /*rListener*/)
{
    OSL_FAIL("Not yet implemented");
}

void SAL_CALL PivotTableDataProvider::addVetoableChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/)
{
    OSL_FAIL("Not yet implemented");
}

void SAL_CALL PivotTableDataProvider::removeVetoableChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/ )
{
    OSL_FAIL("Not yet implemented");
}

} // end sc namespace

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataSequence.cxx b/sc/source/ui/unoobj/PivotTableDataSequence.cxx
new file mode 100644
index 0000000..da8bb26
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataSequence.cxx
@@ -0,0 +1,278 @@
/* -*- 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/.
 */

#include "PivotTableDataSequence.hxx"

#include <sal/config.h>

#include "miscuno.hxx"
#include "document.hxx"
#include "docsh.hxx"
#include "hints.hxx"

#include <com/sun/star/chart/ChartDataChangeEvent.hpp>

using namespace css;

namespace sc
{

SC_SIMPLE_SERVICE_INFO( PivotTableDataSequence, "PivotTableDataSequence", "com.sun.star.chart2.data.DataSequence")

const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap()
{
    static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
    {
        { OUString(SC_UNONAME_HIDDENVALUES), 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), 0, 0 },
        { OUString(SC_UNONAME_ROLE), 0, cppu::UnoType<css::chart2::data::DataSequenceRole>::get(), 0, 0 },
        { OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, cppu::UnoType<bool>::get(), 0, 0 },
        { OUString(), 0, css::uno::Type(), 0, 0 }
    };
    return aDataSequencePropertyMap_Impl;
}

PivotTableDataSequence::PivotTableDataSequence(ScDocument* pDocument, OUString const & sPivotTableName, OUString const & sID,
                                               std::vector<ValueAndFormat> const & rData)
    : m_pDocument(pDocument)
    , m_sPivotTableName(sPivotTableName)
    , m_aID(sID)
    , m_aData(rData)
    , m_aPropSet(lcl_GetDataSequencePropertyMap())
{
    if (m_pDocument)
        m_pDocument->AddUnoObject(*this);
}

PivotTableDataSequence::~PivotTableDataSequence()
{
    SolarMutexGuard g;

    if (m_pDocument)
        m_pDocument->RemoveUnoObject(*this);
}

void PivotTableDataSequence::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
{
    if (rHint.GetId() == SfxHintId::Dying)
    {
        m_pDocument = nullptr;
    }
}

uno::Sequence<uno::Any> SAL_CALL PivotTableDataSequence::getData()
{
    SolarMutexGuard aGuard;

    if (!m_pDocument)
        throw uno::RuntimeException();

    uno::Sequence<uno::Any> aSeq(m_aData.size());

    size_t i = 0;
    for (ValueAndFormat const & rItem : m_aData)
    {
        if (rItem.m_bIsValue)
            aSeq[i] <<= double(rItem.m_fValue);
        else
            aSeq[i] <<= OUString(rItem.m_aString);
        i++;
    }
    return aSeq;
}

// XNumericalDataSequence --------------------------------------------------

uno::Sequence<double> SAL_CALL PivotTableDataSequence::getNumericalData()
{
    SolarMutexGuard aGuard;
    if (!m_pDocument)
        throw uno::RuntimeException();

    uno::Sequence<double> aSeq(m_aData.size());

    size_t i = 0;
    for (ValueAndFormat const & rItem : m_aData)
    {
        aSeq[i] = rItem.m_fValue;
        i++;
    }
    return aSeq;
}

// XTextualDataSequence --------------------------------------------------

uno::Sequence<OUString> SAL_CALL PivotTableDataSequence::getTextualData()
{
    SolarMutexGuard aGuard;
    if (!m_pDocument)
        throw uno::RuntimeException();

    uno::Sequence<OUString> aSeq(m_aData.size());

    size_t i = 0;
    for (ValueAndFormat const & rItem : m_aData)
    {
        if (!rItem.m_bIsValue)
            aSeq[i] = rItem.m_aString;
        i++;
    }
    return aSeq;
}

OUString SAL_CALL PivotTableDataSequence::getSourceRangeRepresentation()
{
    SolarMutexGuard aGuard;

    return m_aID;
}

uno::Sequence<OUString> SAL_CALL PivotTableDataSequence::generateLabel(chart2::data::LabelOrigin /*eOrigin*/)
{
    SolarMutexGuard aGuard;
    if (!m_pDocument)
        throw uno::RuntimeException();

    uno::Sequence<OUString> aSeq;
    return aSeq;
}

sal_Int32 SAL_CALL PivotTableDataSequence::getNumberFormatKeyByIndex(sal_Int32 nIndex)
{
    SolarMutexGuard aGuard;
    if (nIndex == -1 && !m_aData.empty())
    {
        return m_aData[0].m_nNumberFormat;
    }
    else if (nIndex < 0 && size_t(nIndex) >= m_aData.size())
    {
        SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
        return 0;
    }
    return m_aData[size_t(nIndex)].m_nNumberFormat;
}

// XCloneable ================================================================

uno::Reference<util::XCloneable> SAL_CALL PivotTableDataSequence::createClone()
{
    SolarMutexGuard aGuard;

    std::unique_ptr<PivotTableDataSequence> pClone;
    pClone.reset(new PivotTableDataSequence(m_pDocument, m_sPivotTableName, m_aID, m_aData));
    pClone->setRole(m_aRole);

    uno::Reference<util::XCloneable> xClone(pClone.release());

    return xClone;
}

// XModifyBroadcaster ========================================================

void SAL_CALL PivotTableDataSequence::addModifyListener(const uno::Reference<util::XModifyListener>& aListener)
{
    SolarMutexGuard aGuard;
    m_aValueListeners.push_back(uno::Reference<util::XModifyListener>(aListener));
}

void SAL_CALL PivotTableDataSequence::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener)
{
    SolarMutexGuard aGuard;

    sal_uInt16 nCount = m_aValueListeners.size();
    for (sal_uInt16 n = nCount; n--; )
    {
        uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
        if (rObj == aListener)
        {
            m_aValueListeners.erase(m_aValueListeners.begin() + n);
        }
    }
}

// DataSequence XPropertySet -------------------------------------------------

uno::Reference< beans::XPropertySetInfo> SAL_CALL PivotTableDataSequence::getPropertySetInfo()
{
    SolarMutexGuard aGuard;
    static uno::Reference<beans::XPropertySetInfo> aRef = new SfxItemPropertySetInfo(m_aPropSet.getPropertyMap());
    return aRef;
}

void SAL_CALL PivotTableDataSequence::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
{
    if (rPropertyName == SC_UNONAME_ROLE)
    {
        if (!(rValue >>= m_aRole))
            throw lang::IllegalArgumentException();
    }
    else if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS
          || rPropertyName == SC_UNONAME_HIDDENVALUES
          || rPropertyName == SC_UNONAME_TIME_BASED
          || rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
    {}
    else
        throw beans::UnknownPropertyException();
}

uno::Any SAL_CALL PivotTableDataSequence::getPropertyValue(const OUString& rPropertyName)
{
    uno::Any aReturn;
    if (rPropertyName == SC_UNONAME_ROLE)
        aReturn <<= m_aRole;
    else if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
        aReturn <<= false;
    else if (rPropertyName == SC_UNONAME_HIDDENVALUES)
    {
        css::uno::Sequence<sal_Int32> aHiddenValues;
        aReturn <<= aHiddenValues;
    }
    else if (rPropertyName == SC_UNONAME_TIME_BASED)
    {
        aReturn <<= false;
    }
    else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
    {
        aReturn <<= false;
    }
    else
        throw beans::UnknownPropertyException();
    return aReturn;
}

void SAL_CALL PivotTableDataSequence::addPropertyChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
{
    OSL_FAIL("Not yet implemented");
}

void SAL_CALL PivotTableDataSequence::removePropertyChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
{
    OSL_FAIL("Not yet implemented");
}

void SAL_CALL PivotTableDataSequence::addVetoableChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
{
    OSL_FAIL("Not yet implemented");
}

void SAL_CALL PivotTableDataSequence::removeVetoableChangeListener(
        const OUString& /*rPropertyName*/,
        const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
{
    OSL_FAIL("Not yet implemented");
}

} // end sc namespace

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataSource.cxx b/sc/source/ui/unoobj/PivotTableDataSource.cxx
new file mode 100644
index 0000000..752f8a4
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataSource.cxx
@@ -0,0 +1,51 @@
/* -*- 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/.
 */

#include "PivotTableDataSource.hxx"

#include <sal/config.h>

#include "miscuno.hxx"
#include "docsh.hxx"

#include <comphelper/sequence.hxx>

using namespace css;

namespace sc
{

SC_SIMPLE_SERVICE_INFO(PivotTableDataSource, "PivotTableDataSource", "com.sun.star.chart2.data.DataSource")

PivotTableDataSource::PivotTableDataSource(OUString const & aRangeRepresentation,
                                           std::vector<css::uno::Reference<css::chart2::data::XLabeledDataSequence>>& xLabeledSequence)
    : m_xLabeledSequence(xLabeledSequence)
    , m_aRangeRepresentation(aRangeRepresentation)
{
}

PivotTableDataSource::~PivotTableDataSource()
{
}

void PivotTableDataSource::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& /*rHint*/)
{
}

uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence>> SAL_CALL
    PivotTableDataSource::getDataSequences()
{
    SolarMutexGuard aGuard;

    return comphelper::containerToSequence(m_xLabeledSequence);
}

} // end sc namespace

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/TablePivotChart.cxx b/sc/source/ui/unoobj/TablePivotChart.cxx
new file mode 100644
index 0000000..64d2d87
--- /dev/null
+++ b/sc/source/ui/unoobj/TablePivotChart.cxx
@@ -0,0 +1,104 @@
/* -*- 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/.
 */

#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
#include <svx/charthelper.hxx>
#include <svtools/embedhlp.hxx>

#include "miscuno.hxx"
#include "docsh.hxx"

#include "TablePivotChart.hxx"
#include "ChartTools.hxx"

using namespace css;

namespace sc
{

SC_SIMPLE_SERVICE_INFO(TablePivotChart, "TablePivotChart", "com.sun.star.table.TablePivotChart")

TablePivotChart::TablePivotChart(ScDocShell* pDocShell, SCTAB nTab, const OUString& rName)
    : TablePivotChart_Base(m_aMutex)
    , m_pDocShell(pDocShell)
    , m_nTab(nTab)
    , m_aChartName(rName)
{
    if (m_pDocShell)
        m_pDocShell->GetDocument().AddUnoObject(*this);
}

TablePivotChart::~TablePivotChart()
{
    SolarMutexGuard aGuard;

    if (m_pDocShell)
        m_pDocShell->GetDocument().RemoveUnoObject(*this);
}

void TablePivotChart::Notify(SfxBroadcaster&, const SfxHint& rHint)
{
    if (rHint.GetId() == SfxHintId::Dying)
        m_pDocShell = nullptr;
}

// XEmbeddedObjectSupplier

uno::Reference<lang::XComponent> SAL_CALL TablePivotChart::getEmbeddedObject()
{
    SolarMutexGuard aGuard;
    SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, m_aChartName, sc::tools::ChartSourceType::PIVOT_TABLE);
    if (pObject && svt::EmbeddedObjectRef::TryRunningState(pObject->GetObjRef()))
        return uno::Reference<lang::XComponent>(pObject->GetObjRef()->getComponent(), uno::UNO_QUERY);
    return nullptr;
}

// XNamed

OUString SAL_CALL TablePivotChart::getName()
{
    SolarMutexGuard aGuard;
    return m_aChartName;
}

void SAL_CALL TablePivotChart::setName(OUString const & /* aName */)
{
    SolarMutexGuard aGuard;
    throw uno::RuntimeException(); // name cannot be changed
}

// XTablePivotChart

OUString SAL_CALL TablePivotChart::getPivotTableName()
{
    SolarMutexGuard aGuard;
    OUString aPivotTableName;

    SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, m_aChartName, sc::tools::ChartSourceType::PIVOT_TABLE);

    uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
    if (xObject.is())
    {
        uno::Reference<chart2::XChartDocument> xChartDoc(xObject->getComponent(), uno::UNO_QUERY);
        if (xChartDoc.is())
        {
            uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xChartDoc->getDataProvider(), uno::UNO_QUERY);
            if (xPivotTableDataProvider.is())
            {
                aPivotTableName = xPivotTableDataProvider->getPivotTableName();
            }
        }
    }

    return aPivotTableName;
}

} // end sc namespace

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/TablePivotCharts.cxx b/sc/source/ui/unoobj/TablePivotCharts.cxx
new file mode 100644
index 0000000..e76a88b
--- /dev/null
+++ b/sc/source/ui/unoobj/TablePivotCharts.cxx
@@ -0,0 +1,279 @@
/* -*- 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/.
 */

#include <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <com/sun/star/chart2/data/XDataReceiver.hpp>
#include <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>

#include <tools/gen.hxx>
#include <svx/svditer.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdundo.hxx>
#include <svx/charthelper.hxx>
#include <sfx2/app.hxx>
#include <unotools/moduleoptions.hxx>
#include <comphelper/classids.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <tools/globname.hxx>
#include <svtools/embedhlp.hxx>
#include <comphelper/sequence.hxx>

#include "TablePivotChart.hxx"
#include "TablePivotCharts.hxx"
#include "PivotTableDataProvider.hxx"
#include "ChartTools.hxx"

#include "miscuno.hxx"
#include "docsh.hxx"
#include "drwlayer.hxx"
#include "undodat.hxx"
#include "convuno.hxx"

using namespace css;

namespace sc
{

SC_SIMPLE_SERVICE_INFO(TablePivotCharts, "TablePivotCharts", "com.sun.star.table.TablePivotCharts")

TablePivotCharts::TablePivotCharts(ScDocShell* pDocShell, SCTAB nTab)
    : m_pDocShell(pDocShell)
    , m_nTab(nTab)
{
    m_pDocShell->GetDocument().AddUnoObject(*this);
}

TablePivotCharts::~TablePivotCharts()
{
    SolarMutexGuard aGuard;

    if (m_pDocShell)
        m_pDocShell->GetDocument().RemoveUnoObject(*this);
}

void TablePivotCharts::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
{
    if (rHint.GetId() == SfxHintId::Dying)
        m_pDocShell = nullptr;
}

// XTablePivotCharts
void SAL_CALL TablePivotCharts::addNewByName(OUString const & rName,
                                             const awt::Rectangle& aRect,
                                             OUString const & rDataPilotName)
{
    SolarMutexGuard aGuard;

    if (!m_pDocShell)
        return;

    ScDocument& rDoc = m_pDocShell->GetDocument();
    ScDrawLayer* pModel = m_pDocShell->MakeDrawLayer();
    SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
    if (!pPage)
        return;

    //  chart can't be inserted if any ole object with that name exists on any table
    //  (empty string: generate valid name)

    OUString aName = rName;
    SCTAB nDummy;
    if (!aName.isEmpty() && pModel->GetNamedObject(aName, OBJ_OLE2, nDummy))
    {
        //  object exists - only RuntimeException is specified
        throw uno::RuntimeException();
    }

    uno::Reference<embed::XEmbeddedObject> xObject;

    if (SvtModuleOptions().IsChart())
        xObject = m_pDocShell->GetEmbeddedObjectContainer().CreateEmbeddedObject(SvGlobalName(SO3_SCH_CLASSID).GetByteSequence(), aName);

    if (xObject.is())
    {
            Point aRectPos(aRect.X, aRect.Y);
            bool bLayoutRTL = rDoc.IsLayoutRTL(m_nTab);
            if ((aRectPos.X() < 0 && !bLayoutRTL) || (aRectPos.X() > 0 && bLayoutRTL))
                aRectPos.X() = 0;

            if (aRectPos.Y() < 0)
                aRectPos.Y() = 0;

            Size aRectSize(aRect.Width, aRect.Height);
            if (aRectSize.Width() <= 0)
                aRectSize.Width() = 5000; // default size

            if (aRectSize.Height() <= 0)
                aRectSize.Height() = 5000;

            ::tools::Rectangle aInsRect(aRectPos, aRectSize);

            sal_Int64 nAspect(embed::Aspects::MSOLE_CONTENT);
            MapUnit aMapUnit(VCLUnoHelper::UnoEmbed2VCLMapUnit(xObject->getMapUnit(nAspect)));
            Size aSize(aInsRect.GetSize());
            aSize = vcl::Window::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
            awt::Size aAwtSize;
            aAwtSize.Width = aSize.Width();
            aAwtSize.Height = aSize.Height();

            std::unique_ptr<sc::PivotTableDataProvider> pPivotTableDataProvider(new sc::PivotTableDataProvider(&rDoc));
            pPivotTableDataProvider->setPivotTableName(rDataPilotName);

            uno::Reference<chart2::data::XDataProvider> xDataProvider(pPivotTableDataProvider.release());

            uno::Reference<chart2::data::XDataReceiver> xReceiver;
            uno::Reference<embed::XComponentSupplier> xCompSupp(xObject, uno::UNO_QUERY);

            if (xCompSupp.is())
                xReceiver.set(xCompSupp->getComponent(), uno::UNO_QUERY);

            if (xReceiver.is())
            {
                xReceiver->attachDataProvider(xDataProvider);

                uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
                xReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier);

                uno::Sequence<beans::PropertyValue> aArgs(3);
                aArgs[0] = beans::PropertyValue("CellRangeRepresentation", -1, uno::makeAny(OUString(rDataPilotName)), beans::PropertyState_DIRECT_VALUE);
                aArgs[1] = beans::PropertyValue("HasCategories", -1, uno::makeAny(true), beans::PropertyState_DIRECT_VALUE);
                aArgs[2] = beans::PropertyValue("DataRowSource", -1, uno::makeAny(chart::ChartDataRowSource_COLUMNS), beans::PropertyState_DIRECT_VALUE);
                xReceiver->setArguments(aArgs);
            }

            SdrOle2Obj* pObject = new SdrOle2Obj(svt::EmbeddedObjectRef(xObject, embed::Aspects::MSOLE_CONTENT),
                                                 aName, aInsRect);

            if (xObject.is())
                xObject->setVisualAreaSize(nAspect, aAwtSize);

            pPage->InsertObject(pObject);
            pModel->AddUndo(new SdrUndoInsertObj(*pObject));
    }
}

void SAL_CALL TablePivotCharts::removeByName(const OUString& rName)
{
    SolarMutexGuard aGuard;
    SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE);
    if (pObject)
    {
        ScDocument& rDoc = m_pDocShell->GetDocument();
        ScDrawLayer* pModel = rDoc.GetDrawLayer();
        SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
        pModel->AddUndo(new SdrUndoDelObj(*pObject));
        pPage->RemoveObject(pObject->GetOrdNum());
    }
}

// XIndexAccess
sal_Int32 SAL_CALL TablePivotCharts::getCount()
{
    SolarMutexGuard aGuard;
    sal_Int32 nCount = 0;

    if (!m_pDocShell)
        return nCount;

    sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);

    SdrOle2Obj* pOleObject = aIterator.next();
    while (pOleObject)
    {
        if (pOleObject->GetObjRef().is())
            nCount++;
        pOleObject = aIterator.next();
    }
    return nCount;
}

uno::Any SAL_CALL TablePivotCharts::getByIndex(sal_Int32 nIndex)
{
    SolarMutexGuard aGuard;
    SdrOle2Obj* pObject = sc::tools::getChartByIndex(m_pDocShell, m_nTab, nIndex,
                                                     sc::tools::ChartSourceType::PIVOT_TABLE);
    if (!pObject)
        throw lang::IndexOutOfBoundsException();

    OUString aName;
    uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
    if (xObject.is())
        aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);

    if (aName.isEmpty())
        throw lang::IndexOutOfBoundsException();

    uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, aName));
    if (xChart.is())
        return uno::makeAny(xChart);
    else
        throw lang::IndexOutOfBoundsException();
}

uno::Type SAL_CALL TablePivotCharts::getElementType()
{
    SolarMutexGuard aGuard;
    return cppu::UnoType<table::XTablePivotChart>::get();
}

sal_Bool SAL_CALL TablePivotCharts::hasElements()
{
    SolarMutexGuard aGuard;
    return getCount() != 0;
}

uno::Any SAL_CALL TablePivotCharts::getByName(OUString const & rName)
{
    SolarMutexGuard aGuard;

    if (!sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE))
        throw container::NoSuchElementException();

    uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, rName));
    if (xChart.is())
        return uno::makeAny(xChart);
    else
        throw container::NoSuchElementException();
}

uno::Sequence<OUString> SAL_CALL TablePivotCharts::getElementNames()
{
    SolarMutexGuard aGuard;

    std::vector<OUString> aElements;
    sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);

    SdrOle2Obj* pOleObject = aIterator.next();
    while (pOleObject)
    {
        uno::Reference<embed::XEmbeddedObject> xObject = pOleObject->GetObjRef();
        if (xObject.is())
        {
            OUString aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
            aElements.push_back(aName);
        }
        pOleObject = aIterator.next();
    }
    return comphelper::containerToSequence(aElements);
}

sal_Bool SAL_CALL TablePivotCharts::hasByName(OUString const & rName)
{
    SolarMutexGuard aGuard;

    return sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE) != nullptr;
}

} // end sc namespace

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx
index 0c597a8..6a4f610 100644
--- a/sc/source/ui/unoobj/cellsuno.cxx
+++ b/sc/source/ui/unoobj/cellsuno.cxx
@@ -130,6 +130,7 @@
#include "dputil.hxx"
#include <sortparam.hxx>
#include "condformatuno.hxx"
#include "TablePivotCharts.hxx"

#include <list>
#include <memory>
@@ -6726,6 +6727,7 @@ uno::Any SAL_CALL ScTableSheetObj::queryInterface( const uno::Type& rType )
    SC_QUERYINTERFACE( sheet::XSheetLinkable )
    SC_QUERYINTERFACE( sheet::XExternalSheetName )
    SC_QUERYINTERFACE( document::XEventsSupplier )
    SC_QUERYINTERFACE( table::XTablePivotChartsSupplier )

    return ScCellRangeObj::queryInterface( rType );
}
@@ -6749,7 +6751,8 @@ uno::Sequence<uno::Type> SAL_CALL ScTableSheetObj::getTypes()
        long nParentLen = aParentTypes.getLength();
        const uno::Type* pParentPtr = aParentTypes.getConstArray();

        aTypes.realloc( nParentLen + 18 );
        aTypes.realloc(nParentLen + 19);

        uno::Type* pPtr = aTypes.getArray();
        pPtr[nParentLen + 0] = cppu::UnoType<sheet::XSpreadsheet>::get();
        pPtr[nParentLen + 1] = cppu::UnoType<container::XNamed>::get();
@@ -6769,6 +6772,7 @@ uno::Sequence<uno::Type> SAL_CALL ScTableSheetObj::getTypes()
        pPtr[nParentLen +15] = cppu::UnoType<sheet::XSheetLinkable>::get();
        pPtr[nParentLen +16] = cppu::UnoType<sheet::XExternalSheetName>::get();
        pPtr[nParentLen +17] = cppu::UnoType<document::XEventsSupplier>::get();
        pPtr[nParentLen +18] = cppu::UnoType<table::XTablePivotChartsSupplier>::get();

        for (long i=0; i<nParentLen; i++)
            pPtr[i] = pParentPtr[i];                // parent types first
@@ -6808,6 +6812,17 @@ uno::Reference<table::XTableCharts> SAL_CALL ScTableSheetObj::getCharts()
    return nullptr;
}

uno::Reference<table::XTablePivotCharts> SAL_CALL ScTableSheetObj::getPivotCharts()
{
    SolarMutexGuard aGuard;
    ScDocShell* pDocSh = GetDocShell();
    if (pDocSh)
        return new sc::TablePivotCharts(pDocSh, GetTab_Impl());

    OSL_FAIL("no Document");
    return nullptr;
}

uno::Reference<sheet::XDataPilotTables> SAL_CALL ScTableSheetObj::getDataPilotTables()
{
    SolarMutexGuard aGuard;
diff --git a/sc/source/ui/unoobj/chartuno.cxx b/sc/source/ui/unoobj/chartuno.cxx
index 7815270..20c3f9e 100644
--- a/sc/source/ui/unoobj/chartuno.cxx
+++ b/sc/source/ui/unoobj/chartuno.cxx
@@ -38,6 +38,7 @@
#include <svx/charthelper.hxx>
#include <svtools/embedhlp.hxx>

#include "ChartTools.hxx"
#include "chartuno.hxx"
#include "miscuno.hxx"
#include "docsh.hxx"
@@ -48,47 +49,13 @@
#include "chart2uno.hxx"
#include "convuno.hxx"

using namespace com::sun::star;
using namespace css;

#define PROP_HANDLE_RELATED_CELLRANGES  1

SC_SIMPLE_SERVICE_INFO( ScChartObj, "ScChartObj", "com.sun.star.table.TableChart" )
SC_SIMPLE_SERVICE_INFO( ScChartsObj, "ScChartsObj", "com.sun.star.table.TableCharts" )

static SdrOle2Obj* lcl_FindChartObj( ScDocShell* pDocShell, SCTAB nTab, const OUString& rName )
{
    if (pDocShell)
    {
        ScDocument& rDoc = pDocShell->GetDocument();
        ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
        if (pDrawLayer)
        {
            SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
            OSL_ENSURE(pPage, "Page nicht gefunden");
            if (pPage)
            {
                SdrObjListIter aIter( *pPage, SdrIterMode::DeepNoGroups );
                SdrObject* pObject = aIter.Next();
                while (pObject)
                {
                    if ( pObject->GetObjIdentifier() == OBJ_OLE2 && ScDocument::IsChart(pObject) )
                    {
                        uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObject)->GetObjRef();
                        if ( xObj.is() )
                        {
                            OUString aObjName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xObj );
                            if ( aObjName == rName )
                                return static_cast<SdrOle2Obj*>(pObject);
                        }
                    }
                    pObject = aIter.Next();
                }
            }
        }
    }
    return nullptr;
}

ScChartsObj::ScChartsObj(ScDocShell* pDocSh, SCTAB nT) :
    pDocShell( pDocSh ),
    nTab( nT )
@@ -156,7 +123,7 @@ ScChartObj* ScChartsObj::GetObjectByIndex_Impl(long nIndex) const

ScChartObj* ScChartsObj::GetObjectByName_Impl(const OUString& aName) const
{
    if ( lcl_FindChartObj( pDocShell, nTab, aName ) )
    if (sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::CELL_RANGE))
        return new ScChartObj( pDocShell, nTab, aName );
    return nullptr;
}
@@ -297,7 +264,7 @@ void SAL_CALL ScChartsObj::addNewByName( const OUString& rName,
void SAL_CALL ScChartsObj::removeByName( const OUString& aName )
{
    SolarMutexGuard aGuard;
    SdrOle2Obj* pObj = lcl_FindChartObj( pDocShell, nTab, aName );
    SdrOle2Obj* pObj = sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::CELL_RANGE);
    if (pObj)
    {
        ScDocument& rDoc = pDocShell->GetDocument();
@@ -429,7 +396,9 @@ uno::Sequence<OUString> SAL_CALL ScChartsObj::getElementNames()
sal_Bool SAL_CALL ScChartsObj::hasByName( const OUString& aName )
{
    SolarMutexGuard aGuard;
    return ( lcl_FindChartObj( pDocShell, nTab, aName ) != nullptr );
    SdrOle2Obj* aOle2Obj = sc::tools::findChartsByName(pDocShell, nTab, aName,
                                                       sc::tools::ChartSourceType::CELL_RANGE);
    return aOle2Obj != nullptr;
}

ScChartObj::ScChartObj(ScDocShell* pDocSh, SCTAB nT, const OUString& rN)
@@ -742,7 +711,8 @@ void SAL_CALL ScChartObj::setRanges( const uno::Sequence<table::CellRangeAddress
uno::Reference<lang::XComponent> SAL_CALL ScChartObj::getEmbeddedObject()
{
    SolarMutexGuard aGuard;
    SdrOle2Obj* pObject = lcl_FindChartObj( pDocShell, nTab, aChartName );
    SdrOle2Obj* pObject = sc::tools::findChartsByName(pDocShell, nTab, aChartName,
                                                      sc::tools::ChartSourceType::CELL_RANGE);
    if ( pObject && svt::EmbeddedObjectRef::TryRunningState( pObject->GetObjRef() ) )
    {
        //TODO/LATER: is it OK that something is returned for *all* objects, not only own objects?
diff --git a/sc/source/ui/unoobj/servuno.cxx b/sc/source/ui/unoobj/servuno.cxx
index 6b2fac6..04fb81f 100644
--- a/sc/source/ui/unoobj/servuno.cxx
+++ b/sc/source/ui/unoobj/servuno.cxx
@@ -44,6 +44,7 @@
#include "addruno.hxx"
#include "chart2uno.hxx"
#include "tokenuno.hxx"
#include "PivotTableDataProvider.hxx"

// Support creation of GraphicObjectResolver and EmbeddedObjectResolver
#include <svx/xmleohlp.hxx>
@@ -292,6 +293,7 @@ const ProvNamesId_Type aProvNamesId[] =
    { "com.sun.star.sheet.DocumentSettings",Type::SHEETDOCSET },

    { SC_SERVICENAME_CHDATAPROV,            Type::CHDATAPROV },
    { SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER, Type::CHART_PIVOTTABLE_DATAPROVIDER },
    { SC_SERVICENAME_FORMULAPARS,           Type::FORMULAPARS },
    { SC_SERVICENAME_OPCODEMAPPER,          Type::OPCODEMAPPER },
    { "ooo.vba.VBAObjectModuleObjectProvider", Type::VBAOBJECTPROVIDER },
@@ -388,6 +390,7 @@ uno::Reference<uno::XInterface> ScServiceProvider::MakeInstance(
                                    Type nType, ScDocShell* pDocShell )
{
    uno::Reference<uno::XInterface> xRet;

    switch (nType)
    {
        case Type::SHEET:
@@ -523,6 +526,10 @@ uno::Reference<uno::XInterface> ScServiceProvider::MakeInstance(
            if (pDocShell)
                xRet = *new ScChart2DataProvider( &pDocShell->GetDocument() );
            break;
        case Type::CHART_PIVOTTABLE_DATAPROVIDER:
            if (pDocShell)
                xRet = *new sc::PivotTableDataProvider(&pDocShell->GetDocument());
            break;
        case Type::FORMULAPARS:
            if (pDocShell)
                xRet.set(static_cast<sheet::XFormulaParser*>(new ScFormulaParserObj( pDocShell )));
diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx
index 84c5665..7120412 100644
--- a/sc/source/ui/view/tabview3.cxx
+++ b/sc/source/ui/view/tabview3.cxx
@@ -2469,27 +2469,23 @@ void ScTabView::DoChartSelection(
    }
}

void ScTabView::DoDPFieldPopup(Point aPoint, Size /*aSize*/)
void ScTabView::DoDPFieldPopup(OUString const & rPivotTableName, sal_Int32 nDimensionIndex, Point aPoint, Size aSize)
{
    ScDocument& rDocument = aViewData.GetDocShell()->GetDocument();
    ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();

    if (!pWin)
        return;

    ScDPCollection* pDPs = rDocument.GetDPCollection();
    // TODO - DP name should be a parameter
    ScDPObject* pDPObj = pDPs->GetByName("DataPilot1");
    ScDPCollection* pDPCollection = rDocument.GetDPCollection();
    ScDPObject* pDPObject = pDPCollection->GetByName(rPivotTableName);

    pDPObj->BuildAllDimensionMembers();

    //const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    //bool bIsDataLayout;
    //OUString aDimName = pDPObj->GetDimName(0, bIsDataLayout);
    pDPObject->BuildAllDimensionMembers();

    Point aScreenPoint = pWin->OutputToScreenPixel(pWin->LogicToPixel(aPoint));
    //Size aScreenSize = pWin->LogicToPixel(aSize);
    Size aScreenSize = pWin->LogicToPixel(aSize);

    pWin->DPLaunchFieldPopupMenu(aScreenPoint, Size(1, 1), 1, pDPObj);
    pWin->DPLaunchFieldPopupMenu(aScreenPoint, aScreenSize, nDimensionIndex, pDPObject);
}

//  PaintGrid - repaint data range
diff --git a/sc/source/ui/view/tabvwshb.cxx b/sc/source/ui/view/tabvwshb.cxx
index 3dced27..52990c0 100644
--- a/sc/source/ui/view/tabvwshb.cxx
+++ b/sc/source/ui/view/tabvwshb.cxx
@@ -19,6 +19,8 @@

#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
#include <com/sun/star/chart2/data/XDataReceiver.hpp>
#include <com/sun/star/awt/XRequestCallback.hpp>
#include <com/sun/star/awt/Rectangle.hpp>

#include <com/sun/star/embed/EmbedMisc.hpp>
#include <com/sun/star/embed/EmbedStates.hpp>
@@ -111,10 +113,32 @@ public:
    {}

    // XCallback
    virtual void SAL_CALL notify(const css::uno::Any& /*aData*/) override
    virtual void SAL_CALL notify(const css::uno::Any& aData) override
    {
        tools::Rectangle aRect = m_pObject->GetLogicRect();
        m_pViewShell->DoDPFieldPopup(aRect.TopLeft(), aRect.GetSize());
        uno::Sequence<beans::PropertyValue> aProperties;
        if (aData >>= aProperties)
        {
            awt::Rectangle xRectangle;
            sal_Int32 dimensionIndex = 0;
            OUString sPivotTableName("DataPilot1");

            for (beans::PropertyValue const & rProperty : aProperties)
            {
                if (rProperty.Name == "Rectangle")
                    rProperty.Value >>= xRectangle;
                if (rProperty.Name == "DimensionIndex")
                    rProperty.Value >>= dimensionIndex;
                if (rProperty.Name == "PivotTableName")
                    rProperty.Value >>= sPivotTableName;
            }

            tools::Rectangle aChartRect = m_pObject->GetLogicRect();

            Point aPoint(xRectangle.X  + aChartRect.Left(), xRectangle.Y + aChartRect.Top());
            Size aSize(xRectangle.Width, xRectangle.Height);

            m_pViewShell->DoDPFieldPopup(sPivotTableName, dimensionIndex, aPoint, aSize);
        }
    }
};

@@ -209,7 +233,7 @@ void ScTabViewShell::ActivateObject( SdrOle2Obj* pObj, long nVerb )
                                new ScChartRangeSelectionListener( this ));
                            xRangeHightlighter->addSelectionChangeListener( xListener );
                        }
                        uno::Reference<chart2::data::XPopupRequest> xPopupRequest(xDataReceiver->getPopupRequest());
                        uno::Reference<awt::XRequestCallback> xPopupRequest(xDataReceiver->getPopupRequest());
                        if (xPopupRequest.is())
                        {
                            uno::Reference<awt::XCallback> xCallback(new PopupCallback(this, pObj));
diff --git a/xmloff/inc/SchXMLImport.hxx b/xmloff/inc/SchXMLImport.hxx
index 233ecde..a1c3f69 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 4ce3680..1dc1c14 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 649c9b6..11b6998 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 9b8c205..de3e32c 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 5d33fc6..10d8fc1 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 70eda52..82e3a7c 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 ));
        }

        // values
        Reference< chart2::data::XDataSequence > xSeq;
        if( bHasRange && !m_aSeriesRange.isEmpty() )
            xSeq = SchXMLTools::CreateDataSequence( m_aSeriesRange, mxNewDoc );
        Reference<chart2::data::XDataProvider> xDataProvider(mxNewDoc->getDataProvider());
        Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY);

        Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY );
        if( xSeqProp.is())
        Reference<chart2::data::XDataSequence> xSequenceValues;

        // values
        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(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 31c1ac1..f00ce12 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 5ee0ce8..166aa91 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 e8878d8..7038673 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