LibreOffice Module chart2 (master) 1
ChartSeriesPanel.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <com/sun/star/chart/ErrorBarStyle.hpp>
21#include <com/sun/star/chart/DataLabelPlacement.hpp>
22
23#include <vcl/svapp.hxx>
24#include <sal/log.hxx>
25
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>
36#include <StatisticsHelper.hxx>
38
40
41using namespace css;
42using namespace css::uno;
43
44namespace chart::sidebar {
45
46namespace {
47
48bool isDataLabelVisible(const rtl::Reference<::chart::ChartModel>& xModel, std::u16string_view rCID)
49{
52
53 if (!xSeries.is())
54 return false;
55
57}
58
59void setDataLabelVisible(const rtl::Reference<::chart::ChartModel>& xModel, std::u16string_view rCID, bool bVisible)
60{
63
64 if (!xSeries.is())
65 return;
66
67 if (bVisible)
69 else
71}
72
73struct LabelPlacementMap
74{
75 sal_Int32 nPos;
76 sal_Int32 nApi;
77};
78
79LabelPlacementMap 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 }
86};
87
88sal_Int32 getDataLabelPlacement(const rtl::Reference<::chart::ChartModel>& xModel,
89 std::u16string_view rCID)
90{
93
94 if (!xSeries.is())
95 return 0;
96
97 css::uno::Any aAny = xSeries->getPropertyValue("LabelPlacement");
98 if (!aAny.hasValue())
99 return 0;
100
101 sal_Int32 nPlacement = 0;
102 aAny >>= nPlacement;
103
104 for (LabelPlacementMap const & i : aLabelPlacementMap)
105 {
106 if (i.nApi == nPlacement)
107 return i.nPos;
108 }
109
110 return 0;
111}
112
113void setDataLabelPlacement(const rtl::Reference<::chart::ChartModel>& xModel,
114 std::u16string_view rCID, sal_Int32 nPos)
115{
118
119 if (!xSeries.is())
120 return;
121
122 sal_Int32 nApi = 0;
123 for (LabelPlacementMap const & i : aLabelPlacementMap)
124 {
125 if (i.nPos == nPos)
126 {
127 nApi = i.nApi;
128 break;
129 }
130 }
131
132 xSeries->setPropertyValue("LabelPlacement", css::uno::Any(nApi));
133}
134
135bool isTrendlineVisible(const rtl::Reference<::chart::ChartModel>& xModel,
136 std::u16string_view rCID)
137{
138 rtl::Reference< DataSeries > xRegressionCurveContainer =
140
141 if (!xRegressionCurveContainer.is())
142 return false;
143
144 return !xRegressionCurveContainer->getRegressionCurves2().empty();
145}
146
147void setTrendlineVisible(const rtl::Reference<::chart::ChartModel>&
148 xModel, std::u16string_view rCID, bool bVisible)
149{
150 rtl::Reference< DataSeries > xRegressionCurveContainer =
152
153 if (!xRegressionCurveContainer.is())
154 return;
155
156 if (bVisible)
157 {
159 SvxChartRegress::Linear,
160 xRegressionCurveContainer);
161 }
162 else
164 xRegressionCurveContainer );
165
166}
167
168bool isErrorBarVisible(const rtl::Reference<::chart::ChartModel>& xModel,
169 std::u16string_view rCID, bool bYError)
170{
173
174 if (!xSeries.is())
175 return false;
176
177 return StatisticsHelper::hasErrorBars(xSeries, bYError);
178}
179
180void setErrorBarVisible(const rtl::Reference<::chart::ChartModel>&
181 xModel, std::u16string_view rCID, bool bYError, bool bVisible)
182{
185
186 if (!xSeries.is())
187 return;
188
189 if (bVisible)
190 {
192 css::chart::ErrorBarStyle::STANDARD_DEVIATION,
193 bYError);
194 }
195 else
196 {
197 StatisticsHelper::removeErrorBars( xSeries, bYError );
198 }
199}
200
201bool isPrimaryAxis(const rtl::Reference<::chart::ChartModel>&
202 xModel, std::u16string_view rCID)
203{
206
207 if (!xSeries.is())
208 return true;
209
210 return DataSeriesHelper::getAttachedAxisIndex(xSeries) == 0;
211}
212
213void setAttachedAxisType(const rtl::Reference<::chart::ChartModel>&
214 xModel, std::u16string_view rCID, bool bPrimary)
215{
217
218 if (!xDataSeries.is())
219 return;
220
221 rtl::Reference<Diagram> xDiagram = xModel->getFirstChartDiagram();
222 xDiagram->attachSeriesToAxis(bPrimary, xDataSeries, comphelper::getProcessComponentContext());
223}
224
225rtl::Reference<ChartType> getChartType(
227{
228 rtl::Reference<Diagram> xDiagram = xModel->getFirstChartDiagram();
229 const std::vector< rtl::Reference< BaseCoordinateSystem > > & xCooSysSequence( xDiagram->getBaseCoordinateSystems());
230 return xCooSysSequence[0]->getChartTypes2()[0];
231}
232
233OUString getSeriesLabel(const rtl::Reference<::chart::ChartModel>& xModel, std::u16string_view rCID)
234{
237
238 if (!xSeries.is())
239 return OUString();
240
241 rtl::Reference<ChartType> xChartType = getChartType(xModel);
242 return xSeries->getLabelForRole(xChartType->getRoleOfSequenceForSeriesLabel());
243}
244
245OUString getCID(const css::uno::Reference<css::frame::XModel>& xModel)
246{
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())
250 return OUString();
251
252 uno::Any aAny = xSelectionSupplier->getSelection();
253 if (!aAny.hasValue())
254 return OUString();
255
256 OUString aCID;
257 aAny >>= aCID;
258
259 if (aCID.isEmpty())
260 return OUString();
261
262#if defined DBG_UTIL && !defined NDEBUG
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");
268#endif
269
270 return aCID;
271}
272
273}
274
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())
291 , mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_DATA_SERIES))
292 , mbModelValid(true)
293{
294 Initialize();
295}
296
298{
299 doUpdateModel(nullptr);
300
301 mxCBLabel.reset();
302 mxCBTrendline.reset();
303 mxCBXError.reset();
304 mxCBYError.reset();
305
306 mxRBPrimaryAxis.reset();
307 mxRBSecondaryAxis.reset();
308
309 mxBoxLabelPlacement.reset();
310 mxLBLabelPlacement.reset();
311
312 mxFTSeriesName.reset();
313 mxFTSeriesTemplate.reset();
314}
315
317{
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);
322
323 updateData();
324
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);
330
331 Link<weld::Toggleable&,void> aLink2 = LINK(this, ChartSeriesPanel, RadioBtnHdl);
332 mxRBPrimaryAxis->connect_toggled(aLink2);
333 mxRBSecondaryAxis->connect_toggled(aLink2);
334
335 mxLBLabelPlacement->connect_changed(LINK(this, ChartSeriesPanel, ListBoxHdl));
336}
337
339{
340 if (!mbModelValid)
341 return;
342
343 OUString aCID = getCID(mxModel);
348 return;
349
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));
356
357 bool bPrimaryAxis = isPrimaryAxis(mxModel, aCID);
358 mxRBPrimaryAxis->set_active(bPrimaryAxis);
359 mxRBSecondaryAxis->set_active(!bPrimaryAxis);
360
361 mxBoxLabelPlacement->set_sensitive(bLabelVisible);
362 mxLBLabelPlacement->set_active(getDataLabelPlacement(mxModel, aCID));
363
364 OUString aFrameLabel = mxFTSeriesTemplate->get_label();
365 aFrameLabel = aFrameLabel.replaceFirst("%1", getSeriesLabel(mxModel, aCID));
366 mxFTSeriesName->set_label(aFrameLabel);
367}
368
369std::unique_ptr<PanelLayout> ChartSeriesPanel::Create (
370 weld::Widget* pParent,
371 ChartController* pController)
372{
373 if (pParent == nullptr)
374 throw lang::IllegalArgumentException("no parent Window given to ChartSeriesPanel::Create", nullptr, 0);
375
376 return std::make_unique<ChartSeriesPanel>(pParent, pController);
377}
378
380{
382 updateData();
383}
384
386 const vcl::EnumContext& )
387{
388 updateData();
389}
390
392 sal_uInt16 /*nSID*/,
393 SfxItemState /*eState*/,
394 const SfxPoolItem* /*pState*/ )
395{
396}
397
399{
400 mbModelValid = false;
401}
402
404{
405 if (mbModelValid)
406 {
407 mxModel->removeModifyListener(mxListener);
408 }
409
410 css::uno::Reference<css::view::XSelectionSupplier> oldSelectionSupplier(
411 mxModel->getCurrentController(), css::uno::UNO_QUERY);
412 if (oldSelectionSupplier.is()) {
413 oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener);
414 }
415
416 mxModel = xModel;
417 mbModelValid = mxModel.is();
418
419 if (!mbModelValid)
420 return;
421
422 mxModel->addModifyListener(mxListener);
423
424 css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY);
425 if (xSelectionSupplier.is())
426 xSelectionSupplier->addSelectionChangeListener(mxSelectionListener);
427}
428
429void ChartSeriesPanel::updateModel(css::uno::Reference<css::frame::XModel> xModel)
430{
431 ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get());
432 assert(!xModel || pModel);
433 doUpdateModel(pModel);
434}
435
437{
438 if (bCorrectType)
439 updateData();
440}
441
442IMPL_LINK(ChartSeriesPanel, CheckBoxHdl, weld::Toggleable&, rCheckBox, void)
443{
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);
454}
455
457{
458 OUString aCID = getCID(mxModel);
459 bool bChecked = mxRBPrimaryAxis->get_active();
460
461 setAttachedAxisType(mxModel, aCID, bChecked);
462}
463
465{
466 OUString aCID = getCID(mxModel);
467
468 sal_Int32 nPos = mxLBLabelPlacement->get_active();
469 setDataLabelPlacement(mxModel, aCID, nPos);
470}
471
472} // end of namespace ::chart::sidebar
473
474/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nPos
sal_Int32 nApi
css::uno::Reference< css::frame::XModel2 > mxModel
virtual void DataChanged(const DataChangedEvent &rEvent)
static rtl::Reference< ::chart::DataSeries > getDataSeriesForCID(std::u16string_view rObjectCID, const rtl::Reference<::chart::ChartModel > &xChartModel)
ObjectType getObjectType() const
ChartSeriesPanel(weld::Widget *pParent, ChartController *pController)
std::unique_ptr< weld::Label > mxFTSeriesName
std::unique_ptr< weld::CheckButton > mxCBLabel
virtual void updateData() override
virtual void DataChanged(const DataChangedEvent &rEvent) override
static std::unique_ptr< PanelLayout > Create(weld::Widget *pParent, ChartController *pController)
std::unique_ptr< weld::Label > mxFTSeriesTemplate
virtual void modelInvalid() override
virtual void NotifyItemUpdate(const sal_uInt16 nSId, const SfxItemState eState, const SfxPoolItem *pState) override
std::unique_ptr< weld::CheckButton > mxCBYError
css::uno::Reference< css::util::XModifyListener > mxListener
void doUpdateModel(rtl::Reference<::chart::ChartModel > xModel)
css::uno::Reference< css::view::XSelectionChangeListener > mxSelectionListener
std::unique_ptr< weld::ComboBox > mxLBLabelPlacement
std::unique_ptr< weld::CheckButton > mxCBXError
std::unique_ptr< weld::RadioButton > mxRBPrimaryAxis
virtual void updateModel(css::uno::Reference< css::frame::XModel > xModel) override
std::unique_ptr< weld::RadioButton > mxRBSecondaryAxis
rtl::Reference<::chart::ChartModel > mxModel
std::unique_ptr< weld::Widget > mxBoxLabelPlacement
virtual void HandleContextChange(const vcl::EnumContext &rContext) override
virtual void selectionChanged(bool bCorrectType) override
std::unique_ptr< weld::CheckButton > mxCBTrendline
Reference< script::XScriptListener > mxListener
DocumentType eType
#define SAL_WARN(area, stream)
OOO_DLLPUBLIC_CHARTTOOLS bool hasDataLabelsAtSeries(const rtl::Reference< ::chart::DataSeries > &xSeries)
OOO_DLLPUBLIC_CHARTTOOLS void insertDataLabelsToSeriesAndAllPoints(const rtl::Reference< ::chart::DataSeries > &xSeries)
OOO_DLLPUBLIC_CHARTTOOLS void deleteDataLabelsFromSeriesAndAllPoints(const rtl::Reference< ::chart::DataSeries > &xSeries)
OOO_DLLPUBLIC_CHARTTOOLS sal_Int32 getAttachedAxisIndex(const rtl::Reference< ::chart::DataSeries > &xSeries)
OOO_DLLPUBLIC_CHARTTOOLS bool removeAllExceptMeanValueLine(rtl::Reference<::chart::DataSeries > const &xCurveContainer)
OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel > addRegressionCurve(SvxChartRegress eType, css::uno::Reference< css::chart2::XRegressionCurveContainer > const &xCurveContainer, const css::uno::Reference< css::beans::XPropertySet > &xPropertySource=css::uno::Reference< css::beans::XPropertySet >(), const css::uno::Reference< css::beans::XPropertySet > &xEquationProperties=css::uno::Reference< css::beans::XPropertySet >())
OOO_DLLPUBLIC_CHARTTOOLS void removeErrorBars(const rtl::Reference< ::chart::DataSeries > &xDataSeries, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS bool hasErrorBars(const rtl::Reference< ::chart::DataSeries > &xDataSeries, bool bYError=true)
OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::beans::XPropertySet > addErrorBars(const rtl::Reference< ::chart::DataSeries > &xDataSeries, sal_Int32 nStyle, bool bYError=true)
IMPL_LINK_NOARG(ChartAxisPanel, ListBoxHdl, weld::ComboBox &, void)
IMPL_LINK(ChartAxisPanel, CheckBoxHdl, weld::Toggleable &, rCheckbox, void)
@ OBJECTTYPE_DATA_SERIES
@ OBJECTTYPE_DATA_POINT
@ OBJECTTYPE_DATA_CURVE
Reference< XComponentContext > getProcessComponentContext()
int i
ObjectType
SfxItemState
bool hasValue()
Reference< XController > xController
Reference< XModel > xModel