vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / chart2 / source / controller / sidebar / ChartSeriesPanel.cxx
blob36b5dc2957bb4128c5204a12684e4e43fe3b9cce
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/beans/XPropertySet.hpp>
22 #include <com/sun/star/chart/DataLabelPlacement.hpp>
23 #include <com/sun/star/chart2/XChartDocument.hpp>
24 #include <com/sun/star/chart2/XDataSeries.hpp>
25 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
26 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
27 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
28 #include <com/sun/star/util/XModifyBroadcaster.hpp>
30 #include <sal/log.hxx>
31 #include "ChartSeriesPanel.hxx"
32 #include <ChartController.hxx>
33 #include <vcl/fixed.hxx>
34 #include <vcl/lstbox.hxx>
36 #include <DataSeriesHelper.hxx>
37 #include <RegressionCurveHelper.hxx>
38 #include <StatisticsHelper.hxx>
40 using namespace css;
41 using namespace css::uno;
43 namespace chart { namespace sidebar {
45 namespace {
47 bool isDataLabelVisible(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rCID)
49 css::uno::Reference< css::chart2::XDataSeries > xSeries =
50 ObjectIdentifier::getDataSeriesForCID(rCID, xModel);
52 if (!xSeries.is())
53 return false;
55 return DataSeriesHelper::hasDataLabelsAtSeries(xSeries);
58 void setDataLabelVisible(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rCID, bool bVisible)
60 css::uno::Reference< css::chart2::XDataSeries > xSeries =
61 ObjectIdentifier::getDataSeriesForCID(rCID, xModel);
63 if (!xSeries.is())
64 return;
66 if (bVisible)
67 DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints(xSeries);
68 else
69 DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints(xSeries);
72 struct LabelPlacementMap
74 sal_Int32 nPos;
75 sal_Int32 nApi;
78 static LabelPlacementMap const aLabelPlacementMap[] = {
79 { 0, css::chart::DataLabelPlacement::TOP },
80 { 1, css::chart::DataLabelPlacement::BOTTOM },
81 { 2, css::chart::DataLabelPlacement::CENTER },
82 { 3, css::chart::DataLabelPlacement::OUTSIDE },
83 { 4, css::chart::DataLabelPlacement::INSIDE },
84 { 5, css::chart::DataLabelPlacement::NEAR_ORIGIN }
87 sal_Int32 getDataLabelPlacement(const css::uno::Reference<css::frame::XModel>& xModel,
88 const OUString& rCID)
90 css::uno::Reference< css::beans::XPropertySet > xSeries(
91 ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY );
93 if (!xSeries.is())
94 return 0;
96 css::uno::Any aAny = xSeries->getPropertyValue("LabelPlacement");
97 if (!aAny.hasValue())
98 return 0;
100 sal_Int32 nPlacement = 0;
101 aAny >>= nPlacement;
103 for (LabelPlacementMap const & i : aLabelPlacementMap)
105 if (i.nApi == nPlacement)
106 return i.nPos;
109 return 0;
112 void setDataLabelPlacement(const css::uno::Reference<css::frame::XModel>& xModel,
113 const OUString& rCID, sal_Int32 nPos)
115 css::uno::Reference< css::beans::XPropertySet > xSeries(
116 ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY );
118 if (!xSeries.is())
119 return;
121 sal_Int32 nApi = 0;
122 for (LabelPlacementMap const & i : aLabelPlacementMap)
124 if (i.nPos == nPos)
126 nApi = i.nApi;
127 break;
131 xSeries->setPropertyValue("LabelPlacement", css::uno::Any(nApi));
134 bool isTrendlineVisible(const css::uno::Reference<css::frame::XModel>& xModel,
135 const OUString& rCID)
137 css::uno::Reference< css::chart2::XRegressionCurveContainer > xRegressionCurveContainer(
138 ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY );
140 if (!xRegressionCurveContainer.is())
141 return false;
143 return xRegressionCurveContainer->getRegressionCurves().hasElements();
146 void setTrendlineVisible(const css::uno::Reference<css::frame::XModel>&
147 xModel, const OUString& rCID, bool bVisible)
149 css::uno::Reference< css::chart2::XRegressionCurveContainer > xRegressionCurveContainer(
150 ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY );
152 if (!xRegressionCurveContainer.is())
153 return;
155 if (bVisible)
157 RegressionCurveHelper::addRegressionCurve(
158 SvxChartRegress::Linear,
159 xRegressionCurveContainer);
161 else
162 RegressionCurveHelper::removeAllExceptMeanValueLine(
163 xRegressionCurveContainer );
167 bool isErrorBarVisible(const css::uno::Reference<css::frame::XModel>& xModel,
168 const OUString& rCID, bool bYError)
170 css::uno::Reference< css::chart2::XDataSeries > xSeries =
171 ObjectIdentifier::getDataSeriesForCID(rCID, xModel);
173 if (!xSeries.is())
174 return false;
176 return StatisticsHelper::hasErrorBars(xSeries, bYError);
179 void setErrorBarVisible(const css::uno::Reference<css::frame::XModel>&
180 xModel, const OUString& rCID, bool bYError, bool bVisible)
182 css::uno::Reference< css::chart2::XDataSeries > xSeries =
183 ObjectIdentifier::getDataSeriesForCID(rCID, xModel);
185 if (!xSeries.is())
186 return;
188 if (bVisible)
190 StatisticsHelper::addErrorBars( xSeries,
191 css::chart::ErrorBarStyle::STANDARD_DEVIATION,
192 bYError);
194 else
196 StatisticsHelper::removeErrorBars( xSeries, bYError );
200 bool isPrimaryAxis(const css::uno::Reference<css::frame::XModel>&
201 xModel, const OUString& rCID)
203 css::uno::Reference< css::chart2::XDataSeries > xSeries =
204 ObjectIdentifier::getDataSeriesForCID(rCID, xModel);
206 if (!xSeries.is())
207 return true;
209 return DataSeriesHelper::getAttachedAxisIndex(xSeries) == 0;
212 void setAttachedAxisType(const css::uno::Reference<css::frame::XModel>&
213 xModel, const OUString& rCID, bool bPrimary)
215 css::uno::Reference< css::beans::XPropertySet > xSeries(
216 ObjectIdentifier::getDataSeriesForCID(rCID, xModel), uno::UNO_QUERY );
218 if (!xSeries.is())
219 return;
221 sal_Int32 nIndex = bPrimary ? 0 : 1;
222 xSeries->setPropertyValue("AttachedAxisIndex", css::uno::Any(nIndex));
225 css::uno::Reference<css::chart2::XChartType> getChartType(
226 const css::uno::Reference<css::frame::XModel>& xModel)
228 css::uno::Reference<css::chart2::XChartDocument> xChartDoc (xModel, css::uno::UNO_QUERY);
229 css::uno::Reference<css::chart2::XDiagram> xDiagram = xChartDoc->getFirstDiagram();
230 css::uno::Reference< css::chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, UNO_QUERY_THROW );
231 css::uno::Sequence< css::uno::Reference< css::chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems());
232 css::uno::Reference< css::chart2::XChartTypeContainer > xChartTypeContainer( xCooSysSequence[0], UNO_QUERY_THROW );
233 css::uno::Sequence< css::uno::Reference< css::chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() );
234 return xChartTypeSequence[0];
237 OUString getSeriesLabel(const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rCID)
239 css::uno::Reference< css::chart2::XDataSeries > xSeries =
240 ObjectIdentifier::getDataSeriesForCID(rCID, xModel);
242 if (!xSeries.is())
243 return OUString();
245 css::uno::Reference<css::chart2::XChartType> xChartType = getChartType(xModel);
246 return DataSeriesHelper::getDataSeriesLabel(xSeries, xChartType->getRoleOfSequenceForSeriesLabel());
249 OUString getCID(const css::uno::Reference<css::frame::XModel>& xModel)
251 css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController());
252 css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY);
253 if (!xSelectionSupplier.is())
254 return OUString();
256 uno::Any aAny = xSelectionSupplier->getSelection();
257 if (!aAny.hasValue())
258 return OUString();
260 OUString aCID;
261 aAny >>= aCID;
263 if (aCID.isEmpty())
264 return OUString();
266 #if defined DBG_UTIL && !defined NDEBUG
267 ObjectType eType = ObjectIdentifier::getObjectType(aCID);
268 if (eType != OBJECTTYPE_DATA_SERIES &&
269 eType != OBJECTTYPE_DATA_POINT &&
270 eType != OBJECTTYPE_DATA_CURVE)
271 SAL_WARN("chart2","Selected item is not a chart series");
272 #endif
274 return aCID;
279 ChartSeriesPanel::ChartSeriesPanel(
280 vcl::Window* pParent,
281 const css::uno::Reference<css::frame::XFrame>& rxFrame,
282 ChartController* pController)
283 : PanelLayout(pParent, "ChartSeriesPanel", "modules/schart/ui/sidebarseries.ui", rxFrame),
284 mxModel(pController->getModel()),
285 mxListener(new ChartSidebarModifyListener(this)),
286 mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_DATA_SERIES)),
287 mbModelValid(true)
289 get(mpCBLabel, "checkbutton_label");
290 get(mpCBTrendline, "checkbutton_trendline");
291 get(mpCBXError, "checkbutton_x_error");
292 get(mpCBYError, "checkbutton_y_error");
294 get(mpRBPrimaryAxis, "radiobutton_primary_axis");
295 get(mpRBSecondaryAxis, "radiobutton_secondary_axis");
297 get(mpBoxLabelPlacement, "datalabel_box");
298 get(mpLBLabelPlacement, "comboboxtext_label");
300 get(mpFTSeriesName, "label_series_name");
301 get(mpFTSeriesTemplate, "label_series_tmpl");
303 Initialize();
306 ChartSeriesPanel::~ChartSeriesPanel()
308 disposeOnce();
311 void ChartSeriesPanel::dispose()
313 css::uno::Reference<css::util::XModifyBroadcaster> xBroadcaster(mxModel, css::uno::UNO_QUERY_THROW);
314 xBroadcaster->removeModifyListener(mxListener);
315 css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY);
316 if (xSelectionSupplier.is())
317 xSelectionSupplier->removeSelectionChangeListener(mxSelectionListener);
319 mpCBLabel.clear();
320 mpCBTrendline.clear();
321 mpCBXError.clear();
322 mpCBYError.clear();
324 mpRBPrimaryAxis.clear();
325 mpRBSecondaryAxis.clear();
327 mpBoxLabelPlacement.clear();
328 mpLBLabelPlacement.clear();
330 mpFTSeriesName.clear();
331 mpFTSeriesTemplate.clear();
333 PanelLayout::dispose();
336 void ChartSeriesPanel::Initialize()
338 css::uno::Reference<css::util::XModifyBroadcaster> xBroadcaster(mxModel, css::uno::UNO_QUERY_THROW);
339 xBroadcaster->addModifyListener(mxListener);
340 css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY);
341 if (xSelectionSupplier.is())
342 xSelectionSupplier->addSelectionChangeListener(mxSelectionListener);
344 updateData();
346 Link<Button*,void> aLink = LINK(this, ChartSeriesPanel, CheckBoxHdl);
347 mpCBLabel->SetClickHdl(aLink);
348 mpCBTrendline->SetClickHdl(aLink);
349 mpCBXError->SetClickHdl(aLink);
350 mpCBYError->SetClickHdl(aLink);
352 Link<RadioButton&,void> aLink2 = LINK(this, ChartSeriesPanel, RadioBtnHdl);
353 mpRBPrimaryAxis->SetToggleHdl(aLink2);
354 mpRBSecondaryAxis->SetToggleHdl(aLink2);
356 mpLBLabelPlacement->SetSelectHdl(LINK(this, ChartSeriesPanel, ListBoxHdl));
359 void ChartSeriesPanel::updateData()
361 if (!mbModelValid)
362 return;
364 OUString aCID = getCID(mxModel);
365 ObjectType eType = ObjectIdentifier::getObjectType(aCID);
366 if (eType!=OBJECTTYPE_DATA_SERIES &&
367 eType != OBJECTTYPE_DATA_POINT &&
368 eType != OBJECTTYPE_DATA_CURVE)
369 return;
371 SolarMutexGuard aGuard;
372 bool bLabelVisible = isDataLabelVisible(mxModel, aCID);
373 mpCBLabel->Check(bLabelVisible);
374 mpCBTrendline->Check(isTrendlineVisible(mxModel, aCID));
375 mpCBXError->Check(isErrorBarVisible(mxModel, aCID, false));
376 mpCBYError->Check(isErrorBarVisible(mxModel, aCID, true));
378 bool bPrimaryAxis = isPrimaryAxis(mxModel, aCID);
379 mpRBPrimaryAxis->Check(bPrimaryAxis);
380 mpRBSecondaryAxis->Check(!bPrimaryAxis);
382 mpBoxLabelPlacement->Enable(bLabelVisible);
383 mpLBLabelPlacement->SelectEntryPos(getDataLabelPlacement(mxModel, aCID));
385 OUString aFrameLabel = mpFTSeriesTemplate->GetText();
386 aFrameLabel = aFrameLabel.replaceFirst("%1", getSeriesLabel(mxModel, aCID));
387 mpFTSeriesName->SetText(aFrameLabel);
390 VclPtr<vcl::Window> ChartSeriesPanel::Create (
391 vcl::Window* pParent,
392 const css::uno::Reference<css::frame::XFrame>& rxFrame,
393 ChartController* pController)
395 if (pParent == nullptr)
396 throw lang::IllegalArgumentException("no parent Window given to ChartSeriesPanel::Create", nullptr, 0);
397 if ( ! rxFrame.is())
398 throw lang::IllegalArgumentException("no XFrame given to ChartSeriesPanel::Create", nullptr, 1);
400 return VclPtr<ChartSeriesPanel>::Create(
401 pParent, rxFrame, pController);
404 void ChartSeriesPanel::DataChanged(
405 const DataChangedEvent& )
407 updateData();
410 void ChartSeriesPanel::HandleContextChange(
411 const vcl::EnumContext& )
413 updateData();
416 void ChartSeriesPanel::NotifyItemUpdate(
417 sal_uInt16 /*nSID*/,
418 SfxItemState /*eState*/,
419 const SfxPoolItem* /*pState*/ )
423 void ChartSeriesPanel::modelInvalid()
425 mbModelValid = false;
428 void ChartSeriesPanel::updateModel(
429 css::uno::Reference<css::frame::XModel> xModel)
431 if (mbModelValid)
433 css::uno::Reference<css::util::XModifyBroadcaster> xBroadcaster(mxModel, css::uno::UNO_QUERY_THROW);
434 xBroadcaster->removeModifyListener(mxListener);
437 mxModel = xModel;
438 mbModelValid = true;
440 css::uno::Reference<css::util::XModifyBroadcaster> xBroadcasterNew(mxModel, css::uno::UNO_QUERY_THROW);
441 xBroadcasterNew->addModifyListener(mxListener);
443 css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY);
444 if (xSelectionSupplier.is())
445 xSelectionSupplier->addSelectionChangeListener(mxSelectionListener);
448 void ChartSeriesPanel::selectionChanged(bool bCorrectType)
450 if (bCorrectType)
451 updateData();
454 IMPL_LINK(ChartSeriesPanel, CheckBoxHdl, Button*, pButton, void)
456 CheckBox* pCheckBox = static_cast<CheckBox*>(pButton);
457 bool bChecked = pCheckBox->IsChecked();
458 OUString aCID = getCID(mxModel);
459 if (pCheckBox == mpCBLabel.get())
460 setDataLabelVisible(mxModel, aCID, bChecked);
461 else if (pCheckBox == mpCBTrendline.get())
462 setTrendlineVisible(mxModel, aCID, bChecked);
463 else if (pCheckBox == mpCBXError.get())
464 setErrorBarVisible(mxModel, aCID, false, bChecked);
465 else if (pCheckBox == mpCBYError.get())
466 setErrorBarVisible(mxModel, aCID, true, bChecked);
469 IMPL_LINK_NOARG(ChartSeriesPanel, RadioBtnHdl, RadioButton&, void)
471 OUString aCID = getCID(mxModel);
472 bool bChecked = mpRBPrimaryAxis->IsChecked();
474 setAttachedAxisType(mxModel, aCID, bChecked);
477 IMPL_LINK_NOARG(ChartSeriesPanel, ListBoxHdl, ListBox&, void)
479 OUString aCID = getCID(mxModel);
481 sal_Int32 nPos = mpLBLabelPlacement->GetSelectedEntryPos();
482 setDataLabelPlacement(mxModel, aCID, nPos);
485 }} // end of namespace ::chart::sidebar
487 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */