labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

Histogram.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : Histogram.cpp
3  Project : LabPlot
4  Description : Histogram
5  --------------------------------------------------------------------
6  Copyright : (C) 2016 Anu Mittal (anu22mittal@gmail.com)
7  Copyright : (C) 2016-2018 by Alexander Semke (alexander.semke@web.de)
8  Copyright : (C) 2017-2018 by Garvit Khatri (garvitdelhi@gmail.com)
9 
10  ***************************************************************************/
11 
12 /***************************************************************************
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * *
19  * This program is distributed in the hope that it will be useful, *
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22  * GNU General Public License for more details. *
23  * *
24  * You should have received a copy of the GNU General Public License *
25  * along with this program; if not, write to the Free Software *
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
27  * Boston, MA 02110-1301 USA *
28  * *
29  ***************************************************************************/
30 
31 /*!
32  \class Histogram
33  \brief A 2D-curve, provides an interface for editing many properties of the curve.
34 
35  \ingroup worksheet
36  */
37 #include "Histogram.h"
38 #include "HistogramPrivate.h"
45 #include "tools/ImageTools.h"
46 #include "backend/lib/trace.h"
47 
48 #include <QPainter>
49 #include <QGraphicsSceneContextMenuEvent>
50 #include <QMenu>
51 
52 #include <KConfig>
53 #include <KConfigGroup>
54 #include <KSharedConfig>
55 #include <KLocalizedString>
56 
57 extern "C" {
58 #include <gsl/gsl_histogram.h>
59 #include <gsl/gsl_spline.h>
60 #include <gsl/gsl_errno.h>
61 }
62 
63 Histogram::Histogram(const QString &name)
64  : WorksheetElement(name, AspectType::Histogram), Curve(), d_ptr(new HistogramPrivate(this)) {
65 
66  init();
67 }
68 
69 Histogram::Histogram(const QString &name, HistogramPrivate *dd)
70  : WorksheetElement(name, AspectType::Histogram), Curve(), d_ptr(dd) {
71 
72  init();
73 }
74 
76  Q_D(Histogram);
77 
78  KConfig config;
79  KConfigGroup group = config.group("Histogram");
80 
81  d->dataColumn = nullptr;
82 
83  d->type = (Histogram::HistogramType) group.readEntry("Type", (int)Histogram::Ordinary);
84  d->orientation = (Histogram::HistogramOrientation) group.readEntry("Orientation", (int)Histogram::Vertical);
85  d->binningMethod = (Histogram::BinningMethod) group.readEntry("BinningMethod", (int)Histogram::SquareRoot);
86  d->binCount = group.readEntry("BinCount", 10);
87  d->binWidth = group.readEntry("BinWidth", 1.0f);
88  d->autoBinRanges = group.readEntry("AutoBinRanges", true);
89  d->binRangesMin = 0.0;
90  d->binRangesMax = 1.0;
91 
92  d->lineType = (Histogram::LineType) group.readEntry("LineType", (int)Histogram::Bars);
93  d->linePen.setStyle( (Qt::PenStyle) group.readEntry("LineStyle", (int)Qt::SolidLine) );
94  d->linePen.setColor( group.readEntry("LineColor", QColor(Qt::black)) );
95  d->linePen.setWidthF( group.readEntry("LineWidth", Worksheet::convertToSceneUnits(1.0, Worksheet::Unit::Point)) );
96  d->lineOpacity = group.readEntry("LineOpacity", 1.0);
97 
98  d->symbolsStyle = (Symbol::Style)group.readEntry("SymbolStyle", (int)Symbol::Style::NoSymbols);
99  d->symbolsSize = group.readEntry("SymbolSize", Worksheet::convertToSceneUnits(5, Worksheet::Unit::Point));
100  d->symbolsRotationAngle = group.readEntry("SymbolRotation", 0.0);
101  d->symbolsOpacity = group.readEntry("SymbolOpacity", 1.0);
102  d->symbolsBrush.setStyle( (Qt::BrushStyle)group.readEntry("SymbolFillingStyle", (int)Qt::SolidPattern) );
103  d->symbolsBrush.setColor( group.readEntry("SymbolFillingColor", QColor(Qt::black)) );
104  d->symbolsPen.setStyle( (Qt::PenStyle)group.readEntry("SymbolBorderStyle", (int)Qt::SolidLine) );
105  d->symbolsPen.setColor( group.readEntry("SymbolBorderColor", QColor(Qt::black)) );
106  d->symbolsPen.setWidthF( group.readEntry("SymbolBorderWidth", Worksheet::convertToSceneUnits(0.0, Worksheet::Unit::Point)) );
107 
108  d->valuesType = (Histogram::ValuesType) group.readEntry("ValuesType", (int)Histogram::NoValues);
109  d->valuesColumn = nullptr;
110  d->valuesPosition = (Histogram::ValuesPosition) group.readEntry("ValuesPosition", (int)Histogram::ValuesAbove);
111  d->valuesDistance = group.readEntry("ValuesDistance", Worksheet::convertToSceneUnits(5, Worksheet::Unit::Point));
112  d->valuesRotationAngle = group.readEntry("ValuesRotation", 0.0);
113  d->valuesOpacity = group.readEntry("ValuesOpacity", 1.0);
114  d->valuesNumericFormat = group.readEntry("ValuesNumericFormat", "f").at(0).toLatin1();
115  d->valuesPrecision = group.readEntry("ValuesNumericFormat", 2);
116  d->valuesDateTimeFormat = group.readEntry("ValuesDateTimeFormat", "yyyy-MM-dd");
117  d->valuesPrefix = group.readEntry("ValuesPrefix", "");
118  d->valuesSuffix = group.readEntry("ValuesSuffix", "");
119  d->valuesFont = group.readEntry("ValuesFont", QFont());
120  d->valuesFont.setPixelSize( Worksheet::convertToSceneUnits( 8, Worksheet::Unit::Point ) );
121  d->valuesColor = group.readEntry("ValuesColor", QColor(Qt::black));
122 
123  d->fillingEnabled = group.readEntry("FillingEnabled", true);
124  d->fillingType = (PlotArea::BackgroundType) group.readEntry("FillingType", static_cast<int>(PlotArea::BackgroundType::Color));
125  d->fillingColorStyle = (PlotArea::BackgroundColorStyle) group.readEntry("FillingColorStyle", static_cast<int>(PlotArea::BackgroundColorStyle::SingleColor));
126  d->fillingImageStyle = (PlotArea::BackgroundImageStyle) group.readEntry("FillingImageStyle", static_cast<int>(PlotArea::BackgroundImageStyle::Scaled));
127  d->fillingBrushStyle = (Qt::BrushStyle) group.readEntry("FillingBrushStyle", static_cast<int>(Qt::SolidPattern));
128  d->fillingFileName = group.readEntry("FillingFileName", QString());
129  d->fillingFirstColor = group.readEntry("FillingFirstColor", QColor(Qt::white));
130  d->fillingSecondColor = group.readEntry("FillingSecondColor", QColor(Qt::black));
131  d->fillingOpacity = group.readEntry("FillingOpacity", 1.0);
132 
133  d->errorType = (Histogram::ErrorType) group.readEntry("ErrorType", (int)Histogram::NoError);
134  d->errorBarsType = (XYCurve::ErrorBarsType) group.readEntry("ErrorBarsType", static_cast<int>(XYCurve::ErrorBarsType::Simple));
135  d->errorBarsCapSize = group.readEntry( "ErrorBarsCapSize", Worksheet::convertToSceneUnits(10, Worksheet::Unit::Point) );
136  d->errorBarsPen.setStyle( (Qt::PenStyle)group.readEntry("ErrorBarsStyle", (int)Qt::SolidLine) );
137  d->errorBarsPen.setColor( group.readEntry("ErrorBarsColor", QColor(Qt::black)) );
138  d->errorBarsPen.setWidthF( group.readEntry("ErrorBarsWidth", Worksheet::convertToSceneUnits(1.0, Worksheet::Unit::Point)) );
139  d->errorBarsOpacity = group.readEntry("ErrorBarsOpacity", 1.0);
140 
141  this->initActions();
142 }
143 
145  visibilityAction = new QAction(QIcon::fromTheme("view-visible"), i18n("Visible"), this);
146  visibilityAction->setCheckable(true);
147  connect(visibilityAction, &QAction::triggered, this, &Histogram::visibilityChangedSlot);
148 }
149 
151  QMenu *menu = WorksheetElement::createContextMenu();
152  QAction* firstAction = menu->actions().at(1); //skip the first action because of the "title-action"
153  visibilityAction->setChecked(isVisible());
154  menu->insertAction(firstAction, visibilityAction);
155  return menu;
156 }
157 
158 /*!
159  Returns an icon to be used in the project explorer.
160  */
161 QIcon Histogram::icon() const {
162  return QIcon::fromTheme("view-object-histogram-linear");
163 }
164 
165 QGraphicsItem* Histogram::graphicsItem() const {
166  return d_ptr;
167 }
168 
169 STD_SWAP_METHOD_SETTER_CMD_IMPL(Histogram, SetVisible, bool, swapVisible)
170 void Histogram::setVisible(bool on) {
171  Q_D(Histogram);
172  exec(new HistogramSetVisibleCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible")));
173 }
174 
175 bool Histogram::isVisible() const {
176  Q_D(const Histogram);
177  return d->isVisible();
178 }
179 
180 void Histogram::setPrinting(bool on) {
181  Q_D(Histogram);
182  d->m_printing = on;
183 }
184 
185 bool Histogram::activateCurve(QPointF mouseScenePos, double maxDist) {
186  Q_D(Histogram);
187  return d->activateCurve(mouseScenePos, maxDist);
188 }
189 
190 void Histogram::setHover(bool on) {
191  Q_D(Histogram);
192  d->setHover(on);
193 }
194 
195 //##############################################################################
196 //########################## getter methods ##################################
197 //##############################################################################
198 //general
201 BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::BinningMethod, binningMethod, binningMethod)
202 BASIC_SHARED_D_READER_IMPL(Histogram, int, binCount, binCount)
203 BASIC_SHARED_D_READER_IMPL(Histogram, float, binWidth, binWidth)
204 BASIC_SHARED_D_READER_IMPL(Histogram, bool, autoBinRanges, autoBinRanges)
205 BASIC_SHARED_D_READER_IMPL(Histogram, double, binRangesMin, binRangesMin)
206 BASIC_SHARED_D_READER_IMPL(Histogram, double, binRangesMax, binRangesMax)
207 BASIC_SHARED_D_READER_IMPL(Histogram, const AbstractColumn*, dataColumn, dataColumn)
208 
209 QString& Histogram::dataColumnPath() const {
210  return d_ptr->dataColumnPath;
211 }
212 
213 //line
215 CLASS_SHARED_D_READER_IMPL(Histogram, QPen, linePen, linePen)
216 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, lineOpacity, lineOpacity)
217 
218 //symbols
219 BASIC_SHARED_D_READER_IMPL(Histogram, Symbol::Style, symbolsStyle, symbolsStyle)
220 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, symbolsOpacity, symbolsOpacity)
221 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, symbolsRotationAngle, symbolsRotationAngle)
222 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, symbolsSize, symbolsSize)
223 CLASS_SHARED_D_READER_IMPL(Histogram, QBrush, symbolsBrush, symbolsBrush)
224 CLASS_SHARED_D_READER_IMPL(Histogram, QPen, symbolsPen, symbolsPen)
225 
226 //values
228 BASIC_SHARED_D_READER_IMPL(Histogram, const AbstractColumn *, valuesColumn, valuesColumn)
229 QString& Histogram::valuesColumnPath() const {
230  return d_ptr->valuesColumnPath;
231 }
232 BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::ValuesPosition, valuesPosition, valuesPosition)
233 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, valuesDistance, valuesDistance)
234 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, valuesRotationAngle, valuesRotationAngle)
235 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, valuesOpacity, valuesOpacity)
236 CLASS_SHARED_D_READER_IMPL(Histogram, char, valuesNumericFormat, valuesNumericFormat)
237 BASIC_SHARED_D_READER_IMPL(Histogram, int, valuesPrecision, valuesPrecision)
238 CLASS_SHARED_D_READER_IMPL(Histogram, QString, valuesDateTimeFormat, valuesDateTimeFormat)
239 CLASS_SHARED_D_READER_IMPL(Histogram, QString, valuesPrefix, valuesPrefix)
240 CLASS_SHARED_D_READER_IMPL(Histogram, QString, valuesSuffix, valuesSuffix)
241 CLASS_SHARED_D_READER_IMPL(Histogram, QColor, valuesColor, valuesColor)
242 CLASS_SHARED_D_READER_IMPL(Histogram, QFont, valuesFont, valuesFont)
243 
244 //filling
245 BASIC_SHARED_D_READER_IMPL(Histogram, bool, fillingEnabled, fillingEnabled)
247 BASIC_SHARED_D_READER_IMPL(Histogram, PlotArea::BackgroundColorStyle, fillingColorStyle, fillingColorStyle)
248 BASIC_SHARED_D_READER_IMPL(Histogram, PlotArea::BackgroundImageStyle, fillingImageStyle, fillingImageStyle)
249 CLASS_SHARED_D_READER_IMPL(Histogram, Qt::BrushStyle, fillingBrushStyle, fillingBrushStyle)
250 CLASS_SHARED_D_READER_IMPL(Histogram, QColor, fillingFirstColor, fillingFirstColor)
251 CLASS_SHARED_D_READER_IMPL(Histogram, QColor, fillingSecondColor, fillingSecondColor)
252 CLASS_SHARED_D_READER_IMPL(Histogram, QString, fillingFileName, fillingFileName)
253 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, fillingOpacity, fillingOpacity)
254 
255 //error bars
257 BASIC_SHARED_D_READER_IMPL(Histogram, XYCurve::ErrorBarsType, errorBarsType, errorBarsType)
258 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, errorBarsCapSize, errorBarsCapSize)
259 CLASS_SHARED_D_READER_IMPL(Histogram, QPen, errorBarsPen, errorBarsPen)
260 BASIC_SHARED_D_READER_IMPL(Histogram, qreal, errorBarsOpacity, errorBarsOpacity)
261 
262 double Histogram::getYMaximum() const {
263  return d_ptr->getYMaximum();
264 }
265 
266 double Histogram::getYMinimum() const {
267  return d_ptr->getYMinimum();
268 }
269 
270 double Histogram::getXMaximum() const {
271  return d_ptr->getXMaximum();
272 }
273 
274 double Histogram::getXMinimum() const {
275  return d_ptr->getXMinimum();
276 }
277 
278 //##############################################################################
279 //################# setter methods and undo commands ##########################
280 //##############################################################################
281 
282 //General
283 STD_SETTER_CMD_IMPL_F_S(Histogram, SetDataColumn, const AbstractColumn*, dataColumn, recalcHistogram)
284 void Histogram::setDataColumn(const AbstractColumn* column) {
285  Q_D(Histogram);
286  if (column != d->dataColumn) {
287  exec(new HistogramSetDataColumnCmd(d, column, ki18n("%1: set data column")));
288 
289  if (column) {
290  connect(column, &AbstractColumn::dataChanged, this, &Histogram::dataChanged);
291 
292  //update the curve itself on changes
296  //TODO: add disconnect in the undo-function
297  }
298  }
299 }
300 
301 STD_SETTER_CMD_IMPL_F_S(Histogram, SetHistogramType, Histogram::HistogramType, type, updateType)
302 void Histogram::setType(Histogram::HistogramType type) {
303  Q_D(Histogram);
304  if (type != d->type)
305  exec(new HistogramSetHistogramTypeCmd(d, type, ki18n("%1: set histogram type")));
306 }
307 
308 STD_SETTER_CMD_IMPL_F_S(Histogram, SetHistogramOrientation, Histogram::HistogramOrientation, orientation, updateOrientation)
309 void Histogram::setOrientation(Histogram::HistogramOrientation orientation) {
310  Q_D(Histogram);
311  if (orientation != d->orientation)
312  exec(new HistogramSetHistogramOrientationCmd(d, orientation, ki18n("%1: set histogram orientation")));
313 }
314 
315 STD_SETTER_CMD_IMPL_F_S(Histogram, SetBinningMethod, Histogram::BinningMethod, binningMethod, recalcHistogram)
316 void Histogram::setBinningMethod(Histogram::BinningMethod method) {
317  Q_D(Histogram);
318  if (method != d->binningMethod)
319  exec(new HistogramSetBinningMethodCmd(d, method, ki18n("%1: set binning method")));
320 }
321 
322 STD_SETTER_CMD_IMPL_F_S(Histogram, SetBinCount, int, binCount, recalcHistogram)
323 void Histogram::setBinCount(int count) {
324  Q_D(Histogram);
325  if (count != d->binCount)
326  exec(new HistogramSetBinCountCmd(d, count, ki18n("%1: set bin count")));
327 }
328 
329 STD_SETTER_CMD_IMPL_F_S(Histogram, SetBinWidth, float, binWidth, recalcHistogram)
330 void Histogram::setBinWidth(float width) {
331  Q_D(Histogram);
332  if (width != d->binWidth)
333  exec(new HistogramSetBinWidthCmd(d, width, ki18n("%1: set bin width")));
334 }
335 
336 class HistogramSetAutoBinRangesCmd : public QUndoCommand {
337 public:
338  HistogramSetAutoBinRangesCmd(HistogramPrivate* private_obj, bool autoBinRanges) :
339  m_private(private_obj), m_autoBinRanges(autoBinRanges) {
340  setText(i18n("%1: change auto bin ranges", m_private->name()));
341  };
342 
343  void redo() override {
346  if (m_autoBinRanges) {
350  }
352  };
353 
354  void undo() override {
356  if (!m_autoBinRangesOld) {
360  }
364  }
366  }
368  }
369 
370 private:
373  bool m_autoBinRangesOld{false};
374  double m_binRangesMinOld{0.0};
375  double m_binRangesMaxOld{0.0};
376 };
377 
378 void Histogram::setAutoBinRanges(bool autoBinRanges) {
379  Q_D(Histogram);
380  if (autoBinRanges != d->autoBinRanges)
381  exec(new HistogramSetAutoBinRangesCmd(d, autoBinRanges));
382 }
383 
384 STD_SETTER_CMD_IMPL_F_S(Histogram, SetBinRangesMin, double, binRangesMin, recalcHistogram)
385 void Histogram::setBinRangesMin(double binRangesMin) {
386  Q_D(Histogram);
387  if (binRangesMin != d->binRangesMin)
388  exec(new HistogramSetBinRangesMinCmd(d, binRangesMin, ki18n("%1: set bin ranges start")));
389 }
390 
391 STD_SETTER_CMD_IMPL_F_S(Histogram, SetBinRangesMax, double, binRangesMax, recalcHistogram)
392 void Histogram::setBinRangesMax(double binRangesMax) {
393  Q_D(Histogram);
394  if (binRangesMax != d->binRangesMax)
395  exec(new HistogramSetBinRangesMaxCmd(d, binRangesMax, ki18n("%1: set bin ranges end")));
396 }
397 
398 //Line
399 STD_SETTER_CMD_IMPL_F_S(Histogram, SetLineType, Histogram::LineType, lineType, updateLines)
400 void Histogram::setLineType(LineType type) {
401  Q_D(Histogram);
402  if (type != d->lineType)
403  exec(new HistogramSetLineTypeCmd(d, type, ki18n("%1: line type changed")));
404 }
405 
406 STD_SETTER_CMD_IMPL_F_S(Histogram, SetLinePen, QPen, linePen, recalcShapeAndBoundingRect)
407 void Histogram::setLinePen(const QPen &pen) {
408  Q_D(Histogram);
409  if (pen != d->linePen)
410  exec(new HistogramSetLinePenCmd(d, pen, ki18n("%1: set line style")));
411 }
412 
413 STD_SETTER_CMD_IMPL_F_S(Histogram, SetLineOpacity, qreal, lineOpacity, updatePixmap);
414 void Histogram::setLineOpacity(qreal opacity) {
415  Q_D(Histogram);
416  if (opacity != d->lineOpacity)
417  exec(new HistogramSetLineOpacityCmd(d, opacity, ki18n("%1: set line opacity")));
418 }
419 
420 // Symbols
421 STD_SETTER_CMD_IMPL_F_S(Histogram, SetSymbolsStyle, Symbol::Style, symbolsStyle, updateSymbols)
422 void Histogram::setSymbolsStyle(Symbol::Style style) {
423  Q_D(Histogram);
424  if (style != d->symbolsStyle)
425  exec(new HistogramSetSymbolsStyleCmd(d, style, ki18n("%1: set symbol style")));
426 }
427 
428 STD_SETTER_CMD_IMPL_F_S(Histogram, SetSymbolsSize, qreal, symbolsSize, updateSymbols)
429 void Histogram::setSymbolsSize(qreal size) {
430  Q_D(Histogram);
431  if (!qFuzzyCompare(1 + size, 1 + d->symbolsSize))
432  exec(new HistogramSetSymbolsSizeCmd(d, size, ki18n("%1: set symbol size")));
433 }
434 
435 STD_SETTER_CMD_IMPL_F_S(Histogram, SetSymbolsRotationAngle, qreal, symbolsRotationAngle, updateSymbols)
436 void Histogram::setSymbolsRotationAngle(qreal angle) {
437  Q_D(Histogram);
438  if (!qFuzzyCompare(1 + angle, 1 + d->symbolsRotationAngle))
439  exec(new HistogramSetSymbolsRotationAngleCmd(d, angle, ki18n("%1: rotate symbols")));
440 }
441 
442 STD_SETTER_CMD_IMPL_F_S(Histogram, SetSymbolsBrush, QBrush, symbolsBrush, updatePixmap)
443 void Histogram::setSymbolsBrush(const QBrush &brush) {
444  Q_D(Histogram);
445  if (brush != d->symbolsBrush)
446  exec(new HistogramSetSymbolsBrushCmd(d, brush, ki18n("%1: set symbol filling")));
447 }
448 
449 STD_SETTER_CMD_IMPL_F_S(Histogram, SetSymbolsPen, QPen, symbolsPen, updateSymbols)
450 void Histogram::setSymbolsPen(const QPen &pen) {
451  Q_D(Histogram);
452  if (pen != d->symbolsPen)
453  exec(new HistogramSetSymbolsPenCmd(d, pen, ki18n("%1: set symbol outline style")));
454 }
455 
456 STD_SETTER_CMD_IMPL_F_S(Histogram, SetSymbolsOpacity, qreal, symbolsOpacity, updatePixmap)
457 void Histogram::setSymbolsOpacity(qreal opacity) {
458  Q_D(Histogram);
459  if (opacity != d->symbolsOpacity)
460  exec(new HistogramSetSymbolsOpacityCmd(d, opacity, ki18n("%1: set symbols opacity")));
461 }
462 
463 //Values
464 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesType, Histogram::ValuesType, valuesType, updateValues)
465 void Histogram::setValuesType(Histogram::ValuesType type) {
466  Q_D(Histogram);
467  if (type != d->valuesType)
468  exec(new HistogramSetValuesTypeCmd(d, type, ki18n("%1: set values type")));
469 }
470 
471 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesColumn, const AbstractColumn*, valuesColumn, updateValues)
472 void Histogram::setValuesColumn(const AbstractColumn* column) {
473  Q_D(Histogram);
474  if (column != d->valuesColumn) {
475  exec(new HistogramSetValuesColumnCmd(d, column, ki18n("%1: set values column")));
476  if (column) {
477  connect(column, &AbstractColumn::dataChanged, this, &Histogram::updateValues);
480  }
481  }
482 }
483 
484 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesPosition, Histogram::ValuesPosition, valuesPosition, updateValues)
485 void Histogram::setValuesPosition(ValuesPosition position) {
486  Q_D(Histogram);
487  if (position != d->valuesPosition)
488  exec(new HistogramSetValuesPositionCmd(d, position, ki18n("%1: set values position")));
489 }
490 
491 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesDistance, qreal, valuesDistance, updateValues)
492 void Histogram::setValuesDistance(qreal distance) {
493  Q_D(Histogram);
494  if (distance != d->valuesDistance)
495  exec(new HistogramSetValuesDistanceCmd(d, distance, ki18n("%1: set values distance")));
496 }
497 
498 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesRotationAngle, qreal, valuesRotationAngle, updateValues)
499 void Histogram::setValuesRotationAngle(qreal angle) {
500  Q_D(Histogram);
501  if (!qFuzzyCompare(1 + angle, 1 + d->valuesRotationAngle))
502  exec(new HistogramSetValuesRotationAngleCmd(d, angle, ki18n("%1: rotate values")));
503 }
504 
505 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesOpacity, qreal, valuesOpacity, updatePixmap)
506 void Histogram::setValuesOpacity(qreal opacity) {
507  Q_D(Histogram);
508  if (opacity != d->valuesOpacity)
509  exec(new HistogramSetValuesOpacityCmd(d, opacity, ki18n("%1: set values opacity")));
510 }
511 
512 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesNumericFormat, char, valuesNumericFormat, updateValues)
513 void Histogram::setValuesNumericFormat(char format) {
514  Q_D(Histogram);
515  if (format != d->valuesNumericFormat)
516  exec(new HistogramSetValuesNumericFormatCmd(d, format, ki18n("%1: set values numeric format")));
517 }
518 
519 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesPrecision, int, valuesPrecision, updateValues)
520 void Histogram::setValuesPrecision(int precision) {
521  Q_D(Histogram);
522  if (precision != d->valuesPrecision)
523  exec(new HistogramSetValuesPrecisionCmd(d, precision, ki18n("%1: set values precision")));
524 }
525 
526 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesDateTimeFormat, QString, valuesDateTimeFormat, updateValues)
527 void Histogram::setValuesDateTimeFormat(const QString& format) {
528  Q_D(Histogram);
529  if (format != d->valuesDateTimeFormat)
530  exec(new HistogramSetValuesDateTimeFormatCmd(d, format, ki18n("%1: set values datetime format")));
531 }
532 
533 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesPrefix, QString, valuesPrefix, updateValues)
534 void Histogram::setValuesPrefix(const QString& prefix) {
535  Q_D(Histogram);
536  if (prefix!= d->valuesPrefix)
537  exec(new HistogramSetValuesPrefixCmd(d, prefix, ki18n("%1: set values prefix")));
538 }
539 
540 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesSuffix, QString, valuesSuffix, updateValues)
541 void Histogram::setValuesSuffix(const QString& suffix) {
542  Q_D(Histogram);
543  if (suffix!= d->valuesSuffix)
544  exec(new HistogramSetValuesSuffixCmd(d, suffix, ki18n("%1: set values suffix")));
545 }
546 
547 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesFont, QFont, valuesFont, updateValues)
548 void Histogram::setValuesFont(const QFont& font) {
549  Q_D(Histogram);
550  if (font!= d->valuesFont)
551  exec(new HistogramSetValuesFontCmd(d, font, ki18n("%1: set values font")));
552 }
553 
554 STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesColor, QColor, valuesColor, updatePixmap)
555 void Histogram::setValuesColor(const QColor& color) {
556  Q_D(Histogram);
557  if (color != d->valuesColor)
558  exec(new HistogramSetValuesColorCmd(d, color, ki18n("%1: set values color")));
559 }
560 
561 //Filling
562 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingEnabled, bool, fillingEnabled, updateFilling)
563 void Histogram::setFillingEnabled(bool enabled) {
564  Q_D(Histogram);
565  if (enabled != d->fillingEnabled)
566  exec(new HistogramSetFillingEnabledCmd(d, enabled, ki18n("%1: filling changed")));
567 }
568 
569 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingType, PlotArea::BackgroundType, fillingType, updatePixmap)
570 void Histogram::setFillingType(PlotArea::BackgroundType type) {
571  Q_D(Histogram);
572  if (type != d->fillingType)
573  exec(new HistogramSetFillingTypeCmd(d, type, ki18n("%1: filling type changed")));
574 }
575 
576 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingColorStyle, PlotArea::BackgroundColorStyle, fillingColorStyle, updatePixmap)
577 void Histogram::setFillingColorStyle(PlotArea::BackgroundColorStyle style) {
578  Q_D(Histogram);
579  if (style != d->fillingColorStyle)
580  exec(new HistogramSetFillingColorStyleCmd(d, style, ki18n("%1: filling color style changed")));
581 }
582 
583 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingImageStyle, PlotArea::BackgroundImageStyle, fillingImageStyle, updatePixmap)
584 void Histogram::setFillingImageStyle(PlotArea::BackgroundImageStyle style) {
585  Q_D(Histogram);
586  if (style != d->fillingImageStyle)
587  exec(new HistogramSetFillingImageStyleCmd(d, style, ki18n("%1: filling image style changed")));
588 }
589 
590 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingBrushStyle, Qt::BrushStyle, fillingBrushStyle, updatePixmap)
591 void Histogram::setFillingBrushStyle(Qt::BrushStyle style) {
592  Q_D(Histogram);
593  if (style != d->fillingBrushStyle)
594  exec(new HistogramSetFillingBrushStyleCmd(d, style, ki18n("%1: filling brush style changed")));
595 }
596 
597 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingFirstColor, QColor, fillingFirstColor, updatePixmap)
598 void Histogram::setFillingFirstColor(const QColor& color) {
599  Q_D(Histogram);
600  if (color!= d->fillingFirstColor)
601  exec(new HistogramSetFillingFirstColorCmd(d, color, ki18n("%1: set filling first color")));
602 }
603 
604 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingSecondColor, QColor, fillingSecondColor, updatePixmap)
605 void Histogram::setFillingSecondColor(const QColor& color) {
606  Q_D(Histogram);
607  if (color!= d->fillingSecondColor)
608  exec(new HistogramSetFillingSecondColorCmd(d, color, ki18n("%1: set filling second color")));
609 }
610 
611 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingFileName, QString, fillingFileName, updatePixmap)
612 void Histogram::setFillingFileName(const QString& fileName) {
613  Q_D(Histogram);
614  if (fileName!= d->fillingFileName)
615  exec(new HistogramSetFillingFileNameCmd(d, fileName, ki18n("%1: set filling image")));
616 }
617 
618 STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingOpacity, qreal, fillingOpacity, updatePixmap)
619 void Histogram::setFillingOpacity(qreal opacity) {
620  Q_D(Histogram);
621  if (opacity != d->fillingOpacity)
622  exec(new HistogramSetFillingOpacityCmd(d, opacity, ki18n("%1: set filling opacity")));
623 }
624 
625 //Error bars
626 STD_SETTER_CMD_IMPL_F_S(Histogram, SetErrorType, Histogram::ErrorType, errorType, updateErrorBars)
627 void Histogram::setErrorType(ErrorType type) {
628  Q_D(Histogram);
629  if (type != d->errorType)
630  exec(new HistogramSetErrorTypeCmd(d, type, ki18n("%1: x-error type changed")));
631 }
632 
633 STD_SETTER_CMD_IMPL_F_S(Histogram, SetErrorBarsCapSize, qreal, errorBarsCapSize, updateErrorBars)
634 void Histogram::setErrorBarsCapSize(qreal size) {
635  Q_D(Histogram);
636  if (size != d->errorBarsCapSize)
637  exec(new HistogramSetErrorBarsCapSizeCmd(d, size, ki18n("%1: set error bar cap size")));
638 }
639 
640 STD_SETTER_CMD_IMPL_F_S(Histogram, SetErrorBarsType, XYCurve::ErrorBarsType, errorBarsType, updateErrorBars)
641 void Histogram::setErrorBarsType(XYCurve::ErrorBarsType type) {
642  Q_D(Histogram);
643  if (type != d->errorBarsType)
644  exec(new HistogramSetErrorBarsTypeCmd(d, type, ki18n("%1: error bar type changed")));
645 }
646 
647 STD_SETTER_CMD_IMPL_F_S(Histogram, SetErrorBarsPen, QPen, errorBarsPen, recalcShapeAndBoundingRect)
648 void Histogram::setErrorBarsPen(const QPen& pen) {
649  Q_D(Histogram);
650  if (pen != d->errorBarsPen)
651  exec(new HistogramSetErrorBarsPenCmd(d, pen, ki18n("%1: set error bar style")));
652 }
653 
654 STD_SETTER_CMD_IMPL_F_S(Histogram, SetErrorBarsOpacity, qreal, errorBarsOpacity, updatePixmap)
655 void Histogram::setErrorBarsOpacity(qreal opacity) {
656  Q_D(Histogram);
657  if (opacity != d->errorBarsOpacity)
658  exec(new HistogramSetErrorBarsOpacityCmd(d, opacity, ki18n("%1: set error bar opacity")));
659 }
660 
661 //##############################################################################
662 //################################# SLOTS ####################################
663 //##############################################################################
665  d_ptr->retransform();
666 }
667 
670 }
671 
672 //TODO
673 void Histogram::handleResize(double horizontalRatio, double verticalRatio, bool pageResize) {
674  Q_UNUSED(pageResize);
675  Q_UNUSED(verticalRatio);
676  Q_D(const Histogram);
677 
678  //setValuesDistance(d->distance*);
679  QFont font = d->valuesFont;
680  font.setPointSizeF(font.pointSizeF()*horizontalRatio);
681  setValuesFont(font);
682 
683  retransform();
684 }
685 
687  d_ptr->updateValues();
688 }
689 
691  Q_D(Histogram);
692  if (aspect == d->dataColumn) {
693  d->dataColumn = nullptr;
694  d->retransform();
695  }
696 }
697 
699  Q_D(Histogram);
700  if (aspect == d->valuesColumn) {
701  d->valuesColumn = nullptr;
702  d->updateValues();
703  }
704 }
705 
706 //##############################################################################
707 //###### SLOTs for changes triggered via QActions in the context menu ########
708 //##############################################################################
710  Q_D(const Histogram);
711  this->setVisible(!d->isVisible());
712 }
713 
714 //##############################################################################
715 //######################### Private implementation #############################
716 //##############################################################################
718  setFlag(QGraphicsItem::ItemIsSelectable, true);
719  setAcceptHoverEvents(false);
720 }
721 
723  if (m_histogram)
724  gsl_histogram_free(m_histogram);
725 }
726 
727 QString HistogramPrivate::name() const {
728  return q->name();
729 }
730 
732  return boundingRectangle;
733 }
734 
736  if (m_histogram) {
737  double yMaxRange = -INFINITY;
738  switch (type) {
739  case Histogram::Ordinary: {
740  size_t maxYAddes = gsl_histogram_max_bin(m_histogram);
741  yMaxRange = gsl_histogram_get(m_histogram, maxYAddes);
742  break;
743  }
744  case Histogram::Cumulative: {
745  size_t maxYAddes = gsl_histogram_max_bin(m_histogram);
746  yMaxRange = gsl_histogram_get(m_histogram, maxYAddes);
747  double point = 0.0;
748  for (size_t i = 0; i < m_bins; ++i) {
749  point+= gsl_histogram_get(m_histogram,i);
750  if (point > yMaxRange) {
751  yMaxRange = point;
752  }
753  }
754  //yMaxRange = dataColumn->rowCount();
755  break;
756  }
757  case Histogram::AvgShift: {
758  //TODO
759  }
760  }
761  return yMaxRange;
762  }
763 
764  return -INFINITY;
765 }
766 
768  switch (orientation) {
769  case Histogram::Vertical:
772  return 0;
773  }
774  return INFINITY;
775 }
776 
778  switch (orientation) {
779  case Histogram::Vertical:
783  }
784  return -INFINITY;
785 }
786 
788  switch (orientation) {
789  case Histogram::Vertical:
790  return 0;
793  }
794  return INFINITY;
795 }
796 
798  switch (orientation) {
799  case Histogram::Vertical:
803  }
804  return INFINITY;
805 }
806 
807 /*!
808  Returns the shape of the Histogram as a QPainterPath in local coordinates
809  */
810 QPainterPath HistogramPrivate::shape() const {
811  return curveShape;
812 }
813 
814 void HistogramPrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) {
815  q->createContextMenu()->exec(event->screenPos());
816 }
817 
819  bool oldValue = isVisible();
820 
821  //When making a graphics item invisible, it gets deselected in the scene.
822  //In this case we don't want to deselect the item in the project explorer.
823  //We need to supress the deselection in the view.
824  auto* worksheet = static_cast<Worksheet*>(q->parent(AspectType::Worksheet));
825  worksheet->suppressSelectionChangedEvent(true);
826  setVisible(on);
827  worksheet->suppressSelectionChangedEvent(false);
828 
829  emit q->visibilityChanged(on);
830  return oldValue;
831 }
832 
833 /*!
834  called when the size of the plot or its data ranges (manual changes, zooming, etc.) were changed.
835  recalculates the position of the scene points to be drawn.
836  triggers the update of lines, drop lines, symbols etc.
837 */
840  return;
841 
842  if (!isVisible())
843  return;
844 
845  PERFTRACE(name().toLatin1() + ", HistogramPrivate::retransform()");
846 
847  if (!dataColumn) {
848  linePath = QPainterPath();
849  symbolsPath = QPainterPath();
850  valuesPath = QPainterPath();
851  curveShape = QPainterPath();
852  lines.clear();
853  pointsLogical.clear();
854  pointsScene.clear();
855  visiblePoints.clear();
856  valuesPoints.clear();
857  valuesStrings.clear();
858  fillPolygon.clear();
860  return;
861  }
862 
863  m_suppressRecalc = true;
864  updateLines();
865  updateSymbols();
866  updateValues();
867  m_suppressRecalc = false;
868 }
869 
870 /*!
871  * called when the data was changed. recalculates the histogram.
872  */
874  PERFTRACE(name().toLatin1() + ", HistogramPrivate::recalcHistogram()");
875 
876  if (m_histogram) {
877  gsl_histogram_free(m_histogram);
878  m_histogram = nullptr;
879  }
880 
881  if (!dataColumn)
882  return;
883 
884  //calculate the number of valid data points
885  int count = 0;
886  for (int row = 0; row < dataColumn->rowCount(); ++row) {
887  if (dataColumn->isValid(row) && !dataColumn->isMasked(row))
888  ++count;
889  }
890 
891  //calculate the number of bins
892  if (count > 0) {
893  if (autoBinRanges) {
894  if (binRangesMin != dataColumn->minimum()) {
897  }
898 
899  if (binRangesMax != dataColumn->maximum()) {
902  }
903  }
904 
905  if (binRangesMin >= binRangesMax) {
906  emit q->dataChanged();
907  emit q->info(i18n("Calculation of the histogram not possible. The max value must be bigger then the min value."));
908  return;
909  }
910 
911  switch (binningMethod) {
912  case Histogram::ByNumber:
913  m_bins = (size_t)binCount;
914  break;
915  case Histogram::ByWidth:
917  break;
919  m_bins = (size_t)sqrt(count);
920  break;
921  case Histogram::Rice:
922  m_bins = (size_t)2*cbrt(count);
923  break;
924  case Histogram::Sturges:
925  m_bins = (size_t) 1 + log2(count);
926  break;
927  case Histogram::Doane: {
928  const double skewness = static_cast<const Column*>(dataColumn)->statistics().skewness;
929  m_bins = (size_t)( 1 + log2(count) + log2(1 + abs(skewness)/sqrt((double)6*(count-2)/(count+1)/(count+3))) );
930  break;
931  }
932  case Histogram::Scott: {
933  const double sigma = static_cast<const Column*>(dataColumn)->statistics().standardDeviation;
934  const double width = 3.5*sigma/cbrt(count);
935  DEBUG("blablub " << sigma << " " << width << " " <<(binRangesMax - binRangesMin)/width);
936  m_bins = (size_t)(binRangesMax - binRangesMin)/width;
937  break;
938  }
939  }
940 
941  DEBUG("min " << binRangesMin)
942  DEBUG("max " << binRangesMax)
943  DEBUG("number of bins " << m_bins)
944 
945  //calculate the histogram
946  if (m_bins > 0) {
947  m_histogram = gsl_histogram_alloc (m_bins);
948  gsl_histogram_set_ranges_uniform (m_histogram, binRangesMin, binRangesMax);
949 
950  switch (dataColumn->columnMode()) {
954  for (int row = 0; row < dataColumn->rowCount(); ++row) {
955  if ( dataColumn->isValid(row) && !dataColumn->isMasked(row) )
956  gsl_histogram_increment(m_histogram, dataColumn->valueAt(row));
957  }
958  break;
960  for (int row = 0; row < dataColumn->rowCount(); ++row) {
961  if ( dataColumn->isValid(row) && !dataColumn->isMasked(row) )
962  gsl_histogram_increment(m_histogram, dataColumn->dateTimeAt(row).toMSecsSinceEpoch());
963  }
964  break;
968  break;
969  }
970  } else
971  DEBUG("Number of bins must be positiv integer")
972  }
973 
974  //histogram changed because of the actual data changes or because of new bin settings,
975  //emit dataChanged() in order to recalculate everything with the new size/shape of the histogram
976  emit q->dataChanged();
977 }
978 
980  //type (ordinary or cumulative) changed,
981  //emit dataChanged() in order to recalculate everything with the new size/shape of the histogram
982  emit q->dataChanged();
983 }
984 
986  //orientation (horizontal or vertical) changed
987  //emit dataChanged() in order to recalculate everything with the new size/shape of the histogram
988  emit q->dataChanged();
989 }
990 
991 /*!
992  recalculates the painter path for the lines connecting the data points.
993  Called each time when the type of this connection is changed.
994  */
996  PERFTRACE(name().toLatin1() + ", HistogramPrivate::updateLines()");
997 
998  linePath = QPainterPath();
999  lines.clear();
1000  pointsLogical.clear();
1001  pointsScene.clear();
1002 
1005  else
1007 
1008  //map the lines and the symbol positions to the scene coordinates
1009  const auto* plot = static_cast<const CartesianPlot*>(q->parentAspect());
1010  const auto* cSystem = static_cast<const CartesianCoordinateSystem*>(plot->coordinateSystem());
1011  lines = cSystem->mapLogicalToScene(lines);
1012  visiblePoints = std::vector<bool>(pointsLogical.count(), false);
1013  cSystem->mapLogicalToScene(pointsLogical, pointsScene, visiblePoints);
1014 
1015  //new line path
1016  for (const auto& line : lines) {
1017  linePath.moveTo(line.p1());
1018  linePath.lineTo(line.p2());
1019  }
1020 
1021  updateFilling();
1023 }
1024 
1026  if (!m_histogram)
1027  return;
1028 
1029  const double width = (binRangesMax - binRangesMin)/m_bins;
1030  double value = 0.;
1031  if (lineType == Histogram::Bars) {
1032  for (size_t i = 0; i < m_bins; ++i) {
1033  if (type == Histogram::Ordinary)
1034  value = gsl_histogram_get(m_histogram, i);
1035  else
1036  value += gsl_histogram_get(m_histogram, i);
1037 
1038  const double x = binRangesMin + i*width;
1039  lines.append(QLineF(x, 0., x, value));
1040  lines.append(QLineF(x, value, x + width, value));
1041  lines.append(QLineF(x + width, value, x + width, 0.));
1042  pointsLogical.append(QPointF(x+width/2, value));
1043  }
1045  double prevValue = 0.;
1046  for (size_t i = 0; i < m_bins; ++i) {
1047  if (type == Histogram::Ordinary)
1048  value = gsl_histogram_get(m_histogram, i);
1049  else
1050  value += gsl_histogram_get(m_histogram, i);
1051 
1052  const double x = binRangesMin + i*width;
1053  lines.append(QLineF(x, prevValue, x, value));
1054  lines.append(QLineF(x, value, x + width, value));
1055  pointsLogical.append(QPointF(x+width/2, value));
1056 
1057  if (i == m_bins - 1)
1058  lines.append(QLineF(x + width, value, x + width, 0.));
1059 
1060  prevValue = value;
1061  }
1062  } else { //drop lines
1063  for (size_t i = 0; i < m_bins; ++i) {
1064  if (type == Histogram::Ordinary)
1065  value = gsl_histogram_get(m_histogram, i);
1066  else
1067  value += gsl_histogram_get(m_histogram, i);
1068 
1069  const double x = binRangesMin + i*width + width/2;
1070  lines.append(QLineF(x, 0., x, value));
1071  pointsLogical.append(QPointF(x, value));
1072  }
1073  }
1074 
1076  lines.append(QLineF(binRangesMax, 0., binRangesMin, 0.));
1077 }
1078 
1080  if (!m_histogram)
1081  return;
1082 
1083  const double width = (binRangesMax - binRangesMin)/m_bins;
1084  double value = 0.;
1085  if (lineType == Histogram::Bars) {
1086  for (size_t i = 0; i < m_bins; ++i) {
1087  if (type == Histogram::Ordinary)
1088  value = gsl_histogram_get(m_histogram,i);
1089  else
1090  value += gsl_histogram_get(m_histogram,i);
1091 
1092  const double y = binRangesMin + i*width;
1093  lines.append(QLineF(0., y, value, y));
1094  lines.append(QLineF(value, y, value, y + width));
1095  lines.append(QLineF(value, y + width, 0., y + width));
1096  pointsLogical.append(QPointF(value, y+width/2));
1097  }
1099  double prevValue = 0.;
1100  for (size_t i = 0; i < m_bins; ++i) {
1101  if (type == Histogram::Ordinary)
1102  value = gsl_histogram_get(m_histogram, i);
1103  else
1104  value += gsl_histogram_get(m_histogram, i);
1105 
1106  const double y = binRangesMin + i*width;
1107  lines.append(QLineF(prevValue, y, value, y));
1108  lines.append(QLineF(value, y, value, y + width));
1109  pointsLogical.append(QPointF(value, y+width/2));
1110 
1111  if (i == m_bins - 1)
1112  lines.append(QLineF(value, y + width, 0., y + width));
1113 
1114  prevValue = value;
1115  }
1116  } else { //drop lines
1117  for (size_t i = 0; i < m_bins; ++i) {
1118  if (type == Histogram::Ordinary)
1119  value = gsl_histogram_get(m_histogram, i);
1120  else
1121  value += gsl_histogram_get(m_histogram, i);
1122 
1123  const double y = binRangesMin + i*width + width/2;
1124  lines.append(QLineF(0., y, value, y));
1125  pointsLogical.append(QPointF(value, y));
1126  }
1127  }
1128 
1130  lines.append(QLineF(0., binRangesMin, 0., binRangesMax));
1131 }
1132 
1134  symbolsPath = QPainterPath();
1136  QPainterPath path = Symbol::pathFromStyle(symbolsStyle);
1137 
1138  QTransform trafo;
1139  trafo.scale(symbolsSize, symbolsSize);
1140  path = trafo.map(path);
1141  trafo.reset();
1142 
1143  if (symbolsRotationAngle != 0) {
1144  trafo.rotate(symbolsRotationAngle);
1145  path = trafo.map(path);
1146  }
1147 
1148  for (const auto& point : pointsScene) {
1149  trafo.reset();
1150  trafo.translate(point.x(), point.y());
1151  symbolsPath.addPath(trafo.map(path));
1152  }
1153  }
1154 
1156 }
1157 
1158 /*!
1159  recreates the value strings to be shown and recalculates their draw position.
1160  */
1162  valuesPath = QPainterPath();
1163  valuesPoints.clear();
1164  valuesStrings.clear();
1165 
1168  return;
1169  }
1170 
1171  //determine the value string for all points that are currently visible in the plot
1173  switch (type) {
1174  case Histogram::Ordinary:
1175  for (size_t i = 0; i < m_bins; ++i) {
1176  if (!visiblePoints[i]) continue;
1177  valuesStrings << valuesPrefix + QString::number(gsl_histogram_get(m_histogram, i)) + valuesSuffix;
1178  }
1179  break;
1180  case Histogram::Cumulative: {
1181  value = 0;
1182  for (size_t i = 0; i < m_bins; ++i) {
1183  if (!visiblePoints[i]) continue;
1184  value += gsl_histogram_get(m_histogram, i);
1185  valuesStrings << valuesPrefix + QString::number(value) + valuesSuffix;
1186  }
1187  break;
1188  }
1189  case Histogram::AvgShift:
1190  break;
1191  }
1192  } else if (valuesType == Histogram::ValuesCustomColumn) {
1193  if (!valuesColumn) {
1195  return;
1196  }
1197 
1198  const int endRow = qMin(pointsLogical.size(), valuesColumn->rowCount());
1199  const auto xColMode = valuesColumn->columnMode();
1200  for (int i = 0; i < endRow; ++i) {
1201  if (!visiblePoints[i]) continue;
1202 
1203  if ( !valuesColumn->isValid(i) || valuesColumn->isMasked(i) )
1204  continue;
1205 
1206  switch (xColMode) {
1209  break;
1212  valuesStrings << valuesPrefix + QString::number(valuesColumn->valueAt(i)) + valuesSuffix;
1213  break;
1216  break;
1221  break;
1222  }
1223  }
1224  }
1225 
1226  //Calculate the coordinates where to paint the value strings.
1227  //The coordinates depend on the actual size of the string.
1228  QPointF tempPoint;
1229  QFontMetrics fm(valuesFont);
1230  qreal w;
1231  const qreal h = fm.ascent();
1232  switch (valuesPosition) {
1234  for (int i = 0; i < valuesStrings.size(); i++) {
1235  w = fm.boundingRect(valuesStrings.at(i)).width();
1236  tempPoint.setX( pointsScene.at(i).x() -w/2);
1237  tempPoint.setY( pointsScene.at(i).y() - valuesDistance );
1238  valuesPoints.append(tempPoint);
1239  }
1240  break;
1242  for (int i = 0; i < valuesStrings.size(); i++) {
1243  w = fm.boundingRect(valuesStrings.at(i)).width();
1244  tempPoint.setX( pointsScene.at(i).x() -w/2);
1245  tempPoint.setY( pointsScene.at(i).y() + valuesDistance + h/2);
1246  valuesPoints.append(tempPoint);
1247  }
1248  break;
1249  case Histogram::ValuesLeft:
1250  for (int i = 0; i < valuesStrings.size(); i++) {
1251  w = fm.boundingRect(valuesStrings.at(i)).width();
1252  tempPoint.setX( pointsScene.at(i).x() - valuesDistance - w - 1);
1253  tempPoint.setY( pointsScene.at(i).y());
1254  valuesPoints.append(tempPoint);
1255  }
1256  break;
1258  for (int i = 0; i < valuesStrings.size(); i++) {
1259  tempPoint.setX( pointsScene.at(i).x() + valuesDistance - 1);
1260  tempPoint.setY( pointsScene.at(i).y() );
1261  valuesPoints.append(tempPoint);
1262  }
1263  break;
1264  }
1265 
1266  QTransform trafo;
1267  QPainterPath path;
1268  for (int i = 0; i < valuesPoints.size(); i++) {
1269  path = QPainterPath();
1270  path.addText( QPoint(0,0), valuesFont, valuesStrings.at(i) );
1271 
1272  trafo.reset();
1273  trafo.translate( valuesPoints.at(i).x(), valuesPoints.at(i).y() );
1274  if (valuesRotationAngle!=0)
1275  trafo.rotate( -valuesRotationAngle );
1276 
1277  valuesPath.addPath(trafo.map(path));
1278  }
1279 
1281 }
1282 
1284  fillPolygon.clear();
1285 
1288  return;
1289  }
1290 
1291  QVector<QLineF> fillLines;
1292  const auto* plot = static_cast<const CartesianPlot*>(q->parentAspect());
1293  const AbstractCoordinateSystem* cSystem = plot->coordinateSystem();
1294 
1295  //if there're no interpolation lines available (Histogram::NoLine selected), create line-interpolation,
1296  //use already available lines otherwise.
1297  if (lines.size())
1298  fillLines = lines;
1299  else {
1300  for (int i = 0; i < pointsLogical.count()-1; i++)
1301  fillLines.append(QLineF(pointsLogical.at(i), pointsLogical.at(i+1)));
1302  fillLines = cSystem->mapLogicalToScene(fillLines);
1303  }
1304 
1305  //no lines available (no points), nothing to do
1306  if (!fillLines.size())
1307  return;
1308 
1309  //create the filling polygon for the visible lines
1310 
1311  //in case the histogram is zoomed, handle the clipping on the l.h.s.
1312  const QPointF& firstPoint = fillLines.constFirst().p1();
1313  QPointF start;
1314  if (plot->xMin() > binRangesMin) {
1315  start = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMin() > 0 ? plot->yMin() : 0));
1316 
1317  if (start.x() != firstPoint.x())
1318  fillPolygon << QPointF(start.x(), firstPoint.y());
1319  }
1320 
1321  //add the first point of the fist visible line
1322  fillPolygon << firstPoint;
1323 
1324  //iterate over all visible lines and add unique points.
1325  //skip the last closing line, the filling polygon will be closed below.
1326  QPointF p1, p2;
1327  for (int i = 0; i < fillLines.size() - 1; ++i) {
1328  const QLineF& line = fillLines.at(i);
1329  p1 = line.p1();
1330  p2 = line.p2();
1331  if (i != 0 && p1 != fillLines.at(i-1).p2())
1332  fillPolygon << p1;
1333 
1334  fillPolygon << p2;
1335  }
1336 
1337  //in case the histogram is zoomed, handle the clipping on the r.h.s.
1338  const QPointF& lastPoint = fillLines.at(fillLines.size()-2).p2();
1339  QPointF end;
1340  if (plot->xMax() < binRangesMax) {
1341  end = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMin() > 0 ? plot->yMin() : 0));
1342 
1343  if (end.y() != lastPoint.y())
1344  fillPolygon << QPointF(end.x(), lastPoint.y());
1345  }
1346  else
1347  end = cSystem->mapLogicalToScene(QPointF(binRangesMax, plot->yMin() > 0 ? plot->yMin() : 0));
1348 
1349  //close the polygon
1350  fillPolygon << end;
1351  if (plot->xMin() > binRangesMin)
1352  fillPolygon << start;
1353 
1355 }
1356 
1358 
1359 }
1360 
1361 /*!
1362  recalculates the outer bounds and the shape of the curve.
1363  */
1365  //if (m_suppressRecalc)
1366  // return;
1367 
1368  prepareGeometryChange();
1369  curveShape = QPainterPath();
1370  if (lineType != Histogram::NoLine)
1372 
1374  curveShape.addPath(symbolsPath);
1375 
1377  curveShape.addPath(valuesPath);
1378 
1379  boundingRectangle = curveShape.boundingRect();
1380 
1381  boundingRectangle = boundingRectangle.united(fillPolygon.boundingRect());
1382 
1383  //TODO: when the selection is painted, line intersections are visible.
1384  //simplified() removes those artifacts but is horrible slow for curves with large number of points.
1385  //search for an alternative.
1386  //curveShape = curveShape.simplified();
1387 
1388  updatePixmap();
1389 }
1390 
1391 void HistogramPrivate::draw(QPainter* painter) {
1392  PERFTRACE(name().toLatin1() + ", HistogramPrivate::draw()");
1393 
1394  //drawing line
1395  if (lineType != Histogram::NoLine) {
1396  painter->setOpacity(lineOpacity);
1397  painter->setPen(linePen);
1398  painter->setBrush(Qt::NoBrush);
1399  painter->drawPath(linePath);
1400  }
1401 
1402  //draw filling
1403  if (fillingEnabled) {
1404  painter->setOpacity(fillingOpacity);
1405  painter->setPen(Qt::SolidLine);
1406  drawFilling(painter);
1407  }
1408 
1409  //draw symbols
1411  painter->setOpacity(symbolsOpacity);
1412  painter->setPen(symbolsPen);
1413  painter->setBrush(symbolsBrush);
1414  drawSymbols(painter);
1415  }
1416 
1417  //draw values
1419  painter->setOpacity(valuesOpacity);
1420  painter->setPen(valuesColor);
1421  painter->setBrush(Qt::SolidPattern);
1422  drawValues(painter);
1423  }
1424 }
1425 
1427  QPixmap pixmap(boundingRectangle.width(), boundingRectangle.height());
1428  if (boundingRectangle.width() == 0 || boundingRectangle.height() == 0) {
1429  m_pixmap = pixmap;
1432  return;
1433  }
1434  pixmap.fill(Qt::transparent);
1435  QPainter painter(&pixmap);
1436  painter.setRenderHint(QPainter::Antialiasing, true);
1437  painter.translate(-boundingRectangle.topLeft());
1438 
1439  draw(&painter);
1440  painter.end();
1441 
1442  m_pixmap = pixmap;
1445  update();
1446 }
1447 
1448 /*!
1449  Reimplementation of QGraphicsItem::paint(). This function does the actual painting of the curve.
1450  \sa QGraphicsItem::paint().
1451  */
1452 void HistogramPrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
1453  Q_UNUSED(option);
1454  Q_UNUSED(widget);
1455  if (!isVisible())
1456  return;
1457 
1458  painter->setPen(Qt::NoPen);
1459  painter->setBrush(Qt::NoBrush);
1460  painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
1461 
1462  if ( KSharedConfig::openConfig()->group("Settings_Worksheet").readEntry<bool>("DoubleBuffering", true) )
1463  painter->drawPixmap(boundingRectangle.topLeft(), m_pixmap); //draw the cached pixmap (fast)
1464  else
1465  draw(painter); //draw directly again (slow)
1466 
1467  if (m_hovered && !isSelected() && !m_printing) {
1469  QPixmap pix = m_pixmap;
1470  QPainter p(&pix);
1471  p.setCompositionMode(QPainter::CompositionMode_SourceIn); // source (shadow) pixels merged with the alpha channel of the destination (m_pixmap)
1472  p.fillRect(pix.rect(), QApplication::palette().color(QPalette::Shadow));
1473  p.end();
1474 
1475  m_hoverEffectImage = ImageTools::blurred(pix.toImage(), m_pixmap.rect(), 5);
1476  m_hoverEffectImageIsDirty = false;
1477  }
1478 
1479  painter->drawImage(boundingRectangle.topLeft(), m_hoverEffectImage, m_pixmap.rect());
1480  return;
1481  }
1482 
1483  if (isSelected() && !m_printing) {
1485  QPixmap pix = m_pixmap;
1486  QPainter p(&pix);
1487  p.setCompositionMode(QPainter::CompositionMode_SourceIn);
1488  p.fillRect(pix.rect(), QApplication::palette().color(QPalette::Highlight));
1489  p.end();
1490 
1491  m_selectionEffectImage = ImageTools::blurred(pix.toImage(), m_pixmap.rect(), 5);
1493  }
1494 
1495  painter->drawImage(boundingRectangle.topLeft(), m_selectionEffectImage, m_pixmap.rect());
1496  return;
1497  }
1498 }
1499 
1500 void HistogramPrivate::drawSymbols(QPainter* painter) {
1501  QPainterPath path = Symbol::pathFromStyle(symbolsStyle);
1502 
1503  QTransform trafo;
1504  trafo.scale(symbolsSize, symbolsSize);
1505  if (symbolsRotationAngle != 0)
1506  trafo.rotate(-symbolsRotationAngle);
1507 
1508  path = trafo.map(path);
1509 
1510  for (const auto& point : pointsScene) {
1511  trafo.reset();
1512  trafo.translate(point.x(), point.y());
1513  painter->drawPath(trafo.map(path));
1514  }
1515 }
1516 
1517 void HistogramPrivate::drawValues(QPainter* painter) {
1518  QTransform trafo;
1519  QPainterPath path;
1520  for (int i = 0; i < valuesPoints.size(); i++) {
1521  path = QPainterPath();
1522  path.addText( QPoint(0,0), valuesFont, valuesStrings.at(i) );
1523 
1524  trafo.reset();
1525  trafo.translate( valuesPoints.at(i).x(), valuesPoints.at(i).y() );
1526  if (valuesRotationAngle!=0)
1527  trafo.rotate(-valuesRotationAngle );
1528 
1529  painter->drawPath(trafo.map(path));
1530  }
1531 }
1532 
1533 void HistogramPrivate::drawFilling(QPainter* painter) {
1534  const QRectF& rect = fillPolygon.boundingRect();
1536  switch (fillingColorStyle) {
1538  painter->setBrush(QBrush(fillingFirstColor));
1539  break;
1540  }
1542  QLinearGradient linearGrad(rect.topLeft(), rect.topRight());
1543  linearGrad.setColorAt(0, fillingFirstColor);
1544  linearGrad.setColorAt(1, fillingSecondColor);
1545  painter->setBrush(QBrush(linearGrad));
1546  break;
1547  }
1549  QLinearGradient linearGrad(rect.topLeft(), rect.bottomLeft());
1550  linearGrad.setColorAt(0, fillingFirstColor);
1551  linearGrad.setColorAt(1, fillingSecondColor);
1552  painter->setBrush(QBrush(linearGrad));
1553  break;
1554  }
1556  QLinearGradient linearGrad(rect.topLeft(), rect.bottomRight());
1557  linearGrad.setColorAt(0, fillingFirstColor);
1558  linearGrad.setColorAt(1, fillingSecondColor);
1559  painter->setBrush(QBrush(linearGrad));
1560  break;
1561  }
1563  QLinearGradient linearGrad(rect.bottomLeft(), rect.topRight());
1564  linearGrad.setColorAt(0, fillingFirstColor);
1565  linearGrad.setColorAt(1, fillingSecondColor);
1566  painter->setBrush(QBrush(linearGrad));
1567  break;
1568  }
1570  QRadialGradient radialGrad(rect.center(), rect.width()/2);
1571  radialGrad.setColorAt(0, fillingFirstColor);
1572  radialGrad.setColorAt(1, fillingSecondColor);
1573  painter->setBrush(QBrush(radialGrad));
1574  break;
1575  }
1576  }
1578  if ( !fillingFileName.trimmed().isEmpty() ) {
1579  QPixmap pix(fillingFileName);
1580  switch (fillingImageStyle) {
1582  pix = pix.scaled(rect.size().toSize(),Qt::KeepAspectRatioByExpanding,Qt::SmoothTransformation);
1583  painter->setBrush(QBrush(pix));
1584  painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2);
1585  break;
1587  pix = pix.scaled(rect.size().toSize(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
1588  painter->setBrush(QBrush(pix));
1589  painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2);
1590  break;
1592  pix = pix.scaled(rect.size().toSize(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
1593  painter->setBrush(QBrush(pix));
1594  painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2);
1595  break;
1597  QPixmap backpix(rect.size().toSize());
1598  backpix.fill();
1599  QPainter p(&backpix);
1600  p.drawPixmap(QPointF(0,0),pix);
1601  p.end();
1602  painter->setBrush(QBrush(backpix));
1603  painter->setBrushOrigin(-pix.size().width()/2,-pix.size().height()/2);
1604  break;
1605  }
1607  painter->setBrush(QBrush(pix));
1608  break;
1610  painter->setBrush(QBrush(pix));
1611  painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2);
1612  }
1613  }
1615  painter->setBrush(QBrush(fillingFirstColor,fillingBrushStyle));
1616 
1617  painter->drawPolygon(fillPolygon);
1618 }
1619 
1620 void HistogramPrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) {
1621  const auto* plot = static_cast<const CartesianPlot*>(q->parentAspect());
1622  if (plot->mouseMode() == CartesianPlot::MouseMode::Selection && !isSelected()) {
1623  m_hovered = true;
1624  emit q->hovered();
1625  update();
1626  }
1627 }
1628 
1629 void HistogramPrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
1630  const auto* plot = static_cast<const CartesianPlot*>(q->parentAspect());
1631  if (plot->mouseMode() == CartesianPlot::MouseMode::Selection && m_hovered) {
1632  m_hovered = false;
1633  emit q->unhovered();
1634  update();
1635  }
1636 }
1637 
1638 bool HistogramPrivate::activateCurve(QPointF mouseScenePos, double maxDist) {
1639  Q_UNUSED(maxDist)
1640  if (!isVisible())
1641  return false;
1642 
1643  return curveShape.contains(mouseScenePos);
1644 }
1645 
1646 /*!
1647  * checks if the mousePress event was done near the histogram shape
1648  * and selects the graphics item if it is the case.
1649  * \p event
1650  */
1651 void HistogramPrivate::mousePressEvent(QGraphicsSceneMouseEvent* event) {
1652  if (static_cast<const CartesianPlot*>(q->parentAspect())->mouseMode()
1654  event->ignore();
1655  return QGraphicsItem::mousePressEvent(event);
1656  }
1657 
1658  if(q->activateCurve(event->pos())){
1659  setSelected(true);
1660  return;
1661  }
1662 
1663  event->ignore();
1664  setSelected(false);
1665  QGraphicsItem::mousePressEvent(event);
1666 }
1667 
1668 /*!
1669  * Is called in CartesianPlot::hoverMoveEvent where it is determined which curve to hover.
1670  * \p on
1671  */
1673  if(on == m_hovered)
1674  return; // don't update if state not changed
1675 
1676  m_hovered = on;
1677  on ? emit q->hovered() : emit q->unhovered();
1678  update();
1679 }
1680 
1681 //##############################################################################
1682 //################## Serialization/Deserialization ###########################
1683 //##############################################################################
1684 //! Save as XML
1685 void Histogram::save(QXmlStreamWriter* writer) const {
1686  Q_D(const Histogram);
1687 
1688  writer->writeStartElement("Histogram");
1689  writeBasicAttributes(writer);
1690  writeCommentElement(writer);
1691 
1692  //general
1693  writer->writeStartElement("general");
1694  WRITE_COLUMN(d->dataColumn, dataColumn);
1695  writer->writeAttribute( "type", QString::number(d->type) );
1696  writer->writeAttribute( "orientation", QString::number(d->orientation) );
1697  writer->writeAttribute( "binningMethod", QString::number(d->binningMethod) );
1698  writer->writeAttribute( "binCount", QString::number(d->binCount));
1699  writer->writeAttribute( "binWidth", QString::number(d->binWidth));
1700  writer->writeAttribute( "autoBinRanges", QString::number(d->autoBinRanges) );
1701  writer->writeAttribute( "binRangesMin", QString::number(d->binRangesMin) );
1702  writer->writeAttribute( "binRangesMax", QString::number(d->binRangesMax) );
1703  writer->writeAttribute( "visible", QString::number(d->isVisible()) );
1704  writer->writeEndElement();
1705 
1706  //Line
1707  writer->writeStartElement("line");
1708  writer->writeAttribute( "type", QString::number(d->lineType) );
1709  WRITE_QPEN(d->linePen);
1710  writer->writeAttribute( "opacity", QString::number(d->lineOpacity) );
1711  writer->writeEndElement();
1712 
1713  //Symbols
1714  writer->writeStartElement( "symbols" );
1715  writer->writeAttribute( "symbolsStyle", QString::number(static_cast<int>(d->symbolsStyle)) );
1716  writer->writeAttribute( "opacity", QString::number(d->symbolsOpacity) );
1717  writer->writeAttribute( "rotation", QString::number(d->symbolsRotationAngle) );
1718  writer->writeAttribute( "size", QString::number(d->symbolsSize) );
1719  WRITE_QBRUSH(d->symbolsBrush);
1720  WRITE_QPEN(d->symbolsPen);
1721  writer->writeEndElement();
1722 
1723  //Values
1724  writer->writeStartElement("values");
1725  writer->writeAttribute( "type", QString::number(d->valuesType) );
1726  WRITE_COLUMN(d->valuesColumn, valuesColumn);
1727  writer->writeAttribute( "position", QString::number(d->valuesPosition) );
1728  writer->writeAttribute( "distance", QString::number(d->valuesDistance) );
1729  writer->writeAttribute( "rotation", QString::number(d->valuesRotationAngle) );
1730  writer->writeAttribute( "opacity", QString::number(d->valuesOpacity) );
1731  writer->writeAttribute("numericFormat", QString(d->valuesNumericFormat));
1732  writer->writeAttribute("dateTimeFormat", d->valuesDateTimeFormat);
1733  writer->writeAttribute("precision", QString::number(d->valuesPrecision));
1734  writer->writeAttribute( "prefix", d->valuesPrefix );
1735  writer->writeAttribute( "suffix", d->valuesSuffix );
1736  WRITE_QCOLOR(d->valuesColor);
1737  WRITE_QFONT(d->valuesFont);
1738  writer->writeEndElement();
1739 
1740  //Filling
1741  writer->writeStartElement("filling");
1742  writer->writeAttribute( "enabled", QString::number(d->fillingEnabled) );
1743  writer->writeAttribute( "type", QString::number(static_cast<int>(d->fillingType)) );
1744  writer->writeAttribute( "colorStyle", QString::number(static_cast<int>(d->fillingColorStyle)) );
1745  writer->writeAttribute( "imageStyle", QString::number(static_cast<int>(d->fillingImageStyle)) );
1746  writer->writeAttribute( "brushStyle", QString::number(d->fillingBrushStyle) );
1747  writer->writeAttribute( "firstColor_r", QString::number(d->fillingFirstColor.red()) );
1748  writer->writeAttribute( "firstColor_g", QString::number(d->fillingFirstColor.green()) );
1749  writer->writeAttribute( "firstColor_b", QString::number(d->fillingFirstColor.blue()) );
1750  writer->writeAttribute( "secondColor_r", QString::number(d->fillingSecondColor.red()) );
1751  writer->writeAttribute( "secondColor_g", QString::number(d->fillingSecondColor.green()) );
1752  writer->writeAttribute( "secondColor_b", QString::number(d->fillingSecondColor.blue()) );
1753  writer->writeAttribute( "fileName", d->fillingFileName );
1754  writer->writeAttribute( "opacity", QString::number(d->fillingOpacity) );
1755  writer->writeEndElement();
1756 
1757  writer->writeEndElement(); //close "Histogram" section
1758 }
1759 
1760 //! Load from XML
1761 bool Histogram::load(XmlStreamReader* reader, bool preview) {
1762  Q_D(Histogram);
1763 
1764  if (!readBasicAttributes(reader))
1765  return false;
1766 
1767  KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used");
1768  QXmlStreamAttributes attribs;
1769  QString str;
1770 
1771  while (!reader->atEnd()) {
1772  reader->readNext();
1773  if (reader->isEndElement() && reader->name() == "Histogram")
1774  break;
1775 
1776  if (!reader->isStartElement())
1777  continue;
1778 
1779  if (reader->name() == "comment") {
1780  if (!readCommentElement(reader)) return false;
1781  } else if (!preview && reader->name() == "general") {
1782  attribs = reader->attributes();
1783 
1784  READ_COLUMN(dataColumn);
1786  READ_INT_VALUE("orientation", orientation, Histogram::HistogramOrientation);
1787  READ_INT_VALUE("binningMethod", binningMethod, Histogram::BinningMethod);
1788  READ_INT_VALUE("binCount", binCount, int);
1789  READ_DOUBLE_VALUE("binWidth", binWidth);
1790  READ_INT_VALUE("autoBinRanges", autoBinRanges, bool);
1791  READ_DOUBLE_VALUE("binRangesMin", binRangesMin);
1792  READ_DOUBLE_VALUE("binRangesMax", binRangesMax);
1793 
1794  str = attribs.value("visible").toString();
1795  if (str.isEmpty())
1796  reader->raiseWarning(attributeWarning.subs("visible").toString());
1797  else
1798  d->setVisible(str.toInt());
1799  } else if (!preview && reader->name() == "line") {
1800  attribs = reader->attributes();
1801 
1802  READ_INT_VALUE("type", lineType, Histogram::LineType);
1803  READ_QPEN(d->linePen);
1804  READ_DOUBLE_VALUE("opacity", lineOpacity);
1805  } else if (!preview && reader->name() == "symbols") {
1806  attribs = reader->attributes();
1807 
1808  READ_INT_VALUE("symbolsStyle", symbolsStyle, Symbol::Style);
1809  READ_DOUBLE_VALUE("opacity", symbolsOpacity);
1810  READ_DOUBLE_VALUE("rotation", symbolsRotationAngle);
1811  READ_DOUBLE_VALUE("size", symbolsSize);
1812 
1813  READ_QBRUSH(d->symbolsBrush);
1814  READ_QPEN(d->symbolsPen);
1815  } else if (!preview && reader->name() == "values") {
1816  attribs = reader->attributes();
1817 
1818  READ_INT_VALUE("type", valuesType, Histogram::ValuesType);
1819  READ_COLUMN(valuesColumn);
1820  READ_INT_VALUE("position", valuesPosition, Histogram::ValuesPosition);
1821  READ_DOUBLE_VALUE("distance", valuesRotationAngle);
1822  READ_DOUBLE_VALUE("rotation", valuesRotationAngle);
1823  READ_DOUBLE_VALUE("opacity", valuesOpacity);
1824 
1825  str = attribs.value("numericFormat").toString();
1826  if (str.isEmpty())
1827  reader->raiseWarning(attributeWarning.subs("numericFormat").toString());
1828  else
1829  d->valuesNumericFormat = *(str.toLatin1().data());
1830 
1831  READ_STRING_VALUE("dateTimeFormat", valuesDateTimeFormat);
1832  READ_INT_VALUE("precision", valuesPrecision, int);
1833 
1834  //don't produce any warning if no prefix or suffix is set (empty string is allowed here in xml)
1835  d->valuesPrefix = attribs.value("prefix").toString();
1836  d->valuesSuffix = attribs.value("suffix").toString();
1837 
1838  READ_QCOLOR(d->valuesColor);
1839  READ_QFONT(d->valuesFont);
1840  } else if (!preview && reader->name() == "filling") {
1841  attribs = reader->attributes();
1842 
1843  READ_INT_VALUE("enabled", fillingEnabled, bool);
1844  READ_INT_VALUE("type", fillingType, PlotArea::BackgroundType);
1845  READ_INT_VALUE("colorStyle", fillingColorStyle, PlotArea::BackgroundColorStyle);
1846  READ_INT_VALUE("imageStyle", fillingImageStyle, PlotArea::BackgroundImageStyle);
1847  READ_INT_VALUE("brushStyle", fillingBrushStyle, Qt::BrushStyle);
1848 
1849  str = attribs.value("firstColor_r").toString();
1850  if (str.isEmpty())
1851  reader->raiseWarning(attributeWarning.subs("firstColor_r").toString());
1852  else
1853  d->fillingFirstColor.setRed(str.toInt());
1854 
1855  str = attribs.value("firstColor_g").toString();
1856  if (str.isEmpty())
1857  reader->raiseWarning(attributeWarning.subs("firstColor_g").toString());
1858  else
1859  d->fillingFirstColor.setGreen(str.toInt());
1860 
1861  str = attribs.value("firstColor_b").toString();
1862  if (str.isEmpty())
1863  reader->raiseWarning(attributeWarning.subs("firstColor_b").toString());
1864  else
1865  d->fillingFirstColor.setBlue(str.toInt());
1866 
1867  str = attribs.value("secondColor_r").toString();
1868  if (str.isEmpty())
1869  reader->raiseWarning(attributeWarning.subs("secondColor_r").toString());
1870  else
1871  d->fillingSecondColor.setRed(str.toInt());
1872 
1873  str = attribs.value("secondColor_g").toString();
1874  if (str.isEmpty())
1875  reader->raiseWarning(attributeWarning.subs("secondColor_g").toString());
1876  else
1877  d->fillingSecondColor.setGreen(str.toInt());
1878 
1879  str = attribs.value("secondColor_b").toString();
1880  if (str.isEmpty())
1881  reader->raiseWarning(attributeWarning.subs("secondColor_b").toString());
1882  else
1883  d->fillingSecondColor.setBlue(str.toInt());
1884 
1885  d->fillingFileName = attribs.value("fileName").toString();
1886  READ_DOUBLE_VALUE("opacity", fillingOpacity);
1887  }
1888  }
1889  return true;
1890 }
1891 
1892 //##############################################################################
1893 //######################### Theme management ##################################
1894 //##############################################################################
1895 void Histogram::loadThemeConfig(const KConfig& config) {
1896  KConfigGroup group;
1897  if (config.hasGroup(QLatin1String("Theme")))
1898  group = config.group("XYCurve"); //when loading from the theme config, use the same properties as for XYCurve
1899  else
1900  group = config.group("Histogram");
1901 
1902  int index = parentAspect()->indexOfChild<Histogram>(this);
1903  const auto* plot = static_cast<const CartesianPlot*>(parentAspect());
1904  QColor themeColor;
1905  if (index<plot->themeColorPalette().size())
1906  themeColor = plot->themeColorPalette().at(index);
1907  else {
1908  if (plot->themeColorPalette().size())
1909  themeColor = plot->themeColorPalette().last();
1910  }
1911 
1912  QPen p;
1913 
1914  Q_D(Histogram);
1915  d->m_suppressRecalc = true;
1916 
1917  //Line
1918  p.setStyle((Qt::PenStyle) group.readEntry("LineStyle", (int)Qt::SolidLine));
1919  p.setWidthF(group.readEntry("LineWidth", Worksheet::convertToSceneUnits(1.0, Worksheet::Unit::Point)));
1920  p.setWidthF(group.readEntry("LineWidth", this->linePen().widthF()));
1921  p.setColor(themeColor);
1922  this->setLinePen(p);
1923  this->setLineOpacity(group.readEntry("LineOpacity", 1.0));
1924 
1925  //Symbol
1926  this->setSymbolsOpacity(group.readEntry("SymbolOpacity", 1.0));
1927 
1928  QBrush brush;
1929  brush.setStyle((Qt::BrushStyle)group.readEntry("SymbolFillingStyle", (int)Qt::SolidPattern));
1930  brush.setColor(themeColor);
1931  this->setSymbolsBrush(brush);
1932  p.setStyle((Qt::PenStyle)group.readEntry("SymbolBorderStyle", (int)Qt::SolidLine));
1933  p.setColor(themeColor);
1934  p.setWidthF(group.readEntry("SymbolBorderWidth", Worksheet::convertToSceneUnits(0.0, Worksheet::Unit::Point)));
1935  this->setSymbolsPen(p);
1936 
1937  //Values
1938  this->setValuesOpacity(group.readEntry("ValuesOpacity", 1.0));
1939  this->setValuesColor(group.readEntry("ValuesColor", themeColor));
1940 
1941  //Filling
1942  this->setFillingBrushStyle((Qt::BrushStyle)group.readEntry("FillingBrushStyle", (int)Qt::SolidPattern));
1943  this->setFillingColorStyle((PlotArea::BackgroundColorStyle)group.readEntry("FillingColorStyle", static_cast<int>(PlotArea::BackgroundColorStyle::SingleColor)));
1944  this->setFillingOpacity(group.readEntry("FillingOpacity", 1.0));
1945  this->setFillingFirstColor(themeColor);
1946  this->setFillingSecondColor(group.readEntry("FillingSecondColor", QColor(Qt::black)));
1947  this->setFillingType((PlotArea::BackgroundType)group.readEntry("FillingType", static_cast<int>(PlotArea::BackgroundType::Color)));
1948 
1949  //Error Bars
1950  //TODO:
1951 // p.setStyle((Qt::PenStyle)group.readEntry("ErrorBarsStyle",(int) this->errorBarsPen().style()));
1952 // p.setWidthF(group.readEntry("ErrorBarsWidth", this->errorBarsPen().widthF()));
1953 // p.setColor(themeColor);
1954 // this->setErrorBarsPen(p);
1955 // this->setErrorBarsOpacity(group.readEntry("ErrorBarsOpacity",this->errorBarsOpacity()));
1956 
1957  d->m_suppressRecalc = false;
1958  d->recalcShapeAndBoundingRect();
1959 }
1960 
1961 void Histogram::saveThemeConfig(const KConfig& config) {
1962  KConfigGroup group = config.group("Histogram");
1963 
1964  //Line
1965  group.writeEntry("LineOpacity", this->lineOpacity());
1966  group.writeEntry("LineStyle",(int) this->linePen().style());
1967  group.writeEntry("LineWidth", this->linePen().widthF());
1968 
1969  //Error Bars
1970 // group.writeEntry("ErrorBarsCapSize",this->errorBarsCapSize());
1971 // group.writeEntry("ErrorBarsOpacity",this->errorBarsOpacity());
1972 // group.writeEntry("ErrorBarsColor",(QColor) this->errorBarsPen().color());
1973 // group.writeEntry("ErrorBarsStyle",(int) this->errorBarsPen().style());
1974 // group.writeEntry("ErrorBarsWidth", this->errorBarsPen().widthF());
1975 
1976  //Filling
1977  group.writeEntry("FillingBrushStyle",(int) this->fillingBrushStyle());
1978  group.writeEntry("FillingColorStyle",(int) this->fillingColorStyle());
1979  group.writeEntry("FillingOpacity", this->fillingOpacity());
1980  group.writeEntry("FillingSecondColor",(QColor) this->fillingSecondColor());
1981  group.writeEntry("FillingType",(int) this->fillingType());
1982 
1983  //Symbol
1984  group.writeEntry("SymbolOpacity", this->symbolsOpacity());
1985 
1986  //Values
1987  group.writeEntry("ValuesOpacity", this->valuesOpacity());
1988  group.writeEntry("ValuesColor", (QColor) this->valuesColor());
1989  group.writeEntry("ValuesFont", this->valuesFont());
1990 
1991  int index = parentAspect()->indexOfChild<Histogram>(this);
1992  if (index < 5) {
1993  KConfigGroup themeGroup = config.group("Theme");
1994  for (int i = index; i < 5; i++) {
1995  QString s = "ThemePaletteColor" + QString::number(i+1);
1996  themeGroup.writeEntry(s,(QColor) this->linePen().color());
1997  }
1998  }
1999 }
AspectType
STD_SETTER_CMD_IMPL_F_S(Histogram, SetLineOpacity, qreal, lineOpacity, updatePixmap)
static const QRgb white
Definition: ImageEditor.cpp:37
static const QRgb black
Definition: ImageEditor.cpp:38
Base class of all persistent objects in a Project.
void info(const QString &text)
Implementations should call this whenever status information should be given to the user.
AspectType type() const
bool readCommentElement(XmlStreamReader *)
Load comment from an XML element.
int indexOfChild(const AbstractAspect *child, ChildIndexFlags flags={}) const
Return (0 based) index of child in the list of children inheriting from class T.
AbstractAspect * parent(AspectType type) const
In the parent-child hierarchy, return the first parent of type.
void aspectAboutToBeRemoved(const AbstractAspect *)
Emitted before an aspect is removed from its parent.
QString name() const
void writeBasicAttributes(QXmlStreamWriter *) const
Save name and creation time to XML.
AbstractAspect * parentAspect() const
Return my parent Aspect or 0 if I currently don't have one.
void exec(QUndoCommand *)
Execute the given command, pushing it on the undoStack() if available.
bool readBasicAttributes(XmlStreamReader *)
Load name and creation time from XML.
void writeCommentElement(QXmlStreamWriter *) const
Save the comment to XML.
AbstractAspectPrivate * d
Interface definition for data with column logic.
virtual double valueAt(int row) const
Return the double value in row 'row'.
bool isMasked(int row) const
Return whether a certain row is masked.
virtual QString textAt(int row) const
Return the content of row 'row'.
virtual int rowCount() const =0
Return the data vector size.
virtual double maximum(int count=0) const
virtual double minimum(int count=0) const
virtual QDateTime dateTimeAt(int row) const
Return the QDateTime in row 'row'.
void dataChanged(const AbstractColumn *source)
Data of the column has changed.
bool isValid(int row) const
Convenience method for mode-independent testing of validity.
virtual ColumnMode columnMode() const =0
Return the column mode.
Base class of all worksheet coordinate systems.
virtual QVector< QPointF > mapLogicalToScene(const QVector< QPointF > &, MappingFlags flags=MappingFlag::DefaultMapping) const =0
Cartesian coordinate system for plots.
A xy-plot.
Definition: CartesianPlot.h:58
MouseMode mouseMode() const
Aspect that manages a column.
Definition: Column.h:42
Definition: Curve.h:34
Histogram::HistogramOrientation orientation
void contextMenuEvent(QGraphicsSceneContextMenuEvent *) override
Definition: Histogram.cpp:814
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *widget=nullptr) override
Definition: Histogram.cpp:1452
Symbol::Style symbolsStyle
gsl_histogram * m_histogram
QPainterPath shape() const override
Definition: Histogram.cpp:810
~HistogramPrivate() override
Definition: Histogram.cpp:722
QPainterPath linePath
Histogram::ValuesPosition valuesPosition
PlotArea::BackgroundImageStyle fillingImageStyle
bool m_selectionEffectImageIsDirty
Qt::BrushStyle fillingBrushStyle
QPainterPath valuesPath
Histogram::ValuesType valuesType
void setHover(bool on)
Definition: Histogram.cpp:1672
HistogramPrivate(Histogram *owner)
Definition: Histogram.cpp:717
const AbstractColumn * valuesColumn
QPainterPath symbolsPath
void draw(QPainter *)
Definition: Histogram.cpp:1391
Histogram *const q
void hoverLeaveEvent(QGraphicsSceneHoverEvent *) override
Definition: Histogram.cpp:1629
void mousePressEvent(QGraphicsSceneMouseEvent *) override
Definition: Histogram.cpp:1651
void drawFilling(QPainter *)
Definition: Histogram.cpp:1533
void drawSymbols(QPainter *)
Definition: Histogram.cpp:1500
Histogram::HistogramType type
bool activateCurve(QPointF mouseScenePos, double maxDist)
Definition: Histogram.cpp:1638
QVector< QPointF > pointsLogical
QImage m_selectionEffectImage
const AbstractColumn * dataColumn
double getMaximumOccuranceofHistogram()
Definition: Histogram.cpp:735
double getYMaximum()
Definition: Histogram.cpp:797
void updateOrientation()
Definition: Histogram.cpp:985
double getXMaximum()
Definition: Histogram.cpp:777
double getXMinimum()
Definition: Histogram.cpp:767
std::vector< bool > visiblePoints
QPainterPath curveShape
bool swapVisible(bool on)
Definition: Histogram.cpp:818
QString name() const
Definition: Histogram.cpp:727
void hoverEnterEvent(QGraphicsSceneHoverEvent *) override
Definition: Histogram.cpp:1620
QVector< QPointF > valuesPoints
void recalcShapeAndBoundingRect()
Definition: Histogram.cpp:1364
double getYMinimum()
Definition: Histogram.cpp:787
Histogram::LineType lineType
QString valuesDateTimeFormat
void updateErrorBars()
Definition: Histogram.cpp:1357
QVector< QPointF > pointsScene
void horizontalHistogram()
Definition: Histogram.cpp:1079
QVector< QString > valuesStrings
PlotArea::BackgroundType fillingType
PlotArea::BackgroundColorStyle fillingColorStyle
QVector< QLineF > lines
QRectF boundingRect() const override
Definition: Histogram.cpp:731
void verticalHistogram()
Definition: Histogram.cpp:1025
void recalcHistogram()
Definition: Histogram.cpp:873
void drawValues(QPainter *)
Definition: Histogram.cpp:1517
Histogram::BinningMethod binningMethod
HistogramSetAutoBinRangesCmd(HistogramPrivate *private_obj, bool autoBinRanges)
Definition: Histogram.cpp:338
HistogramPrivate * m_private
Definition: Histogram.cpp:371
A 2D-curve, provides an interface for editing many properties of the curve.
Definition: Histogram.h:42
QMenu * createContextMenu() override
Return a new context menu.
Definition: Histogram.cpp:150
void dataChanged()
QIcon icon() const override
Definition: Histogram.cpp:161
@ ValuesCustomColumn
Definition: Histogram.h:50
@ ValuesBinEntries
Definition: Histogram.h:50
@ NoValues
Definition: Histogram.h:50
bool activateCurve(QPointF mouseScenePos, double maxDist=-1) override
Definition: Histogram.cpp:185
QString & dataColumnPath() const
Definition: Histogram.cpp:209
QAction * visibilityAction
Definition: Histogram.h:160
void recalcHistogram()
Definition: Histogram.cpp:668
void dataColumnAboutToBeRemoved(const AbstractAspect *)
Definition: Histogram.cpp:690
void autoBinRangesChanged(bool)
void visibilityChanged(bool)
void setPrinting(bool on) override
Switches the printing mode on/off.
Definition: Histogram.cpp:180
void save(QXmlStreamWriter *) const override
Save as XML.
Definition: Histogram.cpp:1685
double getYMinimum() const
Definition: Histogram.cpp:266
bool load(XmlStreamReader *, bool preview) override
Load from XML.
Definition: Histogram.cpp:1761
HistogramOrientation
Definition: Histogram.h:47
@ Horizontal
Definition: Histogram.h:47
@ Vertical
Definition: Histogram.h:47
void initActions()
Definition: Histogram.cpp:144
@ Cumulative
Definition: Histogram.h:46
@ AvgShift
Definition: Histogram.h:46
@ Ordinary
Definition: Histogram.h:46
double getXMaximum() const
Definition: Histogram.cpp:270
@ DropLines
Definition: Histogram.h:49
@ Envelope
Definition: Histogram.h:49
void setVisible(bool on) override
Show/hide the element.
Definition: Histogram.cpp:170
void loadThemeConfig(const KConfig &) override
Definition: Histogram.cpp:1895
double getYMaximum() const
Definition: Histogram.cpp:262
ValuesPosition
Definition: Histogram.h:51
@ ValuesAbove
Definition: Histogram.h:51
@ ValuesUnder
Definition: Histogram.h:51
@ ValuesRight
Definition: Histogram.h:51
@ ValuesLeft
Definition: Histogram.h:51
void setHover(bool on) override
Definition: Histogram.cpp:190
void saveThemeConfig(const KConfig &) override
Definition: Histogram.cpp:1961
bool isVisible() const override
Return whether the element is (at least) partially visible.
Definition: Histogram.cpp:175
QString & valuesColumnPath() const
Definition: Histogram.cpp:229
@ SquareRoot
Definition: Histogram.h:48
@ ByNumber
Definition: Histogram.h:48
void updateValues()
Definition: Histogram.cpp:686
HistogramPrivate *const d_ptr
Definition: Histogram.h:154
void binRangesMaxChanged(double)
void visibilityChangedSlot()
Definition: Histogram.cpp:709
void valuesColumnAboutToBeRemoved(const AbstractAspect *)
Definition: Histogram.cpp:698
void binRangesMinChanged(double)
double getXMinimum() const
Definition: Histogram.cpp:274
void retransform() override
Definition: Histogram.cpp:664
void init()
Definition: Histogram.cpp:75
void handleResize(double horizontalRatio, double verticalRatio, bool pageResize) override
Definition: Histogram.cpp:673
Histogram(const QString &name)
Definition: Histogram.cpp:63
QGraphicsItem * graphicsItem() const override
Return the graphics item representing this element.
Definition: Histogram.cpp:165
static QImage blurred(const QImage &image, QRect rect, int radius, bool alphaOnly=false)
Definition: ImageTools.cpp:35
BackgroundColorStyle
Definition: PlotArea.h:46
BackgroundImageStyle
Definition: PlotArea.h:48
BackgroundType
Definition: PlotArea.h:45
static QPainterPath pathFromStyle(Symbol::Style)
Definition: Symbol.cpp:43
Style
Definition: Symbol.h:38
Base class for all Worksheet children.
static QPainterPath shapeFromPath(const QPainterPath &, const QPen &)
QMenu * createContextMenu() override
Return a new context menu.
Top-level container for worksheet elements like plot, labels, etc.
Definition: Worksheet.h:46
void suppressSelectionChangedEvent(bool)
Definition: Worksheet.cpp:408
static double convertToSceneUnits(const double value, const Worksheet::Unit unit)
Definition: Worksheet.cpp:113
ErrorBarsType
Definition: XYCurve.h:65
XML stream parser that supports errors as well as warnings. This class also adds line and column numb...
void raiseWarning(const QString &)
#define READ_DOUBLE_VALUE(name, var)
Definition: macros.h:475
#define WRITE_QCOLOR(color)
Definition: macros.h:286
#define CLASS_SHARED_D_READER_IMPL(classname, type, method, var)
Definition: macros.h:154
#define DEBUG(x)
Definition: macros.h:50
#define READ_COLUMN(columnName)
Definition: macros.h:462
#define READ_INT_VALUE(name, var, type)
Definition: macros.h:468
#define READ_QPEN(pen)
Definition: macros.h:324
#define WRITE_QPEN(pen)
Definition: macros.h:315
#define READ_QCOLOR(color)
Definition: macros.h:293
#define READ_QBRUSH(brush)
Definition: macros.h:418
#define STD_SWAP_METHOD_SETTER_CMD_IMPL(class_name, cmd_name, value_type, method_name)
Definition: macros.h:250
#define BASIC_SHARED_D_READER_IMPL(classname, type, method, var)
Definition: macros.h:127
#define READ_STRING_VALUE(name, var)
Definition: macros.h:482
#define WRITE_QBRUSH(brush)
Definition: macros.h:410
#define WRITE_COLUMN(column, columnName)
Definition: macros.h:451
#define WRITE_QFONT(font)
Definition: macros.h:361
#define READ_QFONT(font)
Definition: macros.h:370
@ Shadow
Definition: OriginObj.h:71
#define i18n(m)
Definition: nsl_common.h:38
#define PERFTRACE(msg)
Definition: trace.h:57