"Fossies" - the Fresh Open Source Software Archive

Member "labplot-2.8.2/src/backend/worksheet/plots/cartesian/Histogram.cpp" (24 Feb 2021, 72863 Bytes) of package /linux/privat/labplot-2.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Histogram.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.1_vs_2.8.2.

    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"
   39 #include "backend/core/column/Column.h"
   40 #include "backend/worksheet/plots/cartesian/CartesianCoordinateSystem.h"
   41 #include "backend/worksheet/plots/cartesian/CartesianPlot.h"
   42 #include "backend/lib/commandtemplates.h"
   43 #include "backend/worksheet/Worksheet.h"
   44 #include "backend/lib/XmlStreamReader.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 
   75 void Histogram::init() {
   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 
  144 void Histogram::initActions() {
  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 
  150 QMenu* Histogram::createContextMenu() {
  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
  199 BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::HistogramType, type, type)
  200 BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::HistogramOrientation, orientation, orientation)
  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
  214 BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::LineType, lineType, lineType)
  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
  227 BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::ValuesType, valuesType, valuesType)
  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)
  246 BASIC_SHARED_D_READER_IMPL(Histogram, PlotArea::BackgroundType, fillingType, fillingType)
  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
  256 BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::ErrorType, errorType, errorType)
  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
  293             connect(column, &AbstractColumn::dataChanged, this, &Histogram::recalcHistogram);
  294             connect(column->parentAspect(), &AbstractAspect::aspectAboutToBeRemoved,
  295                     this, &Histogram::dataColumnAboutToBeRemoved);
  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 {
  344         m_autoBinRangesOld = m_private->autoBinRanges;
  345         m_private->autoBinRanges = m_autoBinRanges;
  346         if (m_autoBinRanges) {
  347             m_binRangesMinOld = m_private->binRangesMin;
  348             m_binRangesMaxOld = m_private->binRangesMax;
  349             m_private->q->recalcHistogram();
  350         }
  351         emit m_private->q->autoBinRangesChanged(m_autoBinRanges);
  352     };
  353 
  354     void undo() override {
  355         m_private->autoBinRanges = m_autoBinRangesOld;
  356         if (!m_autoBinRangesOld) {
  357             if (m_private->binRangesMin != m_binRangesMinOld) {
  358                 m_private->binRangesMin = m_binRangesMinOld;
  359                 emit m_private->q->binRangesMinChanged(m_private->binRangesMin);
  360             }
  361             if (m_private->binRangesMax != m_binRangesMaxOld) {
  362                 m_private->binRangesMax = m_binRangesMaxOld;
  363                 emit m_private->q->binRangesMaxChanged(m_private->binRangesMax);
  364             }
  365             m_private->recalcHistogram();
  366         }
  367         emit m_private->q->autoBinRangesChanged(m_autoBinRangesOld);
  368     }
  369 
  370 private:
  371     HistogramPrivate* m_private;
  372     bool m_autoBinRanges;
  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);
  478             connect(column->parentAspect(), &AbstractAspect::aspectAboutToBeRemoved,
  479                     this, &Histogram::valuesColumnAboutToBeRemoved);
  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 //##############################################################################
  664 void Histogram::retransform() {
  665     d_ptr->retransform();
  666 }
  667 
  668 void Histogram::recalcHistogram() {
  669     d_ptr->recalcHistogram();
  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 
  686 void Histogram::updateValues() {
  687     d_ptr->updateValues();
  688 }
  689 
  690 void Histogram::dataColumnAboutToBeRemoved(const AbstractAspect* aspect) {
  691     Q_D(Histogram);
  692     if (aspect == d->dataColumn) {
  693         d->dataColumn = nullptr;
  694         d->retransform();
  695     }
  696 }
  697 
  698 void Histogram::valuesColumnAboutToBeRemoved(const AbstractAspect* aspect) {
  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 //##############################################################################
  709 void Histogram::visibilityChangedSlot() {
  710     Q_D(const Histogram);
  711     this->setVisible(!d->isVisible());
  712 }
  713 
  714 //##############################################################################
  715 //######################### Private implementation #############################
  716 //##############################################################################
  717 HistogramPrivate::HistogramPrivate(Histogram *owner) : q(owner) {
  718     setFlag(QGraphicsItem::ItemIsSelectable, true);
  719     setAcceptHoverEvents(false);
  720 }
  721 
  722 HistogramPrivate::~HistogramPrivate() {
  723     if (m_histogram)
  724         gsl_histogram_free(m_histogram);
  725 }
  726 
  727 QString HistogramPrivate::name() const {
  728     return q->name();
  729 }
  730 
  731 QRectF HistogramPrivate::boundingRect() const {
  732     return boundingRectangle;
  733 }
  734 
  735 double HistogramPrivate::getMaximumOccuranceofHistogram() {
  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 
  767 double HistogramPrivate::getXMinimum() {
  768     switch (orientation) {
  769     case Histogram::Vertical:
  770         return autoBinRanges ? dataColumn->minimum() : binRangesMin;
  771     case Histogram::Horizontal:
  772         return 0;
  773     }
  774     return INFINITY;
  775 }
  776 
  777 double HistogramPrivate::getXMaximum() {
  778     switch (orientation) {
  779     case Histogram::Vertical:
  780         return autoBinRanges ? dataColumn->maximum() : binRangesMax;
  781     case Histogram::Horizontal:
  782         return getMaximumOccuranceofHistogram();
  783     }
  784     return -INFINITY;
  785 }
  786 
  787 double HistogramPrivate::getYMinimum() {
  788     switch (orientation) {
  789     case Histogram::Vertical:
  790         return 0;
  791     case Histogram::Horizontal:
  792         return autoBinRanges ? dataColumn->minimum() : binRangesMin;
  793     }
  794     return INFINITY;
  795 }
  796 
  797 double HistogramPrivate::getYMaximum() {
  798     switch (orientation) {
  799     case Histogram::Vertical:
  800         return getMaximumOccuranceofHistogram();
  801     case Histogram::Horizontal:
  802         return autoBinRanges ? dataColumn->maximum() : binRangesMax;
  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 
  818 bool HistogramPrivate::swapVisible(bool on) {
  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 */
  838 void HistogramPrivate::retransform() {
  839     if (m_suppressRetransform)
  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();
  859         recalcShapeAndBoundingRect();
  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  */
  873 void HistogramPrivate::recalcHistogram() {
  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()) {
  895                 binRangesMin = dataColumn->minimum();
  896                 emit q->binRangesMinChanged(binRangesMin);
  897             }
  898 
  899             if (binRangesMax != dataColumn->maximum()) {
  900                 binRangesMax = dataColumn->maximum();
  901                 emit q->binRangesMaxChanged(binRangesMax);
  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:
  916             m_bins = (size_t) (binRangesMax-binRangesMin)/binWidth;
  917             break;
  918         case Histogram::SquareRoot:
  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()) {
  951             case AbstractColumn::ColumnMode::Numeric:
  952             case AbstractColumn::ColumnMode::Integer:
  953             case AbstractColumn::ColumnMode::BigInt:
  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;
  959             case AbstractColumn::ColumnMode::DateTime:
  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;
  965             case AbstractColumn::ColumnMode::Text:
  966             case AbstractColumn::ColumnMode::Month:
  967             case AbstractColumn::ColumnMode::Day:
  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 
  979 void HistogramPrivate::updateType() {
  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 
  985 void HistogramPrivate::updateOrientation() {
  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   */
  995 void HistogramPrivate::updateLines() {
  996     PERFTRACE(name().toLatin1() + ", HistogramPrivate::updateLines()");
  997 
  998     linePath = QPainterPath();
  999     lines.clear();
 1000     pointsLogical.clear();
 1001     pointsScene.clear();
 1002 
 1003     if (orientation == Histogram::Vertical)
 1004         verticalHistogram();
 1005     else
 1006         horizontalHistogram();
 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();
 1022     recalcShapeAndBoundingRect();
 1023 }
 1024 
 1025 void HistogramPrivate::verticalHistogram() {
 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         }
 1044     } else if (lineType == Histogram::NoLine || lineType == Histogram::Envelope) {
 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 
 1075     if (lineType != Histogram::DropLines)
 1076         lines.append(QLineF(binRangesMax, 0., binRangesMin, 0.));
 1077 }
 1078 
 1079 void HistogramPrivate::horizontalHistogram() {
 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         }
 1098     } else if (lineType == Histogram::NoLine || lineType == Histogram::Envelope) {
 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 
 1129     if (lineType != Histogram::DropLines)
 1130         lines.append(QLineF(0., binRangesMin, 0., binRangesMax));
 1131 }
 1132 
 1133 void HistogramPrivate::updateSymbols() {
 1134     symbolsPath = QPainterPath();
 1135     if (symbolsStyle != Symbol::Style::NoSymbols) {
 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 
 1155     recalcShapeAndBoundingRect();
 1156 }
 1157 
 1158 /*!
 1159   recreates the value strings to be shown and recalculates their draw position.
 1160   */
 1161 void HistogramPrivate::updateValues() {
 1162     valuesPath = QPainterPath();
 1163     valuesPoints.clear();
 1164     valuesStrings.clear();
 1165 
 1166     if (valuesType == Histogram::NoValues || !m_histogram) {
 1167         recalcShapeAndBoundingRect();
 1168         return;
 1169     }
 1170 
 1171     //determine the value string for all points that are currently visible in the plot
 1172     if (valuesType == Histogram::ValuesBinEntries) {
 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) {
 1194             recalcShapeAndBoundingRect();
 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) {
 1207             case AbstractColumn::ColumnMode::Numeric:
 1208                 valuesStrings << valuesPrefix + QString::number(valuesColumn->valueAt(i), valuesNumericFormat, valuesPrecision) + valuesSuffix;
 1209                 break;
 1210             case AbstractColumn::ColumnMode::Integer:
 1211             case AbstractColumn::ColumnMode::BigInt:
 1212                 valuesStrings << valuesPrefix + QString::number(valuesColumn->valueAt(i)) + valuesSuffix;
 1213                 break;
 1214             case AbstractColumn::ColumnMode::Text:
 1215                 valuesStrings << valuesPrefix + valuesColumn->textAt(i) + valuesSuffix;
 1216                 break;
 1217             case AbstractColumn::ColumnMode::DateTime:
 1218             case AbstractColumn::ColumnMode::Month:
 1219             case AbstractColumn::ColumnMode::Day:
 1220                 valuesStrings << valuesPrefix + valuesColumn->dateTimeAt(i).toString(valuesDateTimeFormat) + valuesSuffix;
 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) {
 1233     case Histogram::ValuesAbove:
 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;
 1241     case Histogram::ValuesUnder:
 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;
 1257     case Histogram::ValuesRight:
 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 
 1280     recalcShapeAndBoundingRect();
 1281 }
 1282 
 1283 void HistogramPrivate::updateFilling() {
 1284     fillPolygon.clear();
 1285 
 1286     if (!fillingEnabled || lineType == Histogram::DropLines) {
 1287         recalcShapeAndBoundingRect();
 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 
 1354     recalcShapeAndBoundingRect();
 1355 }
 1356 
 1357 void HistogramPrivate::updateErrorBars() {
 1358 
 1359 }
 1360 
 1361 /*!
 1362   recalculates the outer bounds and the shape of the curve.
 1363   */
 1364 void HistogramPrivate::recalcShapeAndBoundingRect() {
 1365     //if (m_suppressRecalc)
 1366     //  return;
 1367 
 1368     prepareGeometryChange();
 1369     curveShape = QPainterPath();
 1370     if (lineType != Histogram::NoLine)
 1371         curveShape.addPath(WorksheetElement::shapeFromPath(linePath, linePen));
 1372 
 1373     if (symbolsStyle != Symbol::Style::NoSymbols)
 1374         curveShape.addPath(symbolsPath);
 1375 
 1376     if (valuesType != Histogram::NoValues)
 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
 1410     if (symbolsStyle != Symbol::Style::NoSymbols) {
 1411         painter->setOpacity(symbolsOpacity);
 1412         painter->setPen(symbolsPen);
 1413         painter->setBrush(symbolsBrush);
 1414         drawSymbols(painter);
 1415     }
 1416 
 1417     //draw values
 1418     if (valuesType != Histogram::NoValues) {
 1419         painter->setOpacity(valuesOpacity);
 1420         painter->setPen(valuesColor);
 1421         painter->setBrush(Qt::SolidPattern);
 1422         drawValues(painter);
 1423     }
 1424 }
 1425 
 1426 void HistogramPrivate::updatePixmap() {
 1427     QPixmap pixmap(boundingRectangle.width(), boundingRectangle.height());
 1428     if (boundingRectangle.width() == 0 || boundingRectangle.height() == 0) {
 1429         m_pixmap = pixmap;
 1430         m_hoverEffectImageIsDirty = true;
 1431         m_selectionEffectImageIsDirty = true;
 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;
 1443     m_hoverEffectImageIsDirty = true;
 1444     m_selectionEffectImageIsDirty = true;
 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) {
 1468         if (m_hoverEffectImageIsDirty) {
 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) {
 1484         if (m_selectionEffectImageIsDirty) {
 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);
 1492             m_selectionEffectImageIsDirty = false;
 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();
 1535     if (fillingType == PlotArea::BackgroundType::Color) {
 1536         switch (fillingColorStyle) {
 1537         case PlotArea::BackgroundColorStyle::SingleColor: {
 1538             painter->setBrush(QBrush(fillingFirstColor));
 1539             break;
 1540         }
 1541         case PlotArea::BackgroundColorStyle::HorizontalLinearGradient: {
 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         }
 1548         case PlotArea::BackgroundColorStyle::VerticalLinearGradient: {
 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         }
 1555         case PlotArea::BackgroundColorStyle::TopLeftDiagonalLinearGradient: {
 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         }
 1562         case PlotArea::BackgroundColorStyle::BottomLeftDiagonalLinearGradient: {
 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         }
 1569         case PlotArea::BackgroundColorStyle::RadialGradient: {
 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         }
 1577     } else if (fillingType == PlotArea::BackgroundType::Image) {
 1578         if ( !fillingFileName.trimmed().isEmpty() ) {
 1579             QPixmap pix(fillingFileName);
 1580             switch (fillingImageStyle) {
 1581             case PlotArea::BackgroundImageStyle::ScaledCropped:
 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;
 1586             case PlotArea::BackgroundImageStyle::Scaled:
 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;
 1591             case PlotArea::BackgroundImageStyle::ScaledAspectRatio:
 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;
 1596             case PlotArea::BackgroundImageStyle::Centered: {
 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             }
 1606             case PlotArea::BackgroundImageStyle::Tiled:
 1607                 painter->setBrush(QBrush(pix));
 1608                 break;
 1609             case PlotArea::BackgroundImageStyle::CenterTiled:
 1610                 painter->setBrush(QBrush(pix));
 1611                 painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2);
 1612             }
 1613         }
 1614     } else if (fillingType == PlotArea::BackgroundType::Pattern)
 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()
 1653         != CartesianPlot::MouseMode::Selection) {
 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  */
 1672 void HistogramPrivate::setHover(bool on) {
 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);
 1785             READ_INT_VALUE("type", type, Histogram::HistogramType);
 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 }