diff options
Diffstat (limited to 'chart2/source/controller/sidebar/ChartSeriesPanel.cxx')
-rw-r--r-- | chart2/source/controller/sidebar/ChartSeriesPanel.cxx | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/chart2/source/controller/sidebar/ChartSeriesPanel.cxx b/chart2/source/controller/sidebar/ChartSeriesPanel.cxx new file mode 100644 index 000000000..abc45c555 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSeriesPanel.cxx @@ -0,0 +1,488 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/chart/ErrorBarStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> +#include <com/sun/star/chart2/XRegressionCurveContainer.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> + +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + +#include "ChartSeriesPanel.hxx" +#include <ChartController.hxx> + +#include <DataSeriesHelper.hxx> +#include <RegressionCurveHelper.hxx> +#include <StatisticsHelper.hxx> + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +bool isDataLabelVisible(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rCID) +{ + css::uno::Reference< css::chart2::XDataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return false; + + return DataSeriesHelper::hasDataLabelsAtSeries(xSeries); +} + +void setDataLabelVisible(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rCID, bool bVisible) +{ + css::uno::Reference< css::chart2::XDataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + if (bVisible) + DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints(xSeries); + else + DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints(xSeries); +} + +struct LabelPlacementMap +{ + sal_Int32 nPos; + sal_Int32 nApi; +}; + +static LabelPlacementMap const aLabelPlacementMap[] = { + { 0, css::chart::DataLabelPlacement::TOP }, + { 1, css::chart::DataLabelPlacement::BOTTOM }, + { 2, css::chart::DataLabelPlacement::CENTER }, + { 3, css::chart::DataLabelPlacement::OUTSIDE }, + { 4, css::chart::DataLabelPlacement::INSIDE }, + { 5, css::chart::DataLabelPlacement::NEAR_ORIGIN } +}; + +sal_Int32 getDataLabelPlacement(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference< css::beans::XPropertySet > xSeries( + ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY ); + + if (!xSeries.is()) + return 0; + + css::uno::Any aAny = xSeries->getPropertyValue("LabelPlacement"); + if (!aAny.hasValue()) + return 0; + + sal_Int32 nPlacement = 0; + aAny >>= nPlacement; + + for (LabelPlacementMap const & i : aLabelPlacementMap) + { + if (i.nApi == nPlacement) + return i.nPos; + } + + return 0; +} + +void setDataLabelPlacement(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rCID, sal_Int32 nPos) +{ + css::uno::Reference< css::beans::XPropertySet > xSeries( + ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY ); + + if (!xSeries.is()) + return; + + sal_Int32 nApi = 0; + for (LabelPlacementMap const & i : aLabelPlacementMap) + { + if (i.nPos == nPos) + { + nApi = i.nApi; + break; + } + } + + xSeries->setPropertyValue("LabelPlacement", css::uno::Any(nApi)); +} + +bool isTrendlineVisible(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference< css::chart2::XRegressionCurveContainer > xRegressionCurveContainer( + ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY ); + + if (!xRegressionCurveContainer.is()) + return false; + + return xRegressionCurveContainer->getRegressionCurves().hasElements(); +} + +void setTrendlineVisible(const css::uno::Reference<css::frame::XModel>& + xModel, const OUString& rCID, bool bVisible) +{ + css::uno::Reference< css::chart2::XRegressionCurveContainer > xRegressionCurveContainer( + ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY ); + + if (!xRegressionCurveContainer.is()) + return; + + if (bVisible) + { + RegressionCurveHelper::addRegressionCurve( + SvxChartRegress::Linear, + xRegressionCurveContainer); + } + else + RegressionCurveHelper::removeAllExceptMeanValueLine( + xRegressionCurveContainer ); + +} + +bool isErrorBarVisible(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rCID, bool bYError) +{ + css::uno::Reference< css::chart2::XDataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return false; + + return StatisticsHelper::hasErrorBars(xSeries, bYError); +} + +void setErrorBarVisible(const css::uno::Reference<css::frame::XModel>& + xModel, const OUString& rCID, bool bYError, bool bVisible) +{ + css::uno::Reference< css::chart2::XDataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + if (bVisible) + { + StatisticsHelper::addErrorBars( xSeries, + css::chart::ErrorBarStyle::STANDARD_DEVIATION, + bYError); + } + else + { + StatisticsHelper::removeErrorBars( xSeries, bYError ); + } +} + +bool isPrimaryAxis(const css::uno::Reference<css::frame::XModel>& + xModel, const OUString& rCID) +{ + css::uno::Reference< css::chart2::XDataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return true; + + return DataSeriesHelper::getAttachedAxisIndex(xSeries) == 0; +} + +void setAttachedAxisType(const css::uno::Reference<css::frame::XModel>& + xModel, const OUString& rCID, bool bPrimary) +{ + css::uno::Reference< css::beans::XPropertySet > xSeries( + ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY ); + + if (!xSeries.is()) + return; + + sal_Int32 nIndex = bPrimary ? 0 : 1; + xSeries->setPropertyValue("AttachedAxisIndex", css::uno::Any(nIndex)); +} + +css::uno::Reference<css::chart2::XChartType> getChartType( + const css::uno::Reference<css::frame::XModel>& xModel) +{ + css::uno::Reference<css::chart2::XChartDocument> xChartDoc (xModel, css::uno::UNO_QUERY); + css::uno::Reference<css::chart2::XDiagram> xDiagram = xChartDoc->getFirstDiagram(); + css::uno::Reference< css::chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, UNO_QUERY_THROW ); + css::uno::Sequence< css::uno::Reference< css::chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems()); + css::uno::Reference< css::chart2::XChartTypeContainer > xChartTypeContainer( xCooSysSequence[0], UNO_QUERY_THROW ); + css::uno::Sequence< css::uno::Reference< css::chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() ); + return xChartTypeSequence[0]; +} + +OUString getSeriesLabel(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rCID) +{ + css::uno::Reference< css::chart2::XDataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return OUString(); + + css::uno::Reference<css::chart2::XChartType> xChartType = getChartType(xModel); + return DataSeriesHelper::getDataSeriesLabel(xSeries, xChartType->getRoleOfSequenceForSeriesLabel()); +} + +OUString getCID(const css::uno::Reference<css::frame::XModel>& xModel) +{ + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + return OUString(); + + OUString aCID; + aAny >>= aCID; + + if (aCID.isEmpty()) + return OUString(); + +#if defined DBG_UTIL && !defined NDEBUG + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType != OBJECTTYPE_DATA_SERIES && + eType != OBJECTTYPE_DATA_POINT && + eType != OBJECTTYPE_DATA_CURVE) + SAL_WARN("chart2","Selected item is not a chart series"); +#endif + + return aCID; +} + +} + +ChartSeriesPanel::ChartSeriesPanel( + vcl::Window* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController) + : PanelLayout(pParent, "ChartSeriesPanel", "modules/schart/ui/sidebarseries.ui", rxFrame) + , mxCBLabel(m_xBuilder->weld_check_button("checkbutton_label")) + , mxCBTrendline(m_xBuilder->weld_check_button("checkbutton_trendline")) + , mxCBXError(m_xBuilder->weld_check_button("checkbutton_x_error")) + , mxCBYError(m_xBuilder->weld_check_button("checkbutton_y_error")) + , mxRBPrimaryAxis(m_xBuilder->weld_radio_button("radiobutton_primary_axis")) + , mxRBSecondaryAxis(m_xBuilder->weld_radio_button("radiobutton_secondary_axis")) + , mxBoxLabelPlacement(m_xBuilder->weld_widget("datalabel_box")) + , mxLBLabelPlacement(m_xBuilder->weld_combo_box("comboboxtext_label")) + , mxFTSeriesName(m_xBuilder->weld_label("label_series_name")) + , mxFTSeriesTemplate(m_xBuilder->weld_label("label_series_tmpl")) + , mxModel(pController->getModel()) + , mxListener(new ChartSidebarModifyListener(this)) + , mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_DATA_SERIES)) + , mbModelValid(true) +{ + Initialize(); +} + +ChartSeriesPanel::~ChartSeriesPanel() +{ + disposeOnce(); +} + +void ChartSeriesPanel::dispose() +{ + css::uno::Reference<css::util::XModifyBroadcaster> xBroadcaster(mxModel, css::uno::UNO_QUERY_THROW); + xBroadcaster->removeModifyListener(mxListener); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + + mxCBLabel.reset(); + mxCBTrendline.reset(); + mxCBXError.reset(); + mxCBYError.reset(); + + mxRBPrimaryAxis.reset(); + mxRBSecondaryAxis.reset(); + + mxBoxLabelPlacement.reset(); + mxLBLabelPlacement.reset(); + + mxFTSeriesName.reset(); + mxFTSeriesTemplate.reset(); + + PanelLayout::dispose(); +} + +void ChartSeriesPanel::Initialize() +{ + css::uno::Reference<css::util::XModifyBroadcaster> xBroadcaster(mxModel, css::uno::UNO_QUERY_THROW); + xBroadcaster->addModifyListener(mxListener); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + updateData(); + + Link<weld::ToggleButton&,void> aLink = LINK(this, ChartSeriesPanel, CheckBoxHdl); + mxCBLabel->connect_toggled(aLink); + mxCBTrendline->connect_toggled(aLink); + mxCBXError->connect_toggled(aLink); + mxCBYError->connect_toggled(aLink); + + Link<weld::ToggleButton&,void> aLink2 = LINK(this, ChartSeriesPanel, RadioBtnHdl); + mxRBPrimaryAxis->connect_toggled(aLink2); + mxRBSecondaryAxis->connect_toggled(aLink2); + + mxLBLabelPlacement->connect_changed(LINK(this, ChartSeriesPanel, ListBoxHdl)); +} + +void ChartSeriesPanel::updateData() +{ + if (!mbModelValid) + return; + + OUString aCID = getCID(mxModel); + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType!=OBJECTTYPE_DATA_SERIES && + eType != OBJECTTYPE_DATA_POINT && + eType != OBJECTTYPE_DATA_CURVE) + return; + + SolarMutexGuard aGuard; + bool bLabelVisible = isDataLabelVisible(mxModel, aCID); + mxCBLabel->set_active(bLabelVisible); + mxCBTrendline->set_active(isTrendlineVisible(mxModel, aCID)); + mxCBXError->set_active(isErrorBarVisible(mxModel, aCID, false)); + mxCBYError->set_active(isErrorBarVisible(mxModel, aCID, true)); + + bool bPrimaryAxis = isPrimaryAxis(mxModel, aCID); + mxRBPrimaryAxis->set_active(bPrimaryAxis); + mxRBSecondaryAxis->set_active(!bPrimaryAxis); + + mxBoxLabelPlacement->set_sensitive(bLabelVisible); + mxLBLabelPlacement->set_active(getDataLabelPlacement(mxModel, aCID)); + + OUString aFrameLabel = mxFTSeriesTemplate->get_label(); + aFrameLabel = aFrameLabel.replaceFirst("%1", getSeriesLabel(mxModel, aCID)); + mxFTSeriesName->set_label(aFrameLabel); +} + +VclPtr<vcl::Window> ChartSeriesPanel::Create ( + vcl::Window* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartSeriesPanel::Create", nullptr, 0); + if ( ! rxFrame.is()) + throw lang::IllegalArgumentException("no XFrame given to ChartSeriesPanel::Create", nullptr, 1); + + return VclPtr<ChartSeriesPanel>::Create( + pParent, rxFrame, pController); +} + +void ChartSeriesPanel::DataChanged( + const DataChangedEvent& ) +{ + updateData(); +} + +void ChartSeriesPanel::HandleContextChange( + const vcl::EnumContext& ) +{ + updateData(); +} + +void ChartSeriesPanel::NotifyItemUpdate( + sal_uInt16 /*nSID*/, + SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/ ) +{ +} + +void ChartSeriesPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartSeriesPanel::updateModel( + css::uno::Reference<css::frame::XModel> xModel) +{ + if (mbModelValid) + { + css::uno::Reference<css::util::XModifyBroadcaster> xBroadcaster(mxModel, css::uno::UNO_QUERY_THROW); + xBroadcaster->removeModifyListener(mxListener); + } + + css::uno::Reference<css::view::XSelectionSupplier> oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener.get()); + } + + mxModel = xModel; + mbModelValid = true; + + css::uno::Reference<css::util::XModifyBroadcaster> xBroadcasterNew(mxModel, css::uno::UNO_QUERY_THROW); + xBroadcasterNew->addModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartSeriesPanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +IMPL_LINK(ChartSeriesPanel, CheckBoxHdl, weld::ToggleButton&, rCheckBox, void) +{ + bool bChecked = rCheckBox.get_active(); + OUString aCID = getCID(mxModel); + if (&rCheckBox == mxCBLabel.get()) + setDataLabelVisible(mxModel, aCID, bChecked); + else if (&rCheckBox == mxCBTrendline.get()) + setTrendlineVisible(mxModel, aCID, bChecked); + else if (&rCheckBox == mxCBXError.get()) + setErrorBarVisible(mxModel, aCID, false, bChecked); + else if (&rCheckBox == mxCBYError.get()) + setErrorBarVisible(mxModel, aCID, true, bChecked); +} + +IMPL_LINK_NOARG(ChartSeriesPanel, RadioBtnHdl, weld::ToggleButton&, void) +{ + OUString aCID = getCID(mxModel); + bool bChecked = mxRBPrimaryAxis->get_active(); + + setAttachedAxisType(mxModel, aCID, bChecked); +} + +IMPL_LINK_NOARG(ChartSeriesPanel, ListBoxHdl, weld::ComboBox&, void) +{ + OUString aCID = getCID(mxModel); + + sal_Int32 nPos = mxLBLabelPlacement->get_active(); + setDataLabelPlacement(mxModel, aCID, nPos); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |