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 /sc | |
parent | 1931b5b01c6fdaa204d26ec4b9675dad16373cf2 (diff) |
tdf#83257 [API-CHANGE] Pivot chart implementation
This is a squashed commit of the pivot chart implementation.
Some of the changes:
- Add pivot chart specific (pivot table) data provider which
provides the data from a pivot table to the associated chart.
- When inserting a chart and the cursor is in a pivot table,
in that case insert a pivot chart
- Modify the pivot chart when the pivot table changes
- Collect and set the number format for the values
- isDataFromSpreadsheet check for the creation wizard
- In ChartView (and VLegend) check if the data provider is a
pivot chart data provider and get the pivot table field names
to create the buttons on the UI.
- Adds the functionallity to show a filter pop-up (from calc)
when clicking on row / column / page field buttons.
- Remove (X)PopupRequest as we won't need it.
- Add ODF import/export for pivot charts:
+ Added loext:data-pilot-source attribute on chart:chart
which is the internal name of the pivot table with which the
pivot chart is associated with. If the element is present, then
the it means the chart is a pivot chart, else it is a normal
chart
+ Added service to create pivot chart data provider through UNO
+ Add new methods to XPivotChartDataProvider to create value and
label data sequences separately from the data source, which is
needed for pivot chart import
+ When importing defer setting the data provider until a later
time when we know if we are creating a chart od a pivot chart
- Pivot chart ODF round-trip test
- Add table pivot chart supplier API:
This adds the XTablePivotChartSupplier and related interfaces so
we can access, create, delete pivot charts from UNO in a sheet
document. With this we now distinguish between normal charts
and pivot charts. This was mainly needed because we can't extend
the "published" interfaces of TableChartSupplier.
- Added an extensive test, which uses the API to create a new
pivot chart when there was none, and checks that the pivot chart
updates when the pivot table updates.
Change-Id: Ia9ed96fd6b1d342e61c2f7f9fa33a5e03dda21af
Reviewed-on: https://gerrit.libreoffice.org/36023
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'sc')
23 files changed, 2444 insertions, 91 deletions
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)); |