diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2017-02-26 22:48:06 +0100 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2017-04-04 13:39:29 +0000 |
commit | 9009663deb8f0862f419fd99bf0b761c7f923eff (patch) | |
tree | ea25976de0919f9d2161037d83be0eace4c1070b | |
parent | 1931b5b01c6fdaa204d26ec4b9675dad16373cf2 (diff) |
tdf#83257 [API-CHANGE] Pivot chart implementation
This is a squashed commit of the pivot chart implementation.
Some of the changes:
- Add pivot chart specific (pivot table) data provider which
provides the data from a pivot table to the associated chart.
- When inserting a chart and the cursor is in a pivot table,
in that case insert a pivot chart
- Modify the pivot chart when the pivot table changes
- Collect and set the number format for the values
- isDataFromSpreadsheet check for the creation wizard
- In ChartView (and VLegend) check if the data provider is a
pivot chart data provider and get the pivot table field names
to create the buttons on the UI.
- Adds the functionallity to show a filter pop-up (from calc)
when clicking on row / column / page field buttons.
- Remove (X)PopupRequest as we won't need it.
- Add ODF import/export for pivot charts:
+ Added loext:data-pilot-source attribute on chart:chart
which is the internal name of the pivot table with which the
pivot chart is associated with. If the element is present, then
the it means the chart is a pivot chart, else it is a normal
chart
+ Added service to create pivot chart data provider through UNO
+ Add new methods to XPivotChartDataProvider to create value and
label data sequences separately from the data source, which is
needed for pivot chart import
+ When importing defer setting the data provider until a later
time when we know if we are creating a chart od a pivot chart
- Pivot chart ODF round-trip test
- Add table pivot chart supplier API:
This adds the XTablePivotChartSupplier and related interfaces so
we can access, create, delete pivot charts from UNO in a sheet
document. With this we now distinguish between normal charts
and pivot charts. This was mainly needed because we can't extend
the "published" interfaces of TableChartSupplier.
- Added an extensive test, which uses the API to create a new
pivot chart when there was none, and checks that the pivot chart
updates when the pivot table updates.
Change-Id: Ia9ed96fd6b1d342e61c2f7f9fa33a5e03dda21af
Reviewed-on: https://gerrit.libreoffice.org/36023
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
60 files changed, 3583 insertions, 329 deletions
diff --git a/chart2/CppunitTest_chart2_pivot_chart_test.mk b/chart2/CppunitTest_chart2_pivot_chart_test.mk new file mode 100644 index 000000000000..418db1af9cc9 --- /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 f39140d61002..3273055d5373 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 29b764b6c546..63bd12667612 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 000000000000..8d1c11d0ce5d --- /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 1d2f4afe9150..b75dac6d25b5 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 Binary files differnew file mode 100644 index 000000000000..c34521e0bc52 --- /dev/null +++ b/chart2/qa/extras/data/ods/PivotChartRoundTrip.ods diff --git a/chart2/qa/extras/data/ods/PivotTableExample.ods b/chart2/qa/extras/data/ods/PivotTableExample.ods Binary files differnew file mode 100644 index 000000000000..bc8df8170208 --- /dev/null +++ b/chart2/qa/extras/data/ods/PivotTableExample.ods diff --git a/chart2/source/controller/dialogs/DialogModel.hxx b/chart2/source/controller/dialogs/DialogModel.hxx index 55251b1ad775..722ce266bc98 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 501272f5c486..b4beb73575a4 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 ); - - uno::Reference< chart2::XChartDocument > xChartDoc( m_xChartModel, uno::UNO_QUERY ); - bool bHasOwnData = (xChartDoc.is() && xChartDoc->hasInternalDataProvider()); + this->SetSizePixel(aSize); - 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 47932bb49d82..c1005f5e0ef3 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 ae579cf14b3d..d69a7a268fd2 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 fed019004716..a1fed3c8ae55 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 11dd2d832ab4..441e8da6e682 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 e564003c9e44..fb98d3d9b19d 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 814bd315928b..579a9c341eb8 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 c19aeaf7c4d6..58585018b2f0 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 2053ab09eaea..6dccabf2d74f 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<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" - }; + uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY); + if (!xPivotTableDataProvider.is()) + return; + uno::Reference<beans::XPropertySet> xModelPage(rModel.getPageBackground()); 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 698f7fcc9400..e2d9b735cefd 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 ae588d28eeac..7675b556ed5c 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 4430d298d63b..9ab65abfd195 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 49602b9555e7..ded4b7039c12 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 index 07116789b311..4d8973ff355b 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 f83ccc09a56b..000000000000 --- 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 abfbc830dd51..a7c853b1f9e6 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 000000000000..731988bc2167 --- /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 000000000000..b6c53d6fe97d --- /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 000000000000..e16b74b0ceac --- /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 000000000000..44017411c7b7 --- /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 9068e5098cc4..0a888ee0e403 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 000000000000..dc9a5c52fb5b --- /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 000000000000..8135cba9d58d --- /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 000000000000..f5e508e6dbab --- /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 000000000000..326f7c31b8a7 --- /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 000000000000..dce05e711f86 --- /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 000000000000..f60726ee2650 --- /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 aded180f3f69..95cef41b70f2 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 44049dd0f98e..e81463273c49 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 469183d18b78..6e104542f7dc 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 7f351853e575..f6cf018b0d75 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; + +namespace +{ -void lcl_ChartInit( const uno::Reference < embed::XEmbeddedObject >& xObj, ScViewData* pViewData, - const OUString& rRangeParam ) +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() ) + ScDocument* pDocument = pViewSh->GetViewData().GetDocument(); + ScDPObject* pObject = pDocument->GetDPAtCursor(pViewSh->GetViewData().GetCurX(), + pViewSh->GetViewData().GetCurY(), + pViewSh->GetViewData().GetTabNo()); + if (pObject) { - pViewSh->GetViewData().GetView()->MarkDataArea(); - bAutomaticMark = true; + aRangeString = pObject->GetName(); + bRangeIsPivotTable = true; } + else + { + bool bAutomaticMark = false; + if ( !aMark.IsMarked() && !aMark.IsMultiMarked() ) + { + pViewSh->GetViewData().GetView()->MarkDataArea(); + bAutomaticMark = true; + } - ScMarkData aMultiMark( aMark ); - aMultiMark.MarkToMulti(); + 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; + 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 ) + // get "total" range for positioning + if ( !aRanges.empty() ) { - aPositionRange.ExtendTo( *aRanges[ i ] ); + aPositionRange = *aRanges[ 0 ]; + for ( size_t i = 1, nCount = aRanges.size(); i < nCount; ++i ) + { + aPositionRange.ExtendTo( *aRanges[ i ] ); + } } - } - if(bAutomaticMark) - pViewSh->GetViewData().GetView()->Unmark(); + 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 b217c5ba0b2a..a9cccb10bbbd 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 000000000000..77818723c7aa --- /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 000000000000..84eb756c3bf3 --- /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 000000000000..da8bb26c3dc3 --- /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 000000000000..752f8a4b4efe --- /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 000000000000..64d2d87890b1 --- /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 000000000000..e76a88b05f25 --- /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 0c597a82934e..6a4f61012ba9 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 78152703066f..20c3f9e1f989 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 6b2fac6b79e8..04fb81f7776f 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 84c56659065e..71204128ce60 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"); - - pDPObj->BuildAllDimensionMembers(); + ScDPCollection* pDPCollection = rDocument.GetDPCollection(); + ScDPObject* pDPObject = pDPCollection->GetByName(rPivotTableName); - //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 3dced2749fd7..52990c0f9428 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 233ecde5b6c9..a1c3f698dca3 100644 --- a/xmloff/inc/SchXMLImport.hxx +++ b/xmloff/inc/SchXMLImport.hxx @@ -97,7 +97,8 @@ enum SchXMLChartAttrMap XML_TOK_CHART_HEIGHT, XML_TOK_CHART_STYLE_NAME, XML_TOK_CHART_COL_MAPPING, - XML_TOK_CHART_ROW_MAPPING + XML_TOK_CHART_ROW_MAPPING, + XML_TOK_CHART_DATA_PILOT_SOURCE, }; enum SchXMLPlotAreaAttrTokenMap diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx index 4ce36805398c..1dc1c145e16e 100644 --- a/xmloff/source/chart/SchXMLChartContext.cxx +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -52,11 +52,15 @@ #include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/chart2/data/XDataSink.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart2/XDataSeriesContainer.hpp> #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> #include <com/sun/star/chart2/XChartTypeContainer.hpp> #include <com/sun/star/chart2/XTitled.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/chart2/data/XDataReceiver.hpp> + using namespace com::sun::star; using namespace ::xmloff::token; using com::sun::star::uno::Reference; @@ -237,10 +241,67 @@ SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper, SchXMLChartContext::~SchXMLChartContext() {} +void lcl_setDataProvider(uno::Reference<chart2::XChartDocument> const & xChartDoc, OUString const & sDataPilotSource) +{ + if (!xChartDoc.is()) + return; + + try + { + uno::Reference<container::XChild> xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference<chart2::data::XDataReceiver> xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) + { + bool bHasOwnData = true; + + Reference<lang::XMultiServiceFactory> xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) + { + if (!xChartDoc->getDataProvider().is()) + { + bool bHasDataPilotSource = !sDataPilotSource.isEmpty(); + OUString aDataProviderServiceName("com.sun.star.chart2.data.DataProvider"); + if (bHasDataPilotSource) + aDataProviderServiceName = "com.sun.star.chart2.data.PivotTableDataProvider"; + + const uno::Sequence<OUString> aServiceNames(xFact->getAvailableServiceNames()); + + if (std::find(aServiceNames.begin(), aServiceNames.end(), aDataProviderServiceName) != aServiceNames.end()) + { + Reference<chart2::data::XDataProvider> xProvider(xFact->createInstance(aDataProviderServiceName), uno::UNO_QUERY); + + if (xProvider.is()) + { + xDataReceiver->attachDataProvider(xProvider); + if (bHasDataPilotSource) + { + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xProvider, uno::UNO_QUERY); + xPivotTableDataProvider->setPivotTableName(sDataPilotSource); + } + bHasOwnData = false; + } + } + } + else + bHasOwnData = false; + } + // else we have no parent => we have our own data + + if (bHasOwnData && ! xChartDoc->hasInternalDataProvider()) + xChartDoc->createInternalDataProvider(false); + } + } + catch (const uno::Exception & rEx) + { + OString aBStr(OUStringToOString(rEx.Message, RTL_TEXTENCODING_ASCII_US)); + SAL_INFO("xmloff.chart", "SchXMLChartContext::StartElement(): Exception caught: " << aBStr); + } +} + void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) { // parse attributes - sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap(); uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY); @@ -264,10 +325,12 @@ void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttribut switch( rAttrTokenMap.Get( nPrefix, aLocalName )) { + case XML_TOK_CHART_DATA_PILOT_SOURCE: + msDataPilotSource = aValue; + break; case XML_TOK_CHART_HREF: m_aXLinkHRefAttributeToIndicateDataProvider = aValue; break; - case XML_TOK_CHART_CLASS: { OUString sClassName; @@ -328,6 +391,11 @@ void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttribut } } + uno::Reference<chart::XChartDocument> xDoc = mrImportHelper.GetChartDocument(); + uno::Reference<chart2::XChartDocument> xNewDoc(xDoc, uno::UNO_QUERY); + + lcl_setDataProvider(xNewDoc, msDataPilotSource); + if( aOldChartTypeName.isEmpty() ) { SAL_WARN("xmloff.chart", "need a charttype to create a diagram" ); diff --git a/xmloff/source/chart/SchXMLChartContext.hxx b/xmloff/source/chart/SchXMLChartContext.hxx index 649c9b6cc387..11b69987ac93 100644 --- a/xmloff/source/chart/SchXMLChartContext.hxx +++ b/xmloff/source/chart/SchXMLChartContext.hxx @@ -104,6 +104,8 @@ private: OUString msCategoriesAddress; OUString msChartAddress; + OUString msDataPilotSource; + SeriesDefaultsAndStyles maSeriesDefaultsAndStyles; tSchXMLLSequencesPerIndex maLSequencesPerIndex; diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx index 9b8c205fa038..de3e32c7cd58 100644 --- a/xmloff/source/chart/SchXMLExport.cxx +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -90,6 +90,7 @@ #include <com/sun/star/chart2/data/XDataReceiver.hpp> #include <com/sun/star/chart2/data/XDataProvider.hpp> #include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> #include <com/sun/star/chart2/data/XTextualDataSequence.hpp> #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp> @@ -1213,6 +1214,13 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); } + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xNewDoc->getDataProvider(), uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName(); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, sPivotTableName); + } + OUString sChartType( xDiagram->getDiagramType() ); // attributes diff --git a/xmloff/source/chart/SchXMLImport.cxx b/xmloff/source/chart/SchXMLImport.cxx index 5d33fc69301b..10d8fc105b39 100644 --- a/xmloff/source/chart/SchXMLImport.cxx +++ b/xmloff/source/chart/SchXMLImport.cxx @@ -249,6 +249,7 @@ const SvXMLTokenMap& SchXMLImportHelper::GetChartAttrTokenMap() { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_CHART_STYLE_NAME }, { XML_NAMESPACE_CHART, XML_COLUMN_MAPPING, XML_TOK_CHART_COL_MAPPING }, { XML_NAMESPACE_CHART, XML_ROW_MAPPING, XML_TOK_CHART_ROW_MAPPING }, + { XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, XML_TOK_CHART_DATA_PILOT_SOURCE }, XML_TOKEN_MAP_END }; @@ -574,65 +575,37 @@ SvXMLImportContext* SchXMLImport::CreateStylesContext( return pStylesCtxt; } -void SAL_CALL SchXMLImport::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc ) +void SAL_CALL SchXMLImport::setTargetDocument(const uno::Reference<lang::XComponent>& xDoc) { - uno::Reference< chart2::XChartDocument > xOldDoc( GetModel(), uno::UNO_QUERY ); - if( xOldDoc.is() && xOldDoc->hasControllersLocked() ) + uno::Reference<chart2::XChartDocument> xOldDoc(GetModel(), uno::UNO_QUERY); + if (xOldDoc.is() && xOldDoc->hasControllersLocked()) xOldDoc->unlockControllers(); - SvXMLImport::setTargetDocument( xDoc ); + SvXMLImport::setTargetDocument(xDoc); - //set data provider and number formatter - // try to get an XDataProvider and set it - // @todo: if we have our own data, we must not use the parent as data provider - uno::Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + uno::Reference<chart2::XChartDocument> xChartDoc(GetModel(), uno::UNO_QUERY); - if( xChartDoc.is() ) + if (xChartDoc.is()) try { - //prevent rebuild of view during load ( necesarry especially if loaded not via load api, which is the case for example if binary files are loaded ) + // prevent rebuild of view during load (necesarry especially if loaded not + // via load api, which is the case for example if binary files are loaded) xChartDoc->lockControllers(); - uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY ); - uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY ); - if( xChild.is() && xDataReceiver.is()) + uno::Reference<container::XChild> xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference<chart2::data::XDataReceiver> xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) { - bool bHasOwnData = true; - - Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY ); - if( xFact.is() ) + Reference<lang::XMultiServiceFactory> xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) { //if the parent has a number formatter we will use the numberformatter of the parent - Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xFact, uno::UNO_QUERY ); - xDataReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier ); - - if ( !xChartDoc->getDataProvider().is() ) - { - const OUString aDataProviderServiceName( "com.sun.star.chart2.data.DataProvider"); - const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames()); - const OUString * pBegin = aServiceNames.getConstArray(); - const OUString * pEnd = pBegin + aServiceNames.getLength(); - if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd ) - { - Reference< chart2::data::XDataProvider > xProvider( - xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY ); - if( xProvider.is()) - { - xDataReceiver->attachDataProvider( xProvider ); - bHasOwnData = false; - } - } - } - else - bHasOwnData = false; + Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(xFact, uno::UNO_QUERY); + xDataReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier); } -// else we have no parent => we have our own data - - if( bHasOwnData && ! xChartDoc->hasInternalDataProvider() ) - xChartDoc->createInternalDataProvider( false ); } } - catch( const uno::Exception & rEx ) + catch (const uno::Exception & rEx) { OString aBStr(OUStringToOString(rEx.Message, RTL_TEXTENCODING_ASCII_US)); SAL_INFO("xmloff.chart", "SchXMLChartContext::StartElement(): Exception caught: " << aBStr); diff --git a/xmloff/source/chart/SchXMLSeries2Context.cxx b/xmloff/source/chart/SchXMLSeries2Context.cxx index 70eda5253150..82e3a7c67da7 100644 --- a/xmloff/source/chart/SchXMLSeries2Context.cxx +++ b/xmloff/source/chart/SchXMLSeries2Context.cxx @@ -30,6 +30,7 @@ #include <com/sun/star/chart2/XRegressionCurveContainer.hpp> #include <com/sun/star/chart2/data/XDataSink.hpp> #include <com/sun/star/chart2/data/XDataReceiver.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart/ChartAxisAssign.hpp> #include <com/sun/star/chart/ChartSymbolType.hpp> @@ -407,20 +408,31 @@ void SchXMLSeries2Context::StartElement( const uno::Reference< xml::sax::XAttrib uno::makeAny( true )); } + Reference<chart2::data::XDataProvider> xDataProvider(mxNewDoc->getDataProvider()); + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + + Reference<chart2::data::XDataSequence> xSequenceValues; + // values - Reference< chart2::data::XDataSequence > xSeq; - if( bHasRange && !m_aSeriesRange.isEmpty() ) - xSeq = SchXMLTools::CreateDataSequence( m_aSeriesRange, mxNewDoc ); + if (xPivotTableDataProvider.is()) // is pivot chart + { + xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex)); + } + else + { + if (bHasRange && !m_aSeriesRange.isEmpty()) + xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc); + } - Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY ); - if( xSeqProp.is()) + Reference<beans::XPropertySet> xSeqProp(xSequenceValues, uno::UNO_QUERY); + if (xSeqProp.is()) { OUString aMainRole("values-y"); - if ( maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType" ) + if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType") aMainRole = "values-size"; - xSeqProp->setPropertyValue("Role", uno::makeAny( aMainRole )); + xSeqProp->setPropertyValue("Role", uno::makeAny(aMainRole)); } - xLabeledSeq->setValues( xSeq ); + xLabeledSeq->setValues(xSequenceValues); // register for setting local data if external data provider is not present maPostponedSequences.insert( @@ -428,18 +440,24 @@ void SchXMLSeries2Context::StartElement( const uno::Reference< xml::sax::XAttrib tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq )); // label - if( !aSeriesLabelRange.isEmpty() ) + Reference<chart2::data::XDataSequence> xSequenceLabel; + + if (xPivotTableDataProvider.is()) { - Reference< chart2::data::XDataSequence > xLabelSequence = - SchXMLTools::CreateDataSequence( aSeriesLabelRange, mxNewDoc ); - xLabeledSeq->setLabel( xLabelSequence ); + xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex)); } - else if( !aSeriesLabelString.isEmpty() ) + else { - Reference< chart2::data::XDataSequence > xLabelSequence = - SchXMLTools::CreateDataSequenceWithoutConvert( aSeriesLabelString, mxNewDoc ); - xLabeledSeq->setLabel( xLabelSequence ); + if (!aSeriesLabelRange.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc)); + } + else if (!aSeriesLabelString.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc)); + } } + xLabeledSeq->setLabel(xSequenceLabel); // Note: Even if we have no label, we have to register the label // for creation, because internal data always has labels. If diff --git a/xmloff/source/chart/SchXMLTools.cxx b/xmloff/source/chart/SchXMLTools.cxx index 31c1ac161b1a..f00ce12d94f3 100644 --- a/xmloff/source/chart/SchXMLTools.cxx +++ b/xmloff/source/chart/SchXMLTools.cxx @@ -36,6 +36,7 @@ #include <com/sun/star/chart2/data/XDataProvider.hpp> #include <com/sun/star/chart2/data/XDataReceiver.hpp> #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> #include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> #include <com/sun/star/chart2/XRegressionCurveContainer.hpp> @@ -488,11 +489,21 @@ void CreateCategories( bRangeConverted = true; } } - Reference< chart2::data::XDataSequence > xSeq( - xDataProvider->createDataSequenceByRangeRepresentation( aConvertedRange )); - xLabeledSeq->setValues( xSeq ); - if( bRangeConverted ) - setXMLRangePropertyAtDataSequence( xSeq, rRangeAddress ); + + Reference<chart2::data::XDataSequence> xSequence; + Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + xSequence.set(xPivotTableDataProvider->createDataSequenceOfCategories()); + } + else + { + xSequence.set(xDataProvider->createDataSequenceByRangeRepresentation(aConvertedRange)); + if (bRangeConverted) + setXMLRangePropertyAtDataSequence(xSequence, rRangeAddress); + } + xLabeledSeq->setValues(xSequence); + } catch( const lang::IllegalArgumentException & ex ) { diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 5ee0ce8dfa84..166aa91b0a42 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -549,6 +549,7 @@ namespace xmloff { namespace token { TOKEN( "data-label-number", XML_DATA_LABEL_NUMBER ), TOKEN( "data-label-symbol", XML_DATA_LABEL_SYMBOL ), TOKEN( "data-label-text", XML_DATA_LABEL_TEXT ), + TOKEN( "data-pilot-source", XML_DATA_PILOT_SOURCE ), TOKEN( "data-pilot-field", XML_DATA_PILOT_FIELD ), TOKEN( "data-pilot-grand-total", XML_DATA_PILOT_GRAND_TOTAL ), TOKEN( "data-pilot-level", XML_DATA_PILOT_LEVEL ), diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index e8878d8ec6c1..70386737e4ed 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -471,6 +471,7 @@ data-cell-range-address data-label-number data-label-symbol data-label-text +data-pilot-source data-pilot-field data-pilot-grand-total data-pilot-level @@ -3050,4 +3051,4 @@ max-numerator-digits zeros-numerator-digits zeros-denominator-digits integer-fraction-delimiter -TOKEN_END_DUMMY
\ No newline at end of file +TOKEN_END_DUMMY |