1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/chart/ErrorBarStyle.hpp>
21 #include <com/sun/star/chart/DataLabelPlacement.hpp>
23 #include <vcl/svapp.hxx>
24 #include <sal/log.hxx>
26 #include "ChartSeriesPanel.hxx"
27 #include <ChartController.hxx>
28 #include <ChartModel.hxx>
29 #include <ChartType.hxx>
30 #include <DataSeries.hxx>
31 #include <DataSeriesHelper.hxx>
32 #include <DiagramHelper.hxx>
33 #include <Diagram.hxx>
34 #include <RegressionCurveHelper.hxx>
35 #include <RegressionCurveModel.hxx>
36 #include <StatisticsHelper.hxx>
37 #include <BaseCoordinateSystem.hxx>
39 #include <comphelper/processfactory.hxx>
42 using namespace css::uno
;
44 namespace chart::sidebar
{
48 bool isDataLabelVisible(const rtl::Reference
<::chart::ChartModel
>& xModel
, std::u16string_view rCID
)
50 rtl::Reference
< DataSeries
> xSeries
=
51 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
56 return DataSeriesHelper::hasDataLabelsAtSeries(xSeries
);
59 void setDataLabelVisible(const rtl::Reference
<::chart::ChartModel
>& xModel
, std::u16string_view rCID
, bool bVisible
)
61 rtl::Reference
< DataSeries
> xSeries
=
62 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
68 DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints(xSeries
);
70 DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints(xSeries
);
73 struct LabelPlacementMap
79 LabelPlacementMap
const aLabelPlacementMap
[] = {
80 { 0, css::chart::DataLabelPlacement::TOP
},
81 { 1, css::chart::DataLabelPlacement::BOTTOM
},
82 { 2, css::chart::DataLabelPlacement::CENTER
},
83 { 3, css::chart::DataLabelPlacement::OUTSIDE
},
84 { 4, css::chart::DataLabelPlacement::INSIDE
},
85 { 5, css::chart::DataLabelPlacement::NEAR_ORIGIN
}
88 sal_Int32
getDataLabelPlacement(const rtl::Reference
<::chart::ChartModel
>& xModel
,
89 std::u16string_view rCID
)
91 rtl::Reference
< DataSeries
> xSeries
=
92 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
97 css::uno::Any aAny
= xSeries
->getPropertyValue("LabelPlacement");
101 sal_Int32 nPlacement
= 0;
104 for (LabelPlacementMap
const & i
: aLabelPlacementMap
)
106 if (i
.nApi
== nPlacement
)
113 void setDataLabelPlacement(const rtl::Reference
<::chart::ChartModel
>& xModel
,
114 std::u16string_view rCID
, sal_Int32 nPos
)
116 rtl::Reference
< DataSeries
> xSeries
=
117 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
123 for (LabelPlacementMap
const & i
: aLabelPlacementMap
)
132 xSeries
->setPropertyValue("LabelPlacement", css::uno::Any(nApi
));
135 bool isTrendlineVisible(const rtl::Reference
<::chart::ChartModel
>& xModel
,
136 std::u16string_view rCID
)
138 rtl::Reference
< DataSeries
> xRegressionCurveContainer
=
139 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
141 if (!xRegressionCurveContainer
.is())
144 return !xRegressionCurveContainer
->getRegressionCurves2().empty();
147 void setTrendlineVisible(const rtl::Reference
<::chart::ChartModel
>&
148 xModel
, std::u16string_view rCID
, bool bVisible
)
150 rtl::Reference
< DataSeries
> xRegressionCurveContainer
=
151 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
153 if (!xRegressionCurveContainer
.is())
158 RegressionCurveHelper::addRegressionCurve(
159 SvxChartRegress::Linear
,
160 xRegressionCurveContainer
);
163 RegressionCurveHelper::removeAllExceptMeanValueLine(
164 xRegressionCurveContainer
);
168 bool isErrorBarVisible(const rtl::Reference
<::chart::ChartModel
>& xModel
,
169 std::u16string_view rCID
, bool bYError
)
171 rtl::Reference
< DataSeries
> xSeries
=
172 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
177 return StatisticsHelper::hasErrorBars(xSeries
, bYError
);
180 void setErrorBarVisible(const rtl::Reference
<::chart::ChartModel
>&
181 xModel
, std::u16string_view rCID
, bool bYError
, bool bVisible
)
183 rtl::Reference
< DataSeries
> xSeries
=
184 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
191 StatisticsHelper::addErrorBars( xSeries
,
192 css::chart::ErrorBarStyle::STANDARD_DEVIATION
,
197 StatisticsHelper::removeErrorBars( xSeries
, bYError
);
201 bool isPrimaryAxis(const rtl::Reference
<::chart::ChartModel
>&
202 xModel
, std::u16string_view rCID
)
204 rtl::Reference
< DataSeries
> xSeries
=
205 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
210 return DataSeriesHelper::getAttachedAxisIndex(xSeries
) == 0;
213 void setAttachedAxisType(const rtl::Reference
<::chart::ChartModel
>&
214 xModel
, std::u16string_view rCID
, bool bPrimary
)
216 const rtl::Reference
<DataSeries
> xDataSeries
= ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
218 if (!xDataSeries
.is())
221 rtl::Reference
<Diagram
> xDiagram
= xModel
->getFirstChartDiagram();
222 xDiagram
->attachSeriesToAxis(bPrimary
, xDataSeries
, comphelper::getProcessComponentContext());
225 rtl::Reference
<ChartType
> getChartType(
226 const rtl::Reference
<::chart::ChartModel
>& xModel
)
228 rtl::Reference
<Diagram
> xDiagram
= xModel
->getFirstChartDiagram();
229 const std::vector
< rtl::Reference
< BaseCoordinateSystem
> > & xCooSysSequence( xDiagram
->getBaseCoordinateSystems());
230 return xCooSysSequence
[0]->getChartTypes2()[0];
233 OUString
getSeriesLabel(const rtl::Reference
<::chart::ChartModel
>& xModel
, std::u16string_view rCID
)
235 rtl::Reference
< DataSeries
> xSeries
=
236 ObjectIdentifier::getDataSeriesForCID(rCID
, xModel
);
241 rtl::Reference
<ChartType
> xChartType
= getChartType(xModel
);
242 return xSeries
->getLabelForRole(xChartType
->getRoleOfSequenceForSeriesLabel());
245 OUString
getCID(const css::uno::Reference
<css::frame::XModel
>& xModel
)
247 css::uno::Reference
<css::frame::XController
> xController(xModel
->getCurrentController());
248 css::uno::Reference
<css::view::XSelectionSupplier
> xSelectionSupplier(xController
, css::uno::UNO_QUERY
);
249 if (!xSelectionSupplier
.is())
252 uno::Any aAny
= xSelectionSupplier
->getSelection();
253 if (!aAny
.hasValue())
262 #if defined DBG_UTIL && !defined NDEBUG
263 ObjectType eType
= ObjectIdentifier::getObjectType(aCID
);
264 if (eType
!= OBJECTTYPE_DATA_SERIES
&&
265 eType
!= OBJECTTYPE_DATA_POINT
&&
266 eType
!= OBJECTTYPE_DATA_CURVE
)
267 SAL_WARN("chart2","Selected item is not a chart series");
275 ChartSeriesPanel::ChartSeriesPanel(
276 weld::Widget
* pParent
,
277 ChartController
* pController
)
278 : PanelLayout(pParent
, "ChartSeriesPanel", "modules/schart/ui/sidebarseries.ui")
279 , mxCBLabel(m_xBuilder
->weld_check_button("checkbutton_label"))
280 , mxCBTrendline(m_xBuilder
->weld_check_button("checkbutton_trendline"))
281 , mxCBXError(m_xBuilder
->weld_check_button("checkbutton_x_error"))
282 , mxCBYError(m_xBuilder
->weld_check_button("checkbutton_y_error"))
283 , mxRBPrimaryAxis(m_xBuilder
->weld_radio_button("radiobutton_primary_axis"))
284 , mxRBSecondaryAxis(m_xBuilder
->weld_radio_button("radiobutton_secondary_axis"))
285 , mxBoxLabelPlacement(m_xBuilder
->weld_widget("datalabel_box"))
286 , mxLBLabelPlacement(m_xBuilder
->weld_combo_box("comboboxtext_label"))
287 , mxFTSeriesName(m_xBuilder
->weld_label("label_series_name"))
288 , mxFTSeriesTemplate(m_xBuilder
->weld_label("label_series_tmpl"))
289 , mxModel(pController
->getChartModel())
290 , mxListener(new ChartSidebarModifyListener(this))
291 , mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_DATA_SERIES
))
297 ChartSeriesPanel::~ChartSeriesPanel()
299 doUpdateModel(nullptr);
302 mxCBTrendline
.reset();
306 mxRBPrimaryAxis
.reset();
307 mxRBSecondaryAxis
.reset();
309 mxBoxLabelPlacement
.reset();
310 mxLBLabelPlacement
.reset();
312 mxFTSeriesName
.reset();
313 mxFTSeriesTemplate
.reset();
316 void ChartSeriesPanel::Initialize()
318 mxModel
->addModifyListener(mxListener
);
319 css::uno::Reference
<css::view::XSelectionSupplier
> xSelectionSupplier(mxModel
->getCurrentController(), css::uno::UNO_QUERY
);
320 if (xSelectionSupplier
.is())
321 xSelectionSupplier
->addSelectionChangeListener(mxSelectionListener
);
325 Link
<weld::Toggleable
&,void> aLink
= LINK(this, ChartSeriesPanel
, CheckBoxHdl
);
326 mxCBLabel
->connect_toggled(aLink
);
327 mxCBTrendline
->connect_toggled(aLink
);
328 mxCBXError
->connect_toggled(aLink
);
329 mxCBYError
->connect_toggled(aLink
);
331 Link
<weld::Toggleable
&,void> aLink2
= LINK(this, ChartSeriesPanel
, RadioBtnHdl
);
332 mxRBPrimaryAxis
->connect_toggled(aLink2
);
333 mxRBSecondaryAxis
->connect_toggled(aLink2
);
335 mxLBLabelPlacement
->connect_changed(LINK(this, ChartSeriesPanel
, ListBoxHdl
));
338 void ChartSeriesPanel::updateData()
343 OUString aCID
= getCID(mxModel
);
344 ObjectType eType
= ObjectIdentifier::getObjectType(aCID
);
345 if (eType
!=OBJECTTYPE_DATA_SERIES
&&
346 eType
!= OBJECTTYPE_DATA_POINT
&&
347 eType
!= OBJECTTYPE_DATA_CURVE
)
350 SolarMutexGuard aGuard
;
351 bool bLabelVisible
= isDataLabelVisible(mxModel
, aCID
);
352 mxCBLabel
->set_active(bLabelVisible
);
353 mxCBTrendline
->set_active(isTrendlineVisible(mxModel
, aCID
));
354 mxCBXError
->set_active(isErrorBarVisible(mxModel
, aCID
, false));
355 mxCBYError
->set_active(isErrorBarVisible(mxModel
, aCID
, true));
357 bool bPrimaryAxis
= isPrimaryAxis(mxModel
, aCID
);
358 mxRBPrimaryAxis
->set_active(bPrimaryAxis
);
359 mxRBSecondaryAxis
->set_active(!bPrimaryAxis
);
361 mxBoxLabelPlacement
->set_sensitive(bLabelVisible
);
362 mxLBLabelPlacement
->set_active(getDataLabelPlacement(mxModel
, aCID
));
364 OUString aFrameLabel
= mxFTSeriesTemplate
->get_label();
365 aFrameLabel
= aFrameLabel
.replaceFirst("%1", getSeriesLabel(mxModel
, aCID
));
366 mxFTSeriesName
->set_label(aFrameLabel
);
369 std::unique_ptr
<PanelLayout
> ChartSeriesPanel::Create (
370 weld::Widget
* pParent
,
371 ChartController
* pController
)
373 if (pParent
== nullptr)
374 throw lang::IllegalArgumentException("no parent Window given to ChartSeriesPanel::Create", nullptr, 0);
376 return std::make_unique
<ChartSeriesPanel
>(pParent
, pController
);
379 void ChartSeriesPanel::DataChanged(const DataChangedEvent
& rEvent
)
381 PanelLayout::DataChanged(rEvent
);
385 void ChartSeriesPanel::HandleContextChange(
386 const vcl::EnumContext
& )
391 void ChartSeriesPanel::NotifyItemUpdate(
393 SfxItemState
/*eState*/,
394 const SfxPoolItem
* /*pState*/ )
398 void ChartSeriesPanel::modelInvalid()
400 mbModelValid
= false;
403 void ChartSeriesPanel::doUpdateModel(const rtl::Reference
<::chart::ChartModel
>& xModel
)
407 mxModel
->removeModifyListener(mxListener
);
410 css::uno::Reference
<css::view::XSelectionSupplier
> oldSelectionSupplier(
411 mxModel
->getCurrentController(), css::uno::UNO_QUERY
);
412 if (oldSelectionSupplier
.is()) {
413 oldSelectionSupplier
->removeSelectionChangeListener(mxSelectionListener
);
417 mbModelValid
= mxModel
.is();
422 mxModel
->addModifyListener(mxListener
);
424 css::uno::Reference
<css::view::XSelectionSupplier
> xSelectionSupplier(mxModel
->getCurrentController(), css::uno::UNO_QUERY
);
425 if (xSelectionSupplier
.is())
426 xSelectionSupplier
->addSelectionChangeListener(mxSelectionListener
);
429 void ChartSeriesPanel::updateModel(css::uno::Reference
<css::frame::XModel
> xModel
)
431 ::chart::ChartModel
* pModel
= dynamic_cast<::chart::ChartModel
*>(xModel
.get());
432 assert(!xModel
|| pModel
);
433 doUpdateModel(pModel
);
436 void ChartSeriesPanel::selectionChanged(bool bCorrectType
)
442 IMPL_LINK(ChartSeriesPanel
, CheckBoxHdl
, weld::Toggleable
&, rCheckBox
, void)
444 bool bChecked
= rCheckBox
.get_active();
445 OUString aCID
= getCID(mxModel
);
446 if (&rCheckBox
== mxCBLabel
.get())
447 setDataLabelVisible(mxModel
, aCID
, bChecked
);
448 else if (&rCheckBox
== mxCBTrendline
.get())
449 setTrendlineVisible(mxModel
, aCID
, bChecked
);
450 else if (&rCheckBox
== mxCBXError
.get())
451 setErrorBarVisible(mxModel
, aCID
, false, bChecked
);
452 else if (&rCheckBox
== mxCBYError
.get())
453 setErrorBarVisible(mxModel
, aCID
, true, bChecked
);
456 IMPL_LINK_NOARG(ChartSeriesPanel
, RadioBtnHdl
, weld::Toggleable
&, void)
458 OUString aCID
= getCID(mxModel
);
459 bool bChecked
= mxRBPrimaryAxis
->get_active();
461 setAttachedAxisType(mxModel
, aCID
, bChecked
);
464 IMPL_LINK_NOARG(ChartSeriesPanel
, ListBoxHdl
, weld::ComboBox
&, void)
466 OUString aCID
= getCID(mxModel
);
468 sal_Int32 nPos
= mxLBLabelPlacement
->get_active();
469 setDataLabelPlacement(mxModel
, aCID
, nPos
);
472 } // end of namespace ::chart::sidebar
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */