File indexing completed on 2024-05-12 15:27:56

0001 /***************************************************************************
0002     File                 : CartesianPlotDock.cpp
0003     Project              : LabPlot
0004     Description          : widget for cartesian plot properties
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2011-2020 by Alexander Semke (alexander.semke@web.de)
0007     Copyright            : (C) 2012-2013 by Stefan Gerlach (stefan.gerlach@uni-konstanz.de)
0008 
0009  ***************************************************************************/
0010 
0011 /***************************************************************************
0012  *                                                                         *
0013  *  This program is free software; you can redistribute it and/or modify   *
0014  *  it under the terms of the GNU General Public License as published by   *
0015  *  the Free Software Foundation; either version 2 of the License, or      *
0016  *  (at your option) any later version.                                    *
0017  *                                                                         *
0018  *  This program is distributed in the hope that it will be useful,        *
0019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0021  *  GNU General Public License for more details.                           *
0022  *                                                                         *
0023  *   You should have received a copy of the GNU General Public License     *
0024  *   along with this program; if not, write to the Free Software           *
0025  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0026  *   Boston, MA  02110-1301  USA                                           *
0027  *                                                                         *
0028  ***************************************************************************/
0029 
0030 #include "CartesianPlotDock.h"
0031 #include "backend/worksheet/plots/PlotArea.h"
0032 #include "backend/worksheet/plots/cartesian/XYCurve.h"
0033 #include "backend/core/column/Column.h"
0034 
0035 #include "kdefrontend/widgets/LabelWidget.h"
0036 #include "kdefrontend/GuiTools.h"
0037 #include "kdefrontend/TemplateHandler.h"
0038 #include "kdefrontend/ThemeHandler.h"
0039 
0040 #include <QCompleter>
0041 #include <QPainter>
0042 #include <QTimer>
0043 #include <QDir>
0044 #include <QDirModel>
0045 #include <QFileDialog>
0046 #include <QImageReader>
0047 #include <QButtonGroup>
0048 #include <QIntValidator>
0049 
0050 /*!
0051   \class CartesianPlotDock
0052   \brief  Provides a widget for editing the properties of the cartesian plot currently selected in the project explorer.
0053 
0054   \ingroup kdefrontend
0055 */
0056 
0057 CartesianPlotDock::CartesianPlotDock(QWidget* parent) : BaseDock(parent) {
0058     ui.setupUi(this);
0059     m_leName = ui.leName;
0060     m_leComment = ui.leComment;
0061 
0062     //"General"-tab
0063     auto* rangeButtonsGroup(new QButtonGroup);
0064     rangeButtonsGroup->addButton(ui.rbRangeFirst);
0065     rangeButtonsGroup->addButton(ui.rbRangeLast);
0066     rangeButtonsGroup->addButton(ui.rbRangeFree);
0067 
0068     ui.leXMin->setValidator(new QDoubleValidator(ui.leXMin));
0069     ui.leXMax->setValidator(new QDoubleValidator(ui.leXMax));
0070     ui.leYMin->setValidator(new QDoubleValidator(ui.leYMin));
0071     ui.leYMax->setValidator(new QDoubleValidator(ui.leYMax));
0072 
0073     //"Range breaks"-tab
0074     ui.bAddXBreak->setIcon( QIcon::fromTheme("list-add") );
0075     ui.bRemoveXBreak->setIcon( QIcon::fromTheme("list-remove") );
0076     ui.cbXBreak->addItem("1");
0077 
0078     ui.bAddYBreak->setIcon( QIcon::fromTheme("list-add") );
0079     ui.bRemoveYBreak->setIcon( QIcon::fromTheme("list-remove") );
0080     ui.cbYBreak->addItem("1");
0081 
0082     //"Background"-tab
0083     ui.bOpen->setIcon( QIcon::fromTheme("document-open") );
0084     ui.leBackgroundFileName->setCompleter(new QCompleter(new QDirModel, this));
0085 
0086     //"Title"-tab
0087     auto* hboxLayout = new QHBoxLayout(ui.tabTitle);
0088     labelWidget = new LabelWidget(ui.tabTitle);
0089     hboxLayout->addWidget(labelWidget);
0090     hboxLayout->setContentsMargins(2,2,2,2);
0091     hboxLayout->setSpacing(2);
0092 
0093     //adjust layouts in the tabs
0094     for (int i = 0; i < ui.tabWidget->count(); ++i) {
0095         auto* layout = qobject_cast<QGridLayout*>(ui.tabWidget->widget(i)->layout());
0096         if (!layout)
0097             continue;
0098 
0099         layout->setContentsMargins(2,2,2,2);
0100         layout->setHorizontalSpacing(2);
0101         layout->setVerticalSpacing(2);
0102     }
0103 
0104     // "Cursor"-tab
0105     QStringList list = {i18n("NoPen"), i18n("SolidLine"), i18n("DashLine"), i18n("DotLine"), i18n("DashDotLine"), i18n("DashDotDotLine")};
0106     ui.cbCursorLineStyle->clear();
0107     for (int i = 0; i < list.count(); i++)
0108         ui.cbCursorLineStyle->addItem(list[i], i);
0109 
0110     //Validators
0111     ui.leRangeFirst->setValidator( new QIntValidator(ui.leRangeFirst) );
0112     ui.leRangeLast->setValidator( new QIntValidator(ui.leRangeLast) );
0113     ui.leXBreakStart->setValidator( new QDoubleValidator(ui.leXBreakStart) );
0114     ui.leXBreakEnd->setValidator( new QDoubleValidator(ui.leXBreakEnd) );
0115     ui.leYBreakStart->setValidator( new QDoubleValidator(ui.leYBreakStart) );
0116     ui.leYBreakEnd->setValidator( new QDoubleValidator(ui.leYBreakEnd) );
0117 
0118     //set the current locale
0119     updateLocale();
0120 
0121     //SIGNAL/SLOT
0122     //General
0123     connect(ui.leName, &QLineEdit::textChanged, this, &CartesianPlotDock::nameChanged);
0124     connect(ui.leComment, &QLineEdit::textChanged, this, &CartesianPlotDock::commentChanged);
0125     connect(ui.chkVisible, &QCheckBox::clicked, this, &CartesianPlotDock::visibilityChanged);
0126     connect(ui.sbLeft, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::geometryChanged);
0127     connect(ui.sbTop, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::geometryChanged);
0128     connect(ui.sbWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::geometryChanged);
0129     connect(ui.sbHeight, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::geometryChanged);
0130 
0131     connect(ui.leRangeFirst, &QLineEdit::textChanged, this, &CartesianPlotDock::rangeFirstChanged);
0132     connect(ui.leRangeLast, &QLineEdit::textChanged, this, &CartesianPlotDock::rangeLastChanged);
0133     connect(rangeButtonsGroup, QOverload<int>::of(&QButtonGroup::buttonClicked), this, &CartesianPlotDock::rangeTypeChanged);
0134 
0135     connect(ui.chkAutoScaleX, &QCheckBox::stateChanged, this, &CartesianPlotDock::autoScaleXChanged);
0136     connect(ui.leXMin, &QLineEdit::textChanged, this, &CartesianPlotDock::xMinChanged);
0137     connect(ui.leXMax, &QLineEdit::textChanged, this, &CartesianPlotDock::xMaxChanged);
0138     connect(ui.dateTimeEditXMin, &QDateTimeEdit::dateTimeChanged, this, &CartesianPlotDock::xMinDateTimeChanged);
0139     connect(ui.dateTimeEditXMax, &QDateTimeEdit::dateTimeChanged, this, &CartesianPlotDock::xMaxDateTimeChanged);
0140     connect(ui.cbXScaling, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::xScaleChanged);
0141     connect(ui.cbXRangeFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::xRangeFormatChanged);
0142 
0143     connect(ui.chkAutoScaleY, &QCheckBox::stateChanged, this, &CartesianPlotDock::autoScaleYChanged);
0144     connect(ui.leYMin, &QLineEdit::textChanged, this, &CartesianPlotDock::yMinChanged);
0145     connect(ui.leYMax, &QLineEdit::textChanged, this, &CartesianPlotDock::yMaxChanged);
0146     connect(ui.dateTimeEditYMin, &QDateTimeEdit::dateTimeChanged, this, &CartesianPlotDock::yMinDateTimeChanged);
0147     connect(ui.dateTimeEditYMax, &QDateTimeEdit::dateTimeChanged, this, &CartesianPlotDock::yMaxDateTimeChanged);
0148     connect(ui.cbYScaling, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::yScaleChanged);
0149     connect(ui.cbYRangeFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::yRangeFormatChanged);
0150 
0151     //Range breaks
0152     connect(ui.chkXBreak, &QCheckBox::toggled, this, &CartesianPlotDock::toggleXBreak);
0153     connect(ui.bAddXBreak, &QPushButton::clicked, this, &CartesianPlotDock::addXBreak);
0154     connect(ui.bRemoveXBreak, &QPushButton::clicked, this, &CartesianPlotDock::removeXBreak);
0155     connect(ui.cbXBreak, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::currentXBreakChanged);
0156     connect(ui.leXBreakStart, &QLineEdit::textChanged, this, &CartesianPlotDock::xBreakStartChanged);
0157     connect(ui.leXBreakEnd, &QLineEdit::textChanged, this, &CartesianPlotDock::xBreakEndChanged);
0158     connect(ui.sbXBreakPosition, QOverload<int>::of(&QSpinBox::valueChanged), this, &CartesianPlotDock::xBreakPositionChanged);
0159     connect(ui.cbXBreakStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::xBreakStyleChanged);
0160 
0161     connect(ui.chkYBreak, &QCheckBox::toggled, this, &CartesianPlotDock::toggleYBreak);
0162     connect(ui.bAddYBreak, &QPushButton::clicked, this, &CartesianPlotDock::addYBreak);
0163     connect(ui.bRemoveYBreak, &QPushButton::clicked, this, &CartesianPlotDock::removeYBreak);
0164     connect(ui.cbYBreak, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::currentYBreakChanged);
0165     connect(ui.leYBreakStart, &QLineEdit::textChanged, this, &CartesianPlotDock::yBreakStartChanged);
0166     connect(ui.leYBreakEnd, &QLineEdit::textChanged, this, &CartesianPlotDock::yBreakEndChanged);
0167     connect(ui.sbYBreakPosition, QOverload<int>::of(&QSpinBox::valueChanged), this, &CartesianPlotDock::yBreakPositionChanged);
0168     connect(ui.cbYBreakStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::yBreakStyleChanged);
0169 
0170     //Background
0171     connect(ui.cbBackgroundType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::backgroundTypeChanged);
0172     connect(ui.cbBackgroundColorStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::backgroundColorStyleChanged);
0173     connect(ui.cbBackgroundImageStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::backgroundImageStyleChanged);
0174     connect(ui.cbBackgroundBrushStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::backgroundBrushStyleChanged);
0175     connect(ui.bOpen, &QPushButton::clicked, this, &CartesianPlotDock::selectFile);
0176     connect(ui.leBackgroundFileName, &QLineEdit::textChanged, this, &CartesianPlotDock::fileNameChanged);
0177     connect(ui.kcbBackgroundFirstColor, &KColorButton::changed, this, &CartesianPlotDock::backgroundFirstColorChanged);
0178     connect(ui.kcbBackgroundSecondColor, &KColorButton::changed, this, &CartesianPlotDock::backgroundSecondColorChanged);
0179     connect(ui.sbBackgroundOpacity, QOverload<int>::of(&QSpinBox::valueChanged), this, &CartesianPlotDock::backgroundOpacityChanged);
0180 
0181     //Border
0182     connect(ui.cbBorderStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::borderStyleChanged);
0183     connect(ui.kcbBorderColor, &KColorButton::changed, this, &CartesianPlotDock::borderColorChanged);
0184     connect(ui.sbBorderWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::borderWidthChanged);
0185     connect(ui.sbBorderCornerRadius, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::borderCornerRadiusChanged);
0186     connect(ui.sbBorderOpacity, QOverload<int>::of(&QSpinBox::valueChanged), this, &CartesianPlotDock::borderOpacityChanged);
0187 
0188     //Padding
0189     connect(ui.sbPaddingHorizontal, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::horizontalPaddingChanged);
0190     connect(ui.sbPaddingVertical, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::verticalPaddingChanged);
0191     connect(ui.sbPaddingRight, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::rightPaddingChanged);
0192     connect(ui.sbPaddingBottom, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CartesianPlotDock::bottomPaddingChanged);
0193     connect(ui.cbPaddingSymmetric, &QCheckBox::toggled, this, &CartesianPlotDock::symmetricPaddingChanged);
0194 
0195     // Cursor
0196     connect(ui.sbCursorLineWidth, QOverload<int>::of(&QSpinBox::valueChanged), this, &CartesianPlotDock::cursorLineWidthChanged);
0197     connect(ui.kcbCursorLineColor, &KColorButton::changed, this, &CartesianPlotDock::cursorLineColorChanged);
0198     connect(ui.cbCursorLineStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CartesianPlotDock::cursorLineStyleChanged);
0199 
0200     //theme and template handlers
0201     auto* frame = new QFrame(this);
0202     auto* layout = new QHBoxLayout(frame);
0203     layout->setContentsMargins(0, 11, 0, 11);
0204 
0205     m_themeHandler = new ThemeHandler(this);
0206     layout->addWidget(m_themeHandler);
0207     connect(m_themeHandler, &ThemeHandler::loadThemeRequested, this, &CartesianPlotDock::loadTheme);
0208     connect(m_themeHandler, &ThemeHandler::info, this, &CartesianPlotDock::info);
0209 
0210     auto* templateHandler = new TemplateHandler(this, TemplateHandler::ClassName::CartesianPlot);
0211     layout->addWidget(templateHandler);
0212     connect(templateHandler, &TemplateHandler::loadConfigRequested, this, &CartesianPlotDock::loadConfigFromTemplate);
0213     connect(templateHandler, &TemplateHandler::saveConfigRequested, this, &CartesianPlotDock::saveConfigAsTemplate);
0214     connect(templateHandler, &TemplateHandler::info, this, &CartesianPlotDock::info);
0215 
0216     ui.verticalLayout->addWidget(frame);
0217 
0218     //TODO: activate the tab again once the functionality is implemented
0219     ui.tabWidget->removeTab(2);
0220 
0221     init();
0222 }
0223 
0224 void CartesianPlotDock::init() {
0225     this->retranslateUi();
0226 
0227     GuiTools::updatePenStyles(ui.cbCursorLineStyle, Qt::black);
0228 
0229     /*
0230      //TODO: activate later once range breaking is implemented
0231     //create icons for the different styles for scale breaking
0232     QPainter pa;
0233     pa.setPen( QPen(Qt::SolidPattern, 0) );
0234     QPixmap pm(20, 20);
0235     ui.cbXBreakStyle->setIconSize( QSize(20,20) );
0236     ui.cbYBreakStyle->setIconSize( QSize(20,20) );
0237 
0238     //simple
0239     pm.fill(Qt::transparent);
0240     pa.begin( &pm );
0241     pa.setRenderHint(QPainter::Antialiasing);
0242     pa.setBrush(Qt::SolidPattern);
0243     pa.drawLine(3,10,8,10);
0244     pa.drawLine(12,10,17,10);
0245     pa.end();
0246     ui.cbXBreakStyle->setItemIcon(0, pm);
0247     ui.cbYBreakStyle->setItemIcon(0, pm);
0248 
0249     //vertical
0250     pm.fill(Qt::transparent);
0251     pa.begin( &pm );
0252     pa.setRenderHint(QPainter::Antialiasing);
0253     pa.setBrush(Qt::SolidPattern);
0254     pa.drawLine(3,10,8,10);
0255     pa.drawLine(12,10,17,10);
0256     pa.drawLine(8,14,8,6);
0257     pa.drawLine(12,14,12,6);
0258     pa.end();
0259     ui.cbXBreakStyle->setItemIcon(1, pm);
0260     ui.cbYBreakStyle->setItemIcon(1, pm);
0261 
0262     //sloped
0263     pm.fill(Qt::transparent);
0264     pa.begin( &pm );
0265     pa.setRenderHint(QPainter::Antialiasing);
0266     pa.setBrush(Qt::SolidPattern);
0267     pa.drawLine(3,10,8,10);
0268     pa.drawLine(12,10,17,10);
0269     pa.drawLine(6,14,10,6);
0270     pa.drawLine(10,14,14,6);
0271     pa.end();
0272     ui.cbXBreakStyle->setItemIcon(2, pm);
0273     ui.cbYBreakStyle->setItemIcon(2, pm);
0274     */
0275 }
0276 
0277 void CartesianPlotDock::setPlots(QList<CartesianPlot*> list) {
0278     m_initializing = true;
0279     m_plotList = list;
0280     m_plot = list.first();
0281     m_aspect = list.first();
0282 
0283     QList<TextLabel*> labels;
0284     for (auto* plot : list)
0285         labels.append(plot->title());
0286 
0287     labelWidget->setLabels(labels);
0288 
0289     //if there is more then one plot in the list, disable the name and comment fields in the tab "general"
0290     if (list.size() == 1) {
0291         ui.lName->setEnabled(true);
0292         ui.leName->setEnabled(true);
0293         ui.lComment->setEnabled(true);
0294         ui.leComment->setEnabled(true);
0295 
0296         ui.leName->setText(m_plot->name());
0297         ui.leComment->setText(m_plot->comment());
0298     } else {
0299         ui.lName->setEnabled(false);
0300         ui.leName->setEnabled(false);
0301         ui.lComment->setEnabled(false);
0302         ui.leComment->setEnabled(false);
0303 
0304         ui.leName->setText(QString());
0305         ui.leComment->setText(QString());
0306     }
0307 
0308     symmetricPaddingChanged(m_plot->symmetricPadding());
0309 
0310     ui.leName->setStyleSheet("");
0311     ui.leName->setToolTip("");
0312 
0313     //show the properties of the first plot
0314     this->load();
0315 
0316     //update active widgets
0317     m_themeHandler->setCurrentTheme(m_plot->theme());
0318 
0319     //Deactivate the geometry related widgets, if the worksheet layout is active.
0320     //Currently, a plot can only be a child of the worksheet itself, so we only need to ask the parent aspect (=worksheet).
0321     //TODO redesign this, if the hierarchy will be changend in future (a plot is a child of a new object group/container or so)
0322     auto* w = dynamic_cast<Worksheet*>(m_plot->parentAspect());
0323     if (w) {
0324         bool b = (w->layout() == Worksheet::Layout::NoLayout);
0325         ui.sbTop->setEnabled(b);
0326         ui.sbLeft->setEnabled(b);
0327         ui.sbWidth->setEnabled(b);
0328         ui.sbHeight->setEnabled(b);
0329         connect(w, &Worksheet::layoutChanged, this, &CartesianPlotDock::layoutChanged);
0330     }
0331 
0332     //SIGNALs/SLOTs
0333     connect(m_plot, &CartesianPlot::aspectDescriptionChanged, this, &CartesianPlotDock::plotDescriptionChanged);
0334     connect(m_plot, &CartesianPlot::rectChanged, this, &CartesianPlotDock::plotRectChanged);
0335     connect(m_plot, &CartesianPlot::rangeTypeChanged, this, &CartesianPlotDock::plotRangeTypeChanged);
0336     connect(m_plot, &CartesianPlot::rangeFirstValuesChanged, this, &CartesianPlotDock::plotRangeFirstValuesChanged);
0337     connect(m_plot, &CartesianPlot::rangeLastValuesChanged, this, &CartesianPlotDock::plotRangeLastValuesChanged);
0338     connect(m_plot, &CartesianPlot::xAutoScaleChanged, this, &CartesianPlotDock::plotXAutoScaleChanged);
0339     connect(m_plot, &CartesianPlot::xMinChanged, this, &CartesianPlotDock::plotXMinChanged);
0340     connect(m_plot, &CartesianPlot::xMaxChanged, this, &CartesianPlotDock::plotXMaxChanged);
0341     connect(m_plot, &CartesianPlot::xScaleChanged, this, &CartesianPlotDock::plotXScaleChanged);
0342     connect(m_plot, &CartesianPlot::xRangeFormatChanged, this, &CartesianPlotDock::plotXRangeFormatChanged);
0343     connect(m_plot, &CartesianPlot::yAutoScaleChanged, this, &CartesianPlotDock::plotYAutoScaleChanged);
0344     connect(m_plot, &CartesianPlot::yMinChanged, this, &CartesianPlotDock::plotYMinChanged);
0345     connect(m_plot, &CartesianPlot::yMaxChanged, this, &CartesianPlotDock::plotYMaxChanged);
0346     connect(m_plot, &CartesianPlot::yScaleChanged, this, &CartesianPlotDock::plotYScaleChanged);
0347     connect(m_plot, &CartesianPlot::yRangeFormatChanged, this, &CartesianPlotDock::plotYRangeFormatChanged);
0348     connect(m_plot, &CartesianPlot::visibleChanged, this, &CartesianPlotDock::plotVisibleChanged);
0349 
0350     //range breaks
0351     connect(m_plot, &CartesianPlot::xRangeBreakingEnabledChanged, this, &CartesianPlotDock::plotXRangeBreakingEnabledChanged);
0352     connect(m_plot, &CartesianPlot::xRangeBreaksChanged, this, &CartesianPlotDock::plotXRangeBreaksChanged);
0353     connect(m_plot, &CartesianPlot::yRangeBreakingEnabledChanged, this, &CartesianPlotDock::plotYRangeBreakingEnabledChanged);
0354     connect(m_plot, &CartesianPlot::yRangeBreaksChanged, this, &CartesianPlotDock::plotYRangeBreaksChanged);
0355 
0356     // Plot Area
0357     connect(m_plot->plotArea(), &PlotArea::backgroundTypeChanged, this, &CartesianPlotDock::plotBackgroundTypeChanged);
0358     connect(m_plot->plotArea(), &PlotArea::backgroundColorStyleChanged, this, &CartesianPlotDock::plotBackgroundColorStyleChanged);
0359     connect(m_plot->plotArea(), &PlotArea::backgroundImageStyleChanged, this, &CartesianPlotDock::plotBackgroundImageStyleChanged);
0360     connect(m_plot->plotArea(), &PlotArea::backgroundBrushStyleChanged, this, &CartesianPlotDock::plotBackgroundBrushStyleChanged);
0361     connect(m_plot->plotArea(), &PlotArea::backgroundFirstColorChanged, this, &CartesianPlotDock::plotBackgroundFirstColorChanged);
0362     connect(m_plot->plotArea(), &PlotArea::backgroundSecondColorChanged, this, &CartesianPlotDock::plotBackgroundSecondColorChanged);
0363     connect(m_plot->plotArea(), &PlotArea::backgroundFileNameChanged, this, &CartesianPlotDock::plotBackgroundFileNameChanged);
0364     connect(m_plot->plotArea(), &PlotArea::backgroundOpacityChanged, this, &CartesianPlotDock::plotBackgroundOpacityChanged);
0365     connect(m_plot->plotArea(), &PlotArea::borderPenChanged, this, &CartesianPlotDock::plotBorderPenChanged);
0366     connect(m_plot->plotArea(), &PlotArea::borderOpacityChanged, this, &CartesianPlotDock::plotBorderOpacityChanged);
0367     connect(m_plot, &CartesianPlot::horizontalPaddingChanged, this, &CartesianPlotDock::plotHorizontalPaddingChanged);
0368     connect(m_plot, &CartesianPlot::verticalPaddingChanged, this, &CartesianPlotDock::plotVerticalPaddingChanged);
0369     connect(m_plot, &CartesianPlot::rightPaddingChanged, this, &CartesianPlotDock::plotRightPaddingChanged);
0370     connect(m_plot, &CartesianPlot::bottomPaddingChanged, this, &CartesianPlotDock::plotBottomPaddingChanged);
0371     connect(m_plot, &CartesianPlot::symmetricPaddingChanged, this, &CartesianPlotDock::plotSymmetricPaddingChanged);
0372 
0373     m_initializing = false;
0374 }
0375 
0376 void CartesianPlotDock::activateTitleTab() {
0377     ui.tabWidget->setCurrentWidget(ui.tabTitle);
0378 }
0379 
0380 /*
0381  * updates the locale in the widgets. called when the application settins are changed.
0382  */
0383 void CartesianPlotDock::updateLocale() {
0384     SET_NUMBER_LOCALE
0385 
0386     //update the QSpinBoxes
0387     ui.sbLeft->setLocale(numberLocale);
0388     ui.sbTop->setLocale(numberLocale);
0389     ui.sbWidth->setLocale(numberLocale);
0390     ui.sbHeight->setLocale(numberLocale);
0391     ui.sbBorderWidth->setLocale(numberLocale);
0392     ui.sbBorderCornerRadius->setLocale(numberLocale);
0393     ui.sbPaddingHorizontal->setLocale(numberLocale);
0394     ui.sbPaddingVertical->setLocale(numberLocale);
0395     ui.sbPaddingRight->setLocale(numberLocale);
0396     ui.sbPaddingBottom->setLocale(numberLocale);
0397 
0398     //update the QLineEdits, avoid the change events
0399     if (m_plot) {
0400         Lock lock(m_initializing);
0401         ui.leRangeFirst->setText(numberLocale.toString(m_plot->rangeFirstValues()));
0402         ui.leRangeLast->setText(numberLocale.toString(m_plot->rangeLastValues()));
0403         ui.leXMin->setText(numberLocale.toString(m_plot->xMin()));
0404         ui.leXMax->setText(numberLocale.toString(m_plot->xMax()));
0405         ui.leYMin->setText(numberLocale.toString(m_plot->yMin()));
0406         ui.leYMax->setText(numberLocale.toString(m_plot->yMax()));
0407     }
0408 
0409     //update the title label
0410     labelWidget->updateLocale();
0411 }
0412 
0413 void CartesianPlotDock::updateUnits() {
0414     const KConfigGroup group = KSharedConfig::openConfig()->group(QLatin1String("Settings_General"));
0415     BaseDock::Units units = (BaseDock::Units)group.readEntry("Units", static_cast<int>(Units::Metric));
0416     if (units == m_units)
0417         return;
0418 
0419     m_units = units;
0420     Lock lock(m_initializing);
0421     QString suffix;
0422     if (m_units == Units::Metric) {
0423         //convert from imperial to metric
0424         m_worksheetUnit = Worksheet::Unit::Centimeter;
0425         suffix = QLatin1String(" cm");
0426         ui.sbLeft->setValue(ui.sbLeft->value()*2.54);
0427         ui.sbTop->setValue(ui.sbTop->value()*2.54);
0428         ui.sbWidth->setValue(ui.sbWidth->value()*2.54);
0429         ui.sbHeight->setValue(ui.sbHeight->value()*2.54);
0430         ui.sbBorderCornerRadius->setValue(ui.sbBorderCornerRadius->value()*2.54);
0431         ui.sbPaddingHorizontal->setValue(ui.sbPaddingHorizontal->value()*2.54);
0432         ui.sbPaddingVertical->setValue(ui.sbPaddingVertical->value()*2.54);
0433         ui.sbPaddingRight->setValue(ui.sbPaddingRight->value()*2.54);
0434         ui.sbPaddingBottom->setValue(ui.sbPaddingBottom->value()*2.54);
0435     } else {
0436         //convert from metric to imperial
0437         m_worksheetUnit = Worksheet::Unit::Inch;
0438         suffix = QLatin1String(" in");
0439         ui.sbLeft->setValue(ui.sbLeft->value()/2.54);
0440         ui.sbTop->setValue(ui.sbTop->value()/2.54);
0441         ui.sbWidth->setValue(ui.sbWidth->value()/2.54);
0442         ui.sbHeight->setValue(ui.sbHeight->value()/2.54);
0443         ui.sbBorderCornerRadius->setValue(ui.sbBorderCornerRadius->value()/2.54);
0444         ui.sbPaddingHorizontal->setValue(ui.sbPaddingHorizontal->value()/2.54);
0445         ui.sbPaddingVertical->setValue(ui.sbPaddingVertical->value()/2.54);
0446         ui.sbPaddingRight->setValue(ui.sbPaddingRight->value()/2.54);
0447         ui.sbPaddingBottom->setValue(ui.sbPaddingBottom->value()/2.54);
0448     }
0449 
0450     ui.sbLeft->setSuffix(suffix);
0451     ui.sbTop->setSuffix(suffix);
0452     ui.sbWidth->setSuffix(suffix);
0453     ui.sbHeight->setSuffix(suffix);
0454     ui.sbBorderCornerRadius->setSuffix(suffix);
0455     ui.sbPaddingHorizontal->setSuffix(suffix);
0456     ui.sbPaddingVertical->setSuffix(suffix);
0457     ui.sbPaddingRight->setSuffix(suffix);
0458     ui.sbPaddingBottom->setSuffix(suffix);
0459 
0460     labelWidget->updateUnits();
0461 }
0462 
0463 //************************************************************
0464 //**** SLOTs for changes triggered in CartesianPlotDock ******
0465 //************************************************************
0466 void CartesianPlotDock::retranslateUi() {
0467     Lock lock(m_initializing);
0468 
0469     //general
0470     ui.cbXRangeFormat->addItem(i18n("Numeric"));
0471     ui.cbXRangeFormat->addItem(i18n("Date and Time"));
0472     ui.cbYRangeFormat->addItem(i18n("Numeric"));
0473     ui.cbYRangeFormat->addItem(i18n("Date and Time"));
0474 
0475     ui.cbXScaling->addItem( i18n("linear") );
0476     ui.cbXScaling->addItem( i18n("log(x)") );
0477     ui.cbXScaling->addItem( i18n("log2(x)") );
0478     ui.cbXScaling->addItem( i18n("ln(x)") );
0479     ui.cbXScaling->addItem( i18n("log(abs(x))") );
0480     ui.cbXScaling->addItem( i18n("log2(abs(x))") );
0481     ui.cbXScaling->addItem( i18n("ln(abs(x))") );
0482 
0483     ui.cbYScaling->addItem( i18n("linear") );
0484     ui.cbYScaling->addItem( i18n("log(y)") );
0485     ui.cbYScaling->addItem( i18n("log2(y)") );
0486     ui.cbYScaling->addItem( i18n("ln(y)") );
0487     ui.cbYScaling->addItem( i18n("log(abs(y))") );
0488     ui.cbYScaling->addItem( i18n("log2(abs(y))") );
0489     ui.cbYScaling->addItem( i18n("ln(abs(y))") );
0490 
0491     //scale breakings
0492     ui.cbXBreakStyle->addItem( i18n("Simple") );
0493     ui.cbXBreakStyle->addItem( i18n("Vertical") );
0494     ui.cbXBreakStyle->addItem( i18n("Sloped") );
0495 
0496     ui.cbYBreakStyle->addItem( i18n("Simple") );
0497     ui.cbYBreakStyle->addItem( i18n("Vertical") );
0498     ui.cbYBreakStyle->addItem( i18n("Sloped") );
0499 
0500     //plot area
0501     ui.cbBackgroundType->addItem(i18n("Color"));
0502     ui.cbBackgroundType->addItem(i18n("Image"));
0503     ui.cbBackgroundType->addItem(i18n("Pattern"));
0504 
0505     ui.cbBackgroundColorStyle->addItem(i18n("Single Color"));
0506     ui.cbBackgroundColorStyle->addItem(i18n("Horizontal Gradient"));
0507     ui.cbBackgroundColorStyle->addItem(i18n("Vertical Gradient"));
0508     ui.cbBackgroundColorStyle->addItem(i18n("Diag. Gradient (From Top Left)"));
0509     ui.cbBackgroundColorStyle->addItem(i18n("Diag. Gradient (From Bottom Left)"));
0510     ui.cbBackgroundColorStyle->addItem(i18n("Radial Gradient"));
0511 
0512     ui.cbBackgroundImageStyle->addItem(i18n("Scaled and Cropped"));
0513     ui.cbBackgroundImageStyle->addItem(i18n("Scaled"));
0514     ui.cbBackgroundImageStyle->addItem(i18n("Scaled, Keep Proportions"));
0515     ui.cbBackgroundImageStyle->addItem(i18n("Centered"));
0516     ui.cbBackgroundImageStyle->addItem(i18n("Tiled"));
0517     ui.cbBackgroundImageStyle->addItem(i18n("Center Tiled"));
0518 
0519     GuiTools::updatePenStyles(ui.cbBorderStyle, Qt::black);
0520     GuiTools::updateBrushStyles(ui.cbBackgroundBrushStyle, Qt::SolidPattern);
0521 
0522     QString suffix;
0523     if (m_units == Units::Metric)
0524         suffix = QLatin1String(" cm");
0525     else
0526         suffix = QLatin1String(" in");
0527 
0528     ui.sbLeft->setSuffix(suffix);
0529     ui.sbTop->setSuffix(suffix);
0530     ui.sbWidth->setSuffix(suffix);
0531     ui.sbHeight->setSuffix(suffix);
0532     ui.sbBorderCornerRadius->setSuffix(suffix);
0533     ui.sbPaddingHorizontal->setSuffix(suffix);
0534     ui.sbPaddingVertical->setSuffix(suffix);
0535     ui.sbPaddingRight->setSuffix(suffix);
0536     ui.sbPaddingBottom->setSuffix(suffix);
0537 }
0538 
0539 // "General"-tab
0540 void CartesianPlotDock::visibilityChanged(bool state) {
0541     if (m_initializing)
0542         return;
0543 
0544     for (auto* plot : m_plotList)
0545         plot->setVisible(state);
0546 }
0547 
0548 void CartesianPlotDock::geometryChanged() {
0549     if (m_initializing)
0550         return;
0551 
0552     double x = Worksheet::convertToSceneUnits(ui.sbLeft->value(), m_worksheetUnit);
0553     double y = Worksheet::convertToSceneUnits(ui.sbTop->value(), m_worksheetUnit);
0554     double w = Worksheet::convertToSceneUnits(ui.sbWidth->value(), m_worksheetUnit);
0555     double h = Worksheet::convertToSceneUnits(ui.sbHeight->value(), m_worksheetUnit);
0556 
0557     QRectF rect(x, y, w, h);
0558     m_plot->setRect(rect);
0559 }
0560 
0561 /*!
0562     Called when the layout in the worksheet gets changed.
0563     Enables/disables the geometry widgets if the layout was deactivated/activated.
0564     Shows the new geometry values of the first plot if the layout was activated.
0565  */
0566 void CartesianPlotDock::layoutChanged(Worksheet::Layout layout) {
0567     bool b = (layout == Worksheet::Layout::NoLayout);
0568     ui.sbTop->setEnabled(b);
0569     ui.sbLeft->setEnabled(b);
0570     ui.sbWidth->setEnabled(b);
0571     ui.sbHeight->setEnabled(b);
0572 }
0573 
0574 void CartesianPlotDock::rangeTypeChanged() {
0575     CartesianPlot::RangeType type;
0576     if (ui.rbRangeFirst->isChecked()) {
0577         ui.leRangeFirst->setEnabled(true);
0578         ui.leRangeLast->setEnabled(false);
0579         type = CartesianPlot::RangeType::First;
0580     } else if (ui.rbRangeLast->isChecked()) {
0581         ui.leRangeFirst->setEnabled(false);
0582         ui.leRangeLast->setEnabled(true);
0583         type = CartesianPlot::RangeType::Last;
0584     } else {
0585         ui.leRangeFirst->setEnabled(false);
0586         ui.leRangeLast->setEnabled(false);
0587         type = CartesianPlot::RangeType::Free;
0588     }
0589 
0590     if (m_initializing)
0591         return;
0592 
0593     for (auto* plot : m_plotList)
0594         plot->setRangeType(type);
0595 }
0596 
0597 void CartesianPlotDock::rangeFirstChanged(const QString& text) {
0598     if (m_initializing)
0599         return;
0600 
0601     const int value = text.toInt();
0602     for (auto* plot : m_plotList)
0603         plot->setRangeFirstValues(value);
0604 }
0605 
0606 void CartesianPlotDock::rangeLastChanged(const QString& text) {
0607     if (m_initializing)
0608         return;
0609 
0610     const int value = text.toInt();
0611     for (auto* plot : m_plotList)
0612         plot->setRangeLastValues(value);
0613 }
0614 
0615 void CartesianPlotDock::autoScaleXChanged(int state) {
0616     bool checked = (state == Qt::Checked);
0617     ui.cbXRangeFormat->setEnabled(!checked);
0618     ui.leXMin->setEnabled(!checked);
0619     ui.leXMax->setEnabled(!checked);
0620     ui.dateTimeEditXMin->setEnabled(!checked);
0621     ui.dateTimeEditXMax->setEnabled(!checked);
0622 
0623     if (m_initializing)
0624         return;
0625 
0626     for (auto* plot : m_plotList)
0627         plot->setAutoScaleX(checked);
0628 }
0629 
0630 void CartesianPlotDock::xMinChanged(const QString& value) {
0631     if (m_initializing)
0632         return;
0633 
0634     const Lock lock(m_initializing);
0635     bool ok;
0636     SET_NUMBER_LOCALE
0637     const double xMin = numberLocale.toDouble(value, &ok);
0638     if (ok) {
0639         for (auto* plot : m_plotList)
0640             plot->setXMin(xMin);
0641     }
0642 }
0643 
0644 void CartesianPlotDock::xMaxChanged(const QString& value) {
0645     if (m_initializing)
0646         return;
0647 
0648     const Lock lock(m_initializing);
0649     bool ok;
0650     SET_NUMBER_LOCALE
0651     const double xMax = numberLocale.toDouble(value, &ok);
0652     if (ok) {
0653         for (auto* plot : m_plotList)
0654             plot->setXMax(xMax);
0655     }
0656 }
0657 
0658 void CartesianPlotDock::xMinDateTimeChanged(const QDateTime& dateTime) {
0659     if (m_initializing)
0660         return;
0661 
0662     quint64 value = dateTime.toMSecsSinceEpoch();
0663     for (auto* plot : m_plotList)
0664         plot->setXMin(value);
0665 }
0666 
0667 void CartesianPlotDock::xMaxDateTimeChanged(const QDateTime& dateTime) {
0668     if (m_initializing)
0669         return;
0670 
0671     quint64 value = dateTime.toMSecsSinceEpoch();
0672     for (auto* plot : m_plotList)
0673         plot->setXMax(value);
0674 }
0675 
0676 /*!
0677     called on scale changes (linear, log) for the x-axis
0678  */
0679 void CartesianPlotDock::xScaleChanged(int index) {
0680     if (m_initializing)
0681         return;
0682 
0683     auto scale = static_cast<CartesianPlot::Scale>(index);
0684     for (auto* plot : m_plotList)
0685         plot->setXScale(scale);
0686 }
0687 
0688 void CartesianPlotDock::xRangeFormatChanged(int index) {
0689     bool numeric = (index == 0);
0690 
0691     ui.lXMin->setVisible(numeric);
0692     ui.leXMin->setVisible(numeric);
0693     ui.lXMax->setVisible(numeric);
0694     ui.leXMax->setVisible(numeric);
0695 
0696     ui.lXMinDateTime->setVisible(!numeric);
0697     ui.dateTimeEditXMin->setVisible(!numeric);
0698     ui.lXMaxDateTime->setVisible(!numeric);
0699     ui.dateTimeEditXMax->setVisible(!numeric);
0700 
0701     if (m_initializing)
0702         return;
0703 
0704     auto format = (CartesianPlot::RangeFormat)index;
0705     for (auto* plot : m_plotList)
0706         plot->setXRangeFormat(format);
0707 }
0708 
0709 void CartesianPlotDock::autoScaleYChanged(int state) {
0710     bool checked = (state == Qt::Checked);
0711     ui.cbYRangeFormat->setEnabled(!checked);
0712     ui.leYMin->setEnabled(!checked);
0713     ui.leYMax->setEnabled(!checked);
0714     ui.dateTimeEditYMin->setEnabled(!checked);
0715     ui.dateTimeEditYMax->setEnabled(!checked);
0716 
0717     if (m_initializing)
0718         return;
0719 
0720     for (auto* plot : m_plotList)
0721         plot->setAutoScaleY(checked);
0722 }
0723 
0724 void CartesianPlotDock::yMinChanged(const QString& value) {
0725     if (m_initializing)
0726         return;
0727 
0728     const Lock lock(m_initializing);
0729     bool ok;
0730     SET_NUMBER_LOCALE
0731     const double yMin = numberLocale.toDouble(value, &ok);
0732     if (ok) {
0733         for (auto* plot : m_plotList)
0734             plot->setYMin(yMin);
0735     }
0736 }
0737 
0738 void CartesianPlotDock::yMaxChanged(const QString& value) {
0739     if (m_initializing)
0740         return;
0741 
0742     const Lock lock(m_initializing);
0743     bool ok;
0744     SET_NUMBER_LOCALE
0745     const double yMax = numberLocale.toDouble(value, &ok);
0746     if (ok) {
0747         for (auto* plot : m_plotList)
0748             plot->setYMax(yMax);
0749     }
0750 }
0751 
0752 void CartesianPlotDock::yMinDateTimeChanged(const QDateTime& dateTime) {
0753     if (m_initializing)
0754         return;
0755 
0756     quint64 value = dateTime.toMSecsSinceEpoch();
0757     for (auto* plot : m_plotList)
0758         plot->setXMin(value);
0759 }
0760 
0761 void CartesianPlotDock::yMaxDateTimeChanged(const QDateTime& dateTime) {
0762     if (m_initializing)
0763         return;
0764 
0765     quint64 value = dateTime.toMSecsSinceEpoch();
0766     for (auto* plot : m_plotList)
0767         plot->setXMax(value);
0768 }
0769 
0770 /*!
0771     called on scale changes (linear, log) for the y-axis
0772  */
0773 void CartesianPlotDock::yScaleChanged(int index) {
0774     if (m_initializing)
0775         return;
0776 
0777     auto scale = static_cast<CartesianPlot::Scale>(index);
0778     for (auto* plot : m_plotList)
0779         plot->setYScale(scale);
0780 }
0781 
0782 void CartesianPlotDock::yRangeFormatChanged(int index) {
0783     bool numeric = (index == 0);
0784 
0785     ui.lYMin->setVisible(numeric);
0786     ui.leYMin->setVisible(numeric);
0787     ui.lYMax->setVisible(numeric);
0788     ui.leYMax->setVisible(numeric);
0789 
0790     ui.lYMinDateTime->setVisible(!numeric);
0791     ui.dateTimeEditYMin->setVisible(!numeric);
0792     ui.lYMaxDateTime->setVisible(!numeric);
0793     ui.dateTimeEditYMax->setVisible(!numeric);
0794 
0795     if (m_initializing)
0796         return;
0797 
0798     auto format = (CartesianPlot::RangeFormat)index;
0799     for (auto* plot : m_plotList)
0800         plot->setYRangeFormat(format);
0801 }
0802 
0803 // "Range Breaks"-tab
0804 
0805 // x-range breaks
0806 void CartesianPlotDock::toggleXBreak(bool b) {
0807     ui.frameXBreakEdit->setEnabled(b);
0808     ui.leXBreakStart->setEnabled(b);
0809     ui.leXBreakEnd->setEnabled(b);
0810     ui.sbXBreakPosition->setEnabled(b);
0811     ui.cbXBreakStyle->setEnabled(b);
0812 
0813     if (m_initializing)
0814         return;
0815 
0816     for (auto* plot : m_plotList)
0817         plot->setXRangeBreakingEnabled(b);
0818 }
0819 
0820 void CartesianPlotDock::addXBreak() {
0821     ui.bRemoveXBreak->setVisible(true);
0822 
0823     CartesianPlot::RangeBreaks breaks = m_plot->xRangeBreaks();
0824     CartesianPlot::RangeBreak b;
0825     breaks.list<<b;
0826     breaks.lastChanged = breaks.list.size() - 1;
0827     for (auto* plot : m_plotList)
0828         plot->setXRangeBreaks(breaks);
0829 
0830     ui.cbXBreak->addItem(QString::number(ui.cbXBreak->count() + 1));
0831     ui.cbXBreak->setCurrentIndex(ui.cbXBreak->count()-1);
0832 }
0833 
0834 void CartesianPlotDock::removeXBreak() {
0835     ui.bRemoveXBreak->setVisible(m_plot->xRangeBreaks().list.size()>1);
0836     int index = ui.cbXBreak->currentIndex();
0837     CartesianPlot::RangeBreaks breaks = m_plot->xRangeBreaks();
0838     breaks.list.takeAt(index);
0839     breaks.lastChanged = -1;
0840     for (auto* plot : m_plotList)
0841         plot->setXRangeBreaks(breaks);
0842 
0843     ui.cbXBreak->clear();
0844     for (int i = 1; i <= breaks.list.size(); ++i)
0845         ui.cbXBreak->addItem(QString::number(i));
0846 
0847     if (index < ui.cbXBreak->count()-1)
0848         ui.cbXBreak->setCurrentIndex(index);
0849     else
0850         ui.cbXBreak->setCurrentIndex(ui.cbXBreak->count()-1);
0851 
0852     ui.bRemoveXBreak->setVisible(ui.cbXBreak->count()!=1);
0853 }
0854 
0855 void CartesianPlotDock::currentXBreakChanged(int index) {
0856     if (m_initializing)
0857         return;
0858 
0859     if (index == -1)
0860         return;
0861 
0862     m_initializing = true;
0863     SET_NUMBER_LOCALE
0864     const CartesianPlot::RangeBreak rangeBreak = m_plot->xRangeBreaks().list.at(index);
0865     QString str = std::isnan(rangeBreak.start) ? QString() : numberLocale.toString(rangeBreak.start);
0866     ui.leXBreakStart->setText(str);
0867     str = std::isnan(rangeBreak.end) ? QString() : numberLocale.toString(rangeBreak.end);
0868     ui.leXBreakEnd->setText(str);
0869     ui.sbXBreakPosition->setValue(rangeBreak.position*100);
0870     ui.cbXBreakStyle->setCurrentIndex((int)rangeBreak.style);
0871     m_initializing = false;
0872 }
0873 
0874 void CartesianPlotDock::xBreakStartChanged() {
0875     if (m_initializing)
0876         return;
0877 
0878     int index = ui.cbXBreak->currentIndex();
0879     CartesianPlot::RangeBreaks breaks = m_plot->xRangeBreaks();
0880     breaks.list[index].start = ui.leXBreakStart->text().toDouble();
0881     breaks.lastChanged = index;
0882 
0883     for (auto* plot : m_plotList)
0884         plot->setXRangeBreaks(breaks);
0885 }
0886 
0887 void CartesianPlotDock::xBreakEndChanged() {
0888     if (m_initializing)
0889         return;
0890 
0891     int index = ui.cbXBreak->currentIndex();
0892     CartesianPlot::RangeBreaks breaks = m_plot->xRangeBreaks();
0893     breaks.list[index].end = ui.leXBreakEnd->text().toDouble();
0894     breaks.lastChanged = index;
0895 
0896     for (auto* plot : m_plotList)
0897         plot->setXRangeBreaks(breaks);
0898 }
0899 
0900 void CartesianPlotDock::xBreakPositionChanged(int value) {
0901     if (m_initializing)
0902         return;
0903 
0904     int index = ui.cbXBreak->currentIndex();
0905     CartesianPlot::RangeBreaks breaks = m_plot->xRangeBreaks();
0906     breaks.list[index].position = (float)value/100.;
0907     breaks.lastChanged = index;
0908 
0909     for (auto* plot : m_plotList)
0910         plot->setXRangeBreaks(breaks);
0911 }
0912 
0913 void CartesianPlotDock::xBreakStyleChanged(int styleIndex) {
0914     if (m_initializing)
0915         return;
0916 
0917     int index = ui.cbXBreak->currentIndex();
0918     auto style = CartesianPlot::RangeBreakStyle(styleIndex);
0919     CartesianPlot::RangeBreaks breaks = m_plot->xRangeBreaks();
0920     breaks.list[index].style = style;
0921     breaks.lastChanged = index;
0922 
0923     for (auto* plot : m_plotList)
0924         plot->setXRangeBreaks(breaks);
0925 }
0926 
0927 // y-range breaks
0928 void CartesianPlotDock::toggleYBreak(bool b) {
0929     ui.frameYBreakEdit->setEnabled(b);
0930     ui.leYBreakStart->setEnabled(b);
0931     ui.leYBreakEnd->setEnabled(b);
0932     ui.sbYBreakPosition->setEnabled(b);
0933     ui.cbYBreakStyle->setEnabled(b);
0934 
0935     if (m_initializing)
0936         return;
0937 
0938     for (auto* plot : m_plotList)
0939         plot->setYRangeBreakingEnabled(b);
0940 }
0941 
0942 void CartesianPlotDock::addYBreak() {
0943     ui.bRemoveYBreak->setVisible(true);
0944 
0945     CartesianPlot::RangeBreaks breaks = m_plot->yRangeBreaks();
0946     CartesianPlot::RangeBreak b;
0947     breaks.list << b;
0948     breaks.lastChanged = breaks.list.size() - 1;
0949     for (auto* plot : m_plotList)
0950         plot->setYRangeBreaks(breaks);
0951 
0952     ui.cbYBreak->addItem(QString::number(ui.cbYBreak->count() + 1));
0953     ui.cbYBreak->setCurrentIndex(ui.cbYBreak->count()-1);
0954 }
0955 
0956 void CartesianPlotDock::removeYBreak() {
0957     ui.bRemoveYBreak->setVisible(m_plot->yRangeBreaks().list.size() > 1);
0958     int index = ui.cbYBreak->currentIndex();
0959     CartesianPlot::RangeBreaks breaks = m_plot->yRangeBreaks();
0960     breaks.list.takeAt(index);
0961     breaks.lastChanged = -1;
0962     for (auto* plot : m_plotList)
0963         plot->setYRangeBreaks(breaks);
0964 
0965     ui.cbYBreak->clear();
0966     for (int i = 1; i <= breaks.list.size(); ++i)
0967         ui.cbYBreak->addItem(QString::number(i));
0968 
0969     if (index < ui.cbYBreak->count()-1)
0970         ui.cbYBreak->setCurrentIndex(index);
0971     else
0972         ui.cbYBreak->setCurrentIndex(ui.cbYBreak->count()-1);
0973 
0974     ui.bRemoveYBreak->setVisible(ui.cbYBreak->count() != 1);
0975 }
0976 
0977 void CartesianPlotDock::currentYBreakChanged(int index) {
0978     if (m_initializing)
0979         return;
0980 
0981     if (index == -1)
0982         return;
0983 
0984     m_initializing = true;
0985     SET_NUMBER_LOCALE
0986     const CartesianPlot::RangeBreak rangeBreak = m_plot->yRangeBreaks().list.at(index);
0987     QString str = std::isnan(rangeBreak.start) ? QString() : numberLocale.toString(rangeBreak.start);
0988     ui.leYBreakStart->setText(str);
0989     str = std::isnan(rangeBreak.end) ? QString() : numberLocale.toString(rangeBreak.end);
0990     ui.leYBreakEnd->setText(str);
0991     ui.sbYBreakPosition->setValue(rangeBreak.position*100);
0992     ui.cbYBreakStyle->setCurrentIndex((int)rangeBreak.style);
0993     m_initializing = false;
0994 }
0995 
0996 void CartesianPlotDock::yBreakStartChanged() {
0997     if (m_initializing)
0998         return;
0999 
1000     int index = ui.cbYBreak->currentIndex();
1001     CartesianPlot::RangeBreaks breaks = m_plot->yRangeBreaks();
1002     breaks.list[index].start = ui.leYBreakStart->text().toDouble();
1003     breaks.lastChanged = index;
1004 
1005     for (auto* plot : m_plotList)
1006         plot->setYRangeBreaks(breaks);
1007 }
1008 
1009 void CartesianPlotDock::yBreakEndChanged() {
1010     if (m_initializing)
1011         return;
1012 
1013     int index = ui.cbYBreak->currentIndex();
1014     CartesianPlot::RangeBreaks breaks = m_plot->yRangeBreaks();
1015     breaks.list[index].end = ui.leYBreakEnd->text().toDouble();
1016     breaks.lastChanged = index;
1017 
1018     for (auto* plot : m_plotList)
1019         plot->setYRangeBreaks(breaks);
1020 }
1021 
1022 void CartesianPlotDock::yBreakPositionChanged(int value) {
1023     if (m_initializing)
1024         return;
1025 
1026     int index = ui.cbYBreak->currentIndex();
1027     CartesianPlot::RangeBreaks breaks = m_plot->yRangeBreaks();
1028     breaks.list[index].position = (float)value/100.;
1029     breaks.lastChanged = index;
1030 
1031     for (auto* plot : m_plotList)
1032         plot->setYRangeBreaks(breaks);
1033 }
1034 
1035 void CartesianPlotDock::yBreakStyleChanged(int styleIndex) {
1036     if (m_initializing)
1037         return;
1038 
1039     int index = ui.cbYBreak->currentIndex();
1040     auto style = CartesianPlot::RangeBreakStyle(styleIndex);
1041     CartesianPlot::RangeBreaks breaks = m_plot->yRangeBreaks();
1042     breaks.list[index].style = style;
1043     breaks.lastChanged = index;
1044 
1045     for (auto* plot : m_plotList)
1046         plot->setYRangeBreaks(breaks);
1047 }
1048 
1049 // "Plot area"-tab
1050 void CartesianPlotDock::backgroundTypeChanged(int index) {
1051     auto type = (PlotArea::BackgroundType)index;
1052 
1053     if (type == PlotArea::BackgroundType::Color) {
1054         ui.lBackgroundColorStyle->show();
1055         ui.cbBackgroundColorStyle->show();
1056         ui.lBackgroundImageStyle->hide();
1057         ui.cbBackgroundImageStyle->hide();
1058         ui.lBackgroundBrushStyle->hide();
1059         ui.cbBackgroundBrushStyle->hide();
1060 
1061         ui.lBackgroundFileName->hide();
1062         ui.leBackgroundFileName->hide();
1063         ui.bOpen->hide();
1064 
1065         ui.lBackgroundFirstColor->show();
1066         ui.kcbBackgroundFirstColor->show();
1067 
1068         auto style = (PlotArea::BackgroundColorStyle) ui.cbBackgroundColorStyle->currentIndex();
1069         if (style == PlotArea::BackgroundColorStyle::SingleColor) {
1070             ui.lBackgroundFirstColor->setText(i18n("Color:"));
1071             ui.lBackgroundSecondColor->hide();
1072             ui.kcbBackgroundSecondColor->hide();
1073         } else {
1074             ui.lBackgroundFirstColor->setText(i18n("First color:"));
1075             ui.lBackgroundSecondColor->show();
1076             ui.kcbBackgroundSecondColor->show();
1077         }
1078     } else if (type == PlotArea::BackgroundType::Image) {
1079         ui.lBackgroundColorStyle->hide();
1080         ui.cbBackgroundColorStyle->hide();
1081         ui.lBackgroundImageStyle->show();
1082         ui.cbBackgroundImageStyle->show();
1083         ui.lBackgroundBrushStyle->hide();
1084         ui.cbBackgroundBrushStyle->hide();
1085         ui.lBackgroundFileName->show();
1086         ui.leBackgroundFileName->show();
1087         ui.bOpen->show();
1088 
1089         ui.lBackgroundFirstColor->hide();
1090         ui.kcbBackgroundFirstColor->hide();
1091         ui.lBackgroundSecondColor->hide();
1092         ui.kcbBackgroundSecondColor->hide();
1093     } else if (type == PlotArea::BackgroundType::Pattern) {
1094         ui.lBackgroundFirstColor->setText(i18n("Color:"));
1095         ui.lBackgroundColorStyle->hide();
1096         ui.cbBackgroundColorStyle->hide();
1097         ui.lBackgroundImageStyle->hide();
1098         ui.cbBackgroundImageStyle->hide();
1099         ui.lBackgroundBrushStyle->show();
1100         ui.cbBackgroundBrushStyle->show();
1101         ui.lBackgroundFileName->hide();
1102         ui.leBackgroundFileName->hide();
1103         ui.bOpen->hide();
1104 
1105         ui.lBackgroundFirstColor->show();
1106         ui.kcbBackgroundFirstColor->show();
1107         ui.lBackgroundSecondColor->hide();
1108         ui.kcbBackgroundSecondColor->hide();
1109     }
1110 
1111     if (m_initializing)
1112         return;
1113 
1114     for (auto* plot : m_plotList)
1115         plot->plotArea()->setBackgroundType(type);
1116 }
1117 
1118 void CartesianPlotDock::backgroundColorStyleChanged(int index) {
1119     auto style = (PlotArea::BackgroundColorStyle)index;
1120 
1121     if (style == PlotArea::BackgroundColorStyle::SingleColor) {
1122         ui.lBackgroundFirstColor->setText(i18n("Color:"));
1123         ui.lBackgroundSecondColor->hide();
1124         ui.kcbBackgroundSecondColor->hide();
1125     } else {
1126         ui.lBackgroundFirstColor->setText(i18n("First color:"));
1127         ui.lBackgroundSecondColor->show();
1128         ui.kcbBackgroundSecondColor->show();
1129         ui.lBackgroundBrushStyle->hide();
1130         ui.cbBackgroundBrushStyle->hide();
1131     }
1132 
1133     if (m_initializing)
1134         return;
1135 
1136     for (auto* plot : m_plotList)
1137         plot->plotArea()->setBackgroundColorStyle(style);
1138 }
1139 
1140 void CartesianPlotDock::backgroundImageStyleChanged(int index) {
1141     if (m_initializing)
1142         return;
1143 
1144     auto style = (PlotArea::BackgroundImageStyle)index;
1145     for (auto* plot : m_plotList)
1146         plot->plotArea()->setBackgroundImageStyle(style);
1147 }
1148 
1149 void CartesianPlotDock::backgroundBrushStyleChanged(int index) {
1150     if (m_initializing)
1151         return;
1152 
1153     auto style = (Qt::BrushStyle)index;
1154     for (auto* plot : m_plotList)
1155         plot->plotArea()->setBackgroundBrushStyle(style);
1156 }
1157 
1158 void CartesianPlotDock::backgroundFirstColorChanged(const QColor& c) {
1159     if (m_initializing)
1160         return;
1161 
1162     for (auto* plot : m_plotList)
1163         plot->plotArea()->setBackgroundFirstColor(c);
1164 }
1165 
1166 void CartesianPlotDock::backgroundSecondColorChanged(const QColor& c) {
1167     if (m_initializing)
1168         return;
1169 
1170     for (auto* plot : m_plotList)
1171         plot->plotArea()->setBackgroundSecondColor(c);
1172 }
1173 
1174 /*!
1175     opens a file dialog and lets the user select the image file.
1176 */
1177 void CartesianPlotDock::selectFile() {
1178     KConfigGroup conf(KSharedConfig::openConfig(), "CartesianPlotDock");
1179     QString dir = conf.readEntry("LastImageDir", "");
1180 
1181     QString formats;
1182     for (const auto& format : QImageReader::supportedImageFormats()) {
1183         QString f = "*." + QString(format.constData());
1184         if (f == QLatin1String("*.svg"))
1185             continue;
1186         formats.isEmpty() ? formats += f : formats += ' ' + f;
1187     }
1188 
1189     QString path = QFileDialog::getOpenFileName(this, i18n("Select the image file"), dir, i18n("Images (%1)", formats));
1190     if (path.isEmpty())
1191         return; //cancel was clicked in the file-dialog
1192 
1193     int pos = path.lastIndexOf(QLatin1String("/"));
1194     if (pos != -1) {
1195         QString newDir{path.left(pos)};
1196         if (newDir != dir)
1197             conf.writeEntry("LastImageDir", newDir);
1198     }
1199 
1200     ui.leBackgroundFileName->setText(path);
1201 
1202     for (auto* plot : m_plotList)
1203         plot->plotArea()->setBackgroundFileName(path);
1204 }
1205 
1206 void CartesianPlotDock::fileNameChanged() {
1207     if (m_initializing)
1208         return;
1209 
1210     const QString& fileName = ui.leBackgroundFileName->text();
1211     bool invalid = (!fileName.isEmpty() && !QFile::exists(fileName));
1212     GuiTools::highlight(ui.leBackgroundFileName, invalid);
1213 
1214     for (auto* plot : m_plotList)
1215         plot->plotArea()->setBackgroundFileName(fileName);
1216 }
1217 
1218 void CartesianPlotDock::backgroundOpacityChanged(int value) {
1219     if (m_initializing)
1220         return;
1221 
1222     qreal opacity = (float)value/100.;
1223     for (auto* plot : m_plotList)
1224         plot->plotArea()->setBackgroundOpacity(opacity);
1225 }
1226 
1227 // "Border"-tab
1228 void CartesianPlotDock::borderStyleChanged(int index) {
1229     if (m_initializing)
1230         return;
1231 
1232     auto penStyle = Qt::PenStyle(index);
1233     QPen pen;
1234     for (auto* plot : m_plotList) {
1235         pen = plot->plotArea()->borderPen();
1236         pen.setStyle(penStyle);
1237         plot->plotArea()->setBorderPen(pen);
1238     }
1239 }
1240 
1241 void CartesianPlotDock::borderColorChanged(const QColor& color) {
1242     if (m_initializing)
1243         return;
1244 
1245     QPen pen;
1246     for (auto* plot : m_plotList) {
1247         pen = plot->plotArea()->borderPen();
1248         pen.setColor(color);
1249         plot->plotArea()->setBorderPen(pen);
1250     }
1251 
1252     m_initializing = true;
1253     GuiTools::updatePenStyles(ui.cbBorderStyle, color);
1254     m_initializing = false;
1255 }
1256 
1257 void CartesianPlotDock::borderWidthChanged(double value) {
1258     if (m_initializing)
1259         return;
1260 
1261     QPen pen;
1262     for (auto* plot : m_plotList) {
1263         pen = plot->plotArea()->borderPen();
1264         pen.setWidthF( Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point) );
1265         plot->plotArea()->setBorderPen(pen);
1266     }
1267 }
1268 
1269 void CartesianPlotDock::borderCornerRadiusChanged(double value) {
1270     if (m_initializing)
1271         return;
1272 
1273     for (auto* plot : m_plotList)
1274         plot->plotArea()->setBorderCornerRadius(Worksheet::convertToSceneUnits(value, m_worksheetUnit));
1275 }
1276 
1277 void CartesianPlotDock::borderOpacityChanged(int value) {
1278     if (m_initializing)
1279         return;
1280 
1281     qreal opacity = (float)value/100.;
1282     for (auto* plot : m_plotList)
1283         plot->plotArea()->setBorderOpacity(opacity);
1284 }
1285 
1286 void CartesianPlotDock::symmetricPaddingChanged(bool checked) {
1287     ui.lPaddingHorizontalRight->setVisible(!checked);
1288     ui.sbPaddingRight->setVisible(!checked);
1289     ui.lPaddingVerticalDown->setVisible(!checked);
1290     ui.sbPaddingBottom->setVisible(!checked);
1291 
1292     if (checked) {
1293         ui.lPaddingHorizontal->setText(i18n("Horizontal:"));
1294         ui.lPaddingVertical->setText(i18n("Vertical:"));
1295     } else {
1296         ui.lPaddingHorizontal->setText(i18n("Left:"));
1297         ui.lPaddingVertical->setText(i18n("Top:"));
1298     }
1299 
1300     if (m_initializing)
1301         return;
1302 
1303     for (auto* plot : m_plotList)
1304         plot->setSymmetricPadding(checked);
1305 
1306     if (checked) {
1307         rightPaddingChanged(ui.sbPaddingHorizontal->value());
1308         bottomPaddingChanged(ui.sbPaddingVertical->value());
1309     }
1310 }
1311 
1312 void CartesianPlotDock::horizontalPaddingChanged(double value) {
1313     if (m_initializing)
1314         return;
1315     double padding = Worksheet::convertToSceneUnits(value, m_worksheetUnit);
1316     for (auto* plot : m_plotList)
1317         plot->setHorizontalPadding(padding);
1318 
1319     if (m_plot->symmetricPadding()) {
1320         for (auto* plot: m_plotList)
1321             plot->setRightPadding(padding);
1322     }
1323 }
1324 
1325 void CartesianPlotDock::rightPaddingChanged(double value) {
1326     if (m_initializing)
1327         return;
1328     double padding = Worksheet::convertToSceneUnits(value, m_worksheetUnit);
1329     for (auto* plot : m_plotList)
1330         plot->setRightPadding(padding);
1331 }
1332 
1333 void CartesianPlotDock::verticalPaddingChanged(double value) {
1334     if (m_initializing)
1335         return;
1336 
1337     // TODO: find better solution (set spinbox range). When plot->rect().width() does change?
1338     double padding = Worksheet::convertToSceneUnits(value, m_worksheetUnit);
1339     for (auto* plot : m_plotList)
1340         plot->setVerticalPadding(padding);
1341 
1342     if (m_plot->symmetricPadding()) {
1343         for (auto* plot: m_plotList)
1344             plot->setBottomPadding(padding);
1345     }
1346 }
1347 
1348 void CartesianPlotDock::bottomPaddingChanged(double value) {
1349     if (m_initializing)
1350         return;
1351     double padding = Worksheet::convertToSceneUnits(value, m_worksheetUnit);
1352     for (auto* plot : m_plotList)
1353         plot->setBottomPadding(padding);
1354 }
1355 
1356 void CartesianPlotDock::cursorLineWidthChanged(int width) {
1357     if (m_initializing)
1358         return;
1359 
1360     for (auto* plot : m_plotList) {
1361         QPen pen = plot->cursorPen();
1362         pen.setWidthF( Worksheet::convertToSceneUnits(width, Worksheet::Unit::Point) );
1363         plot->setCursorPen(pen);
1364     }
1365 }
1366 
1367 void CartesianPlotDock::cursorLineColorChanged(const QColor& color) {
1368     if (m_initializing)
1369         return;
1370 
1371     for (auto* plot : m_plotList) {
1372         QPen pen = plot->cursorPen();
1373         pen.setColor(color);
1374         plot->setCursorPen(pen);
1375     }
1376 
1377     m_initializing = true;
1378     GuiTools::updatePenStyles(ui.cbCursorLineStyle, color);
1379     m_initializing = false;
1380 }
1381 
1382 void CartesianPlotDock::cursorLineStyleChanged(int index) {
1383     if (m_initializing)
1384         return;
1385 
1386     if (index > 5)
1387         return;
1388 
1389     for (auto* plot : m_plotList) {
1390         QPen pen = plot->cursorPen();
1391         pen.setStyle(static_cast<Qt::PenStyle>(index));
1392         plot->setCursorPen(pen);
1393     }
1394 }
1395 
1396 //*************************************************************
1397 //****** SLOTs for changes triggered in CartesianPlot *********
1398 //*************************************************************
1399 //general
1400 void CartesianPlotDock::plotDescriptionChanged(const AbstractAspect* aspect) {
1401     if (m_plot != aspect)
1402         return;
1403 
1404     m_initializing = true;
1405     if (aspect->name() != ui.leName->text())
1406         ui.leName->setText(aspect->name());
1407     else if (aspect->comment() != ui.leComment->text())
1408         ui.leComment->setText(aspect->comment());
1409     m_initializing = false;
1410 }
1411 
1412 void CartesianPlotDock::plotRectChanged(QRectF& rect) {
1413     m_initializing = true;
1414     ui.sbLeft->setValue(Worksheet::convertFromSceneUnits(rect.x(), m_worksheetUnit));
1415     ui.sbTop->setValue(Worksheet::convertFromSceneUnits(rect.y(), m_worksheetUnit));
1416     ui.sbWidth->setValue(Worksheet::convertFromSceneUnits(rect.width(), m_worksheetUnit));
1417     ui.sbHeight->setValue(Worksheet::convertFromSceneUnits(rect.height(), m_worksheetUnit));
1418     m_initializing = false;
1419 }
1420 
1421 void CartesianPlotDock::plotRangeTypeChanged(CartesianPlot::RangeType type) {
1422     m_initializing = true;
1423     switch (type) {
1424     case CartesianPlot::RangeType::Free:
1425         ui.rbRangeFree->setChecked(true);
1426         break;
1427     case CartesianPlot::RangeType::First:
1428         ui.rbRangeFirst->setChecked(true);
1429         break;
1430     case CartesianPlot::RangeType::Last:
1431         ui.rbRangeLast->setChecked(true);
1432         break;
1433     }
1434     m_initializing = false;
1435 }
1436 
1437 void CartesianPlotDock::plotRangeFirstValuesChanged(int value) {
1438     m_initializing = true;
1439     SET_NUMBER_LOCALE
1440     ui.leRangeFirst->setText(numberLocale.toString(value));
1441     m_initializing = false;
1442 }
1443 
1444 void CartesianPlotDock::plotRangeLastValuesChanged(int value) {
1445     m_initializing = true;
1446     SET_NUMBER_LOCALE
1447     ui.leRangeLast->setText(numberLocale.toString(value));
1448     m_initializing = false;
1449 }
1450 
1451 void CartesianPlotDock::plotXAutoScaleChanged(bool value) {
1452     m_initializing = true;
1453     ui.chkAutoScaleX->setChecked(value);
1454     m_initializing = false;
1455 }
1456 
1457 void CartesianPlotDock::plotXMinChanged(double value) {
1458     if (m_initializing)
1459         return;
1460     const Lock lock(m_initializing);
1461     SET_NUMBER_LOCALE
1462     ui.leXMin->setText(numberLocale.toString(value));
1463     ui.dateTimeEditXMin->setDateTime(QDateTime::fromMSecsSinceEpoch(value));
1464 }
1465 
1466 void CartesianPlotDock::plotXMaxChanged(double value) {
1467     if (m_initializing)
1468         return;
1469     const Lock lock(m_initializing);
1470     SET_NUMBER_LOCALE
1471     ui.leXMax->setText(numberLocale.toString(value));
1472     ui.dateTimeEditXMax->setDateTime( QDateTime::fromMSecsSinceEpoch(value) );
1473 }
1474 
1475 void CartesianPlotDock::plotXScaleChanged(CartesianPlot::Scale scale) {
1476     m_initializing = true;
1477     ui.cbXScaling->setCurrentIndex(static_cast<int>(scale));
1478     m_initializing = false;
1479 }
1480 
1481 void CartesianPlotDock::plotXRangeFormatChanged(CartesianPlot::RangeFormat format) {
1482     m_initializing = true;
1483     ui.cbXRangeFormat->setCurrentIndex(static_cast<int>(format));
1484     m_initializing = false;
1485 }
1486 
1487 void CartesianPlotDock::plotYAutoScaleChanged(bool value) {
1488     m_initializing = true;
1489     ui.chkAutoScaleY->setChecked(value);
1490     m_initializing = false;
1491 }
1492 
1493 void CartesianPlotDock::plotYMinChanged(double value) {
1494     if (m_initializing)
1495         return;
1496     const Lock lock(m_initializing);
1497     SET_NUMBER_LOCALE
1498     ui.leYMin->setText(numberLocale.toString(value));
1499     ui.dateTimeEditYMin->setDateTime( QDateTime::fromMSecsSinceEpoch(value) );
1500 }
1501 
1502 void CartesianPlotDock::plotYMaxChanged(double value) {
1503     if (m_initializing)
1504         return;
1505     const Lock lock(m_initializing);
1506     SET_NUMBER_LOCALE
1507     ui.leYMax->setText(numberLocale.toString(value));
1508     ui.dateTimeEditYMax->setDateTime( QDateTime::fromMSecsSinceEpoch(value) );
1509 }
1510 
1511 void CartesianPlotDock::plotYScaleChanged(CartesianPlot::Scale scale) {
1512     m_initializing = true;
1513     ui.cbYScaling->setCurrentIndex(static_cast<int>(scale));
1514     m_initializing = false;
1515 }
1516 
1517 void CartesianPlotDock::plotYRangeFormatChanged(CartesianPlot::RangeFormat format) {
1518     m_initializing = true;
1519     ui.cbYRangeFormat->setCurrentIndex(static_cast<int>(format));
1520     m_initializing = false;
1521 }
1522 
1523 void CartesianPlotDock::plotVisibleChanged(bool on) {
1524     m_initializing = true;
1525     ui.chkVisible->setChecked(on);
1526     m_initializing = false;
1527 }
1528 
1529 //range breaks
1530 void CartesianPlotDock::plotXRangeBreakingEnabledChanged(bool on) {
1531     m_initializing = true;
1532     ui.chkXBreak->setChecked(on);
1533     m_initializing = false;
1534 }
1535 
1536 void CartesianPlotDock::plotXRangeBreaksChanged(const CartesianPlot::RangeBreaks& breaks) {
1537     Q_UNUSED(breaks);
1538 }
1539 
1540 void CartesianPlotDock::plotYRangeBreakingEnabledChanged(bool on) {
1541     m_initializing = true;
1542     ui.chkYBreak->setChecked(on);
1543     m_initializing = false;
1544 }
1545 
1546 void CartesianPlotDock::plotYRangeBreaksChanged(const CartesianPlot::RangeBreaks& breaks) {
1547     Q_UNUSED(breaks);
1548 }
1549 
1550 //background
1551 void CartesianPlotDock::plotBackgroundTypeChanged(PlotArea::BackgroundType type) {
1552     m_initializing = true;
1553     ui.cbBackgroundType->setCurrentIndex(static_cast<int>(type));
1554     m_initializing = false;
1555 }
1556 
1557 void CartesianPlotDock::plotBackgroundColorStyleChanged(PlotArea::BackgroundColorStyle style) {
1558     m_initializing = true;
1559     ui.cbBackgroundColorStyle->setCurrentIndex(static_cast<int>(style));
1560     m_initializing = false;
1561 }
1562 
1563 void CartesianPlotDock::plotBackgroundImageStyleChanged(PlotArea::BackgroundImageStyle style) {
1564     m_initializing = true;
1565     ui.cbBackgroundImageStyle->setCurrentIndex(static_cast<int>(style));
1566     m_initializing = false;
1567 }
1568 
1569 void CartesianPlotDock::plotBackgroundBrushStyleChanged(Qt::BrushStyle style) {
1570     m_initializing = true;
1571     ui.cbBackgroundBrushStyle->setCurrentIndex(style);
1572     m_initializing = false;
1573 }
1574 
1575 void CartesianPlotDock::plotBackgroundFirstColorChanged(QColor& color) {
1576     m_initializing = true;
1577     ui.kcbBackgroundFirstColor->setColor(color);
1578     m_initializing = false;
1579 }
1580 
1581 void CartesianPlotDock::plotBackgroundSecondColorChanged(QColor& color) {
1582     m_initializing = true;
1583     ui.kcbBackgroundSecondColor->setColor(color);
1584     m_initializing = false;
1585 }
1586 
1587 void CartesianPlotDock::plotBackgroundFileNameChanged(QString& filename) {
1588     m_initializing = true;
1589     ui.leBackgroundFileName->setText(filename);
1590     m_initializing = false;
1591 }
1592 
1593 void CartesianPlotDock::plotBackgroundOpacityChanged(float opacity) {
1594     m_initializing = true;
1595     ui.sbBackgroundOpacity->setValue( round(opacity*100.0) );
1596     m_initializing = false;
1597 }
1598 
1599 void CartesianPlotDock::plotBorderPenChanged(QPen& pen) {
1600     m_initializing = true;
1601     if (ui.cbBorderStyle->currentIndex() != pen.style())
1602         ui.cbBorderStyle->setCurrentIndex(pen.style());
1603     if (ui.kcbBorderColor->color() != pen.color())
1604         ui.kcbBorderColor->setColor(pen.color());
1605     if (ui.sbBorderWidth->value() != pen.widthF())
1606         ui.sbBorderWidth->setValue(Worksheet::convertFromSceneUnits(pen.widthF(), Worksheet::Unit::Point));
1607     m_initializing = false;
1608 }
1609 
1610 void CartesianPlotDock::plotBorderCornerRadiusChanged(float value) {
1611     m_initializing = true;
1612     ui.sbBorderCornerRadius->setValue(Worksheet::convertFromSceneUnits(value, m_worksheetUnit));
1613     m_initializing = false;
1614 }
1615 
1616 void CartesianPlotDock::plotBorderOpacityChanged(float value) {
1617     m_initializing = true;
1618     float v = (float)value*100.;
1619     ui.sbBorderOpacity->setValue(v);
1620     m_initializing = false;
1621 }
1622 
1623 void CartesianPlotDock::plotHorizontalPaddingChanged(float value) {
1624     m_initializing = true;
1625     ui.sbPaddingHorizontal->setValue(Worksheet::convertFromSceneUnits(value, m_worksheetUnit));
1626     m_initializing = false;
1627 }
1628 
1629 void CartesianPlotDock::plotVerticalPaddingChanged(float value) {
1630     m_initializing = true;
1631     ui.sbPaddingVertical->setValue(Worksheet::convertFromSceneUnits(value, m_worksheetUnit));
1632     m_initializing = false;
1633 }
1634 
1635 void CartesianPlotDock::plotRightPaddingChanged(double value) {
1636     m_initializing = true;
1637     ui.sbPaddingRight->setValue(Worksheet::convertFromSceneUnits(value, m_worksheetUnit));
1638     m_initializing = false;
1639 }
1640 
1641 void CartesianPlotDock::plotBottomPaddingChanged(double value) {
1642     m_initializing = true;
1643     ui.sbPaddingBottom->setValue(Worksheet::convertFromSceneUnits(value, m_worksheetUnit));
1644     m_initializing = false;
1645 }
1646 
1647 void CartesianPlotDock::plotSymmetricPaddingChanged(bool symmetric) {
1648     m_initializing = true;
1649     ui.cbPaddingSymmetric->setChecked(symmetric);
1650     m_initializing = false;
1651 }
1652 
1653 void CartesianPlotDock::plotCursorPenChanged(const QPen& pen) {
1654     m_initializing = true;
1655     ui.sbCursorLineWidth->setValue(Worksheet::convertFromSceneUnits(pen.widthF(), Worksheet::Unit::Point));
1656     ui.kcbCursorLineColor->setColor(pen.color());
1657     ui.cbCursorLineStyle->setCurrentIndex(pen.style());
1658     m_initializing = false;
1659 }
1660 
1661 //*************************************************************
1662 //******************** SETTINGS *******************************
1663 //*************************************************************
1664 void CartesianPlotDock::loadConfigFromTemplate(KConfig& config) {
1665     //extract the name of the template from the file name
1666     QString name;
1667     int index = config.name().lastIndexOf(QLatin1String("/"));
1668     if (index != -1)
1669         name = config.name().right(config.name().size() - index - 1);
1670     else
1671         name = config.name();
1672 
1673     int size = m_plotList.size();
1674     if (size > 1)
1675         m_plot->beginMacro(i18n("%1 cartesian plots: template \"%2\" loaded", size, name));
1676     else
1677         m_plot->beginMacro(i18n("%1: template \"%2\" loaded", m_plot->name(), name));
1678 
1679     this->loadConfig(config);
1680 
1681     m_plot->endMacro();
1682 }
1683 
1684 void CartesianPlotDock::load() {
1685     //General-tab
1686     ui.chkVisible->setChecked(m_plot->isVisible());
1687     ui.sbLeft->setValue(Worksheet::convertFromSceneUnits(m_plot->rect().x(), m_worksheetUnit));
1688     ui.sbTop->setValue(Worksheet::convertFromSceneUnits(m_plot->rect().y(), m_worksheetUnit));
1689     ui.sbWidth->setValue(Worksheet::convertFromSceneUnits(m_plot->rect().width(), m_worksheetUnit));
1690     ui.sbHeight->setValue(Worksheet::convertFromSceneUnits(m_plot->rect().height(), m_worksheetUnit));
1691 
1692     switch (m_plot->rangeType()) {
1693     case CartesianPlot::RangeType::Free:
1694         ui.rbRangeFree->setChecked(true);
1695         break;
1696     case CartesianPlot::RangeType::First:
1697         ui.rbRangeFirst->setChecked(true);
1698         break;
1699     case CartesianPlot::RangeType::Last:
1700         ui.rbRangeLast->setChecked(true);
1701         break;
1702     }
1703     rangeTypeChanged();
1704     SET_NUMBER_LOCALE
1705     ui.leRangeFirst->setText( numberLocale.toString(m_plot->rangeFirstValues()) );
1706     ui.leRangeLast->setText( numberLocale.toString(m_plot->rangeLastValues()) );
1707 
1708     ui.chkAutoScaleX->setChecked(m_plot->autoScaleX());
1709     ui.leXMin->setText(numberLocale.toString(m_plot->xMin()));
1710     ui.leXMax->setText(numberLocale.toString(m_plot->xMax()));
1711     ui.dateTimeEditXMin->setDisplayFormat(m_plot->xRangeDateTimeFormat());
1712     ui.dateTimeEditXMax->setDisplayFormat(m_plot->xRangeDateTimeFormat());
1713     ui.dateTimeEditXMin->setDateTime(QDateTime::fromMSecsSinceEpoch(m_plot->xMin()));
1714     ui.dateTimeEditXMax->setDateTime(QDateTime::fromMSecsSinceEpoch(m_plot->xMax()));
1715     ui.cbXScaling->setCurrentIndex( (int) m_plot->xScale() );
1716     ui.cbXRangeFormat->setCurrentIndex( (int) m_plot->xRangeFormat() );
1717 
1718     ui.chkAutoScaleY->setChecked(m_plot->autoScaleY());
1719     ui.leYMin->setText(numberLocale.toString(m_plot->yMin()));
1720     ui.leYMax->setText(numberLocale.toString(m_plot->yMax()));
1721     ui.dateTimeEditYMin->setDisplayFormat(m_plot->yRangeDateTimeFormat());
1722     ui.dateTimeEditYMax->setDisplayFormat(m_plot->yRangeDateTimeFormat());
1723     ui.dateTimeEditYMin->setDateTime(QDateTime::fromMSecsSinceEpoch(m_plot->yMin()));
1724     ui.dateTimeEditYMax->setDateTime(QDateTime::fromMSecsSinceEpoch(m_plot->yMax()));
1725     ui.cbYScaling->setCurrentIndex( (int)m_plot->yScale() );
1726     ui.cbYRangeFormat->setCurrentIndex( (int) m_plot->yRangeFormat() );
1727 
1728     //Title
1729     labelWidget->load();
1730 
1731     //x-range breaks, show the first break
1732     ui.chkXBreak->setChecked(m_plot->xRangeBreakingEnabled());
1733     this->toggleXBreak(m_plot->xRangeBreakingEnabled());
1734     ui.bRemoveXBreak->setVisible(m_plot->xRangeBreaks().list.size() > 1);
1735     ui.cbXBreak->clear();
1736     if (!m_plot->xRangeBreaks().list.isEmpty()) {
1737         for (int i = 1; i <= m_plot->xRangeBreaks().list.size(); ++i)
1738             ui.cbXBreak->addItem(QString::number(i));
1739     } else
1740         ui.cbXBreak->addItem("1");
1741     ui.cbXBreak->setCurrentIndex(0);
1742 
1743     //y-range breaks, show the first break
1744     ui.chkYBreak->setChecked(m_plot->yRangeBreakingEnabled());
1745     this->toggleYBreak(m_plot->yRangeBreakingEnabled());
1746     ui.bRemoveYBreak->setVisible(m_plot->yRangeBreaks().list.size() > 1);
1747     ui.cbYBreak->clear();
1748     if (!m_plot->yRangeBreaks().list.isEmpty()) {
1749         for (int i = 1; i <= m_plot->yRangeBreaks().list.size(); ++i)
1750             ui.cbYBreak->addItem(QString::number(i));
1751     } else
1752         ui.cbYBreak->addItem("1");
1753     ui.cbYBreak->setCurrentIndex(0);
1754 
1755     //"Plot Area"-tab
1756     //Background
1757     ui.cbBackgroundType->setCurrentIndex( (int)m_plot->plotArea()->backgroundType() );
1758     backgroundTypeChanged(ui.cbBackgroundType->currentIndex());
1759     ui.cbBackgroundColorStyle->setCurrentIndex( (int) m_plot->plotArea()->backgroundColorStyle() );
1760     ui.cbBackgroundImageStyle->setCurrentIndex( (int) m_plot->plotArea()->backgroundImageStyle() );
1761     ui.cbBackgroundBrushStyle->setCurrentIndex( (int) m_plot->plotArea()->backgroundBrushStyle() );
1762     ui.leBackgroundFileName->setText( m_plot->plotArea()->backgroundFileName() );
1763     ui.kcbBackgroundFirstColor->setColor( m_plot->plotArea()->backgroundFirstColor() );
1764     ui.kcbBackgroundSecondColor->setColor( m_plot->plotArea()->backgroundSecondColor() );
1765     ui.sbBackgroundOpacity->setValue( round(m_plot->plotArea()->backgroundOpacity()*100.0) );
1766 
1767     //highlight the text field for the background image red if an image is used and cannot be found
1768     const QString& fileName = m_plot->plotArea()->backgroundFileName();
1769     bool invalid = (!fileName.isEmpty() && !QFile::exists(fileName));
1770     GuiTools::highlight(ui.leBackgroundFileName, invalid);
1771 
1772     //Padding
1773     ui.sbPaddingHorizontal->setValue( Worksheet::convertFromSceneUnits(m_plot->horizontalPadding(), m_worksheetUnit) );
1774     ui.sbPaddingVertical->setValue( Worksheet::convertFromSceneUnits(m_plot->verticalPadding(), m_worksheetUnit) );
1775     ui.sbPaddingRight->setValue(Worksheet::convertFromSceneUnits(m_plot->rightPadding(), m_worksheetUnit));
1776     ui.sbPaddingBottom->setValue(Worksheet::convertFromSceneUnits(m_plot->bottomPadding(), m_worksheetUnit));
1777     ui.cbPaddingSymmetric->setChecked(m_plot->symmetricPadding());
1778 
1779     //Border
1780     ui.kcbBorderColor->setColor( m_plot->plotArea()->borderPen().color() );
1781     ui.cbBorderStyle->setCurrentIndex( (int) m_plot->plotArea()->borderPen().style() );
1782     ui.sbBorderWidth->setValue( Worksheet::convertFromSceneUnits(m_plot->plotArea()->borderPen().widthF(), Worksheet::Unit::Point) );
1783     ui.sbBorderCornerRadius->setValue( Worksheet::convertFromSceneUnits(m_plot->plotArea()->borderCornerRadius(), m_worksheetUnit) );
1784     ui.sbBorderOpacity->setValue( round(m_plot->plotArea()->borderOpacity()*100) );
1785     GuiTools::updatePenStyles(ui.cbBorderStyle, ui.kcbBorderColor->color());
1786 
1787     // Cursor
1788     QPen pen = m_plot->cursorPen();
1789     ui.cbCursorLineStyle->setCurrentIndex(pen.style());
1790     ui.kcbCursorLineColor->setColor(pen.color());
1791     ui.sbCursorLineWidth->setValue(pen.width());
1792     GuiTools::updatePenStyles(ui.cbCursorLineStyle, pen.color());
1793 }
1794 
1795 void CartesianPlotDock::loadConfig(KConfig& config) {
1796     KConfigGroup group = config.group("CartesianPlot");
1797 
1798     //General
1799     //we don't load/save the settings in the general-tab, since they are not style related.
1800     //It doesn't make sense to load/save them in the template.
1801     //This data is read in CartesianPlotDock::setPlots().
1802 
1803     //Title
1804     KConfigGroup plotTitleGroup = config.group("CartesianPlotTitle");
1805     labelWidget->loadConfig(plotTitleGroup);
1806 
1807     //Scale breakings
1808     //TODO
1809 
1810     //Background-tab
1811     ui.cbBackgroundType->setCurrentIndex( group.readEntry("BackgroundType", (int) m_plot->plotArea()->backgroundType()) );
1812     ui.cbBackgroundColorStyle->setCurrentIndex( group.readEntry("BackgroundColorStyle", (int) m_plot->plotArea()->backgroundColorStyle()) );
1813     ui.cbBackgroundImageStyle->setCurrentIndex( group.readEntry("BackgroundImageStyle", (int) m_plot->plotArea()->backgroundImageStyle()) );
1814     ui.cbBackgroundBrushStyle->setCurrentIndex( group.readEntry("BackgroundBrushStyle", (int) m_plot->plotArea()->backgroundBrushStyle()) );
1815     ui.leBackgroundFileName->setText( group.readEntry("BackgroundFileName", m_plot->plotArea()->backgroundFileName()) );
1816     ui.kcbBackgroundFirstColor->setColor( group.readEntry("BackgroundFirstColor", m_plot->plotArea()->backgroundFirstColor()) );
1817     ui.kcbBackgroundSecondColor->setColor( group.readEntry("BackgroundSecondColor", m_plot->plotArea()->backgroundSecondColor()) );
1818     ui.sbBackgroundOpacity->setValue( round(group.readEntry("BackgroundOpacity", m_plot->plotArea()->backgroundOpacity())*100.0) );
1819     ui.sbPaddingHorizontal->setValue(Worksheet::convertFromSceneUnits(group.readEntry("HorizontalPadding", m_plot->horizontalPadding()), m_worksheetUnit));
1820     ui.sbPaddingVertical->setValue(Worksheet::convertFromSceneUnits(group.readEntry("VerticalPadding", m_plot->verticalPadding()), m_worksheetUnit));
1821     ui.sbPaddingRight->setValue(Worksheet::convertFromSceneUnits(group.readEntry("RightPadding", m_plot->rightPadding()), m_worksheetUnit));
1822     ui.sbPaddingBottom->setValue(Worksheet::convertFromSceneUnits(group.readEntry("BottomPadding", m_plot->bottomPadding()), m_worksheetUnit));
1823     ui.cbPaddingSymmetric->setChecked(group.readEntry("SymmetricPadding", m_plot->symmetricPadding()));
1824 
1825     //Border-tab
1826     ui.kcbBorderColor->setColor( group.readEntry("BorderColor", m_plot->plotArea()->borderPen().color()) );
1827     ui.cbBorderStyle->setCurrentIndex( group.readEntry("BorderStyle", (int) m_plot->plotArea()->borderPen().style()) );
1828     ui.sbBorderWidth->setValue( Worksheet::convertFromSceneUnits(group.readEntry("BorderWidth", m_plot->plotArea()->borderPen().widthF()), Worksheet::Unit::Point) );
1829     ui.sbBorderCornerRadius->setValue( Worksheet::convertFromSceneUnits(group.readEntry("BorderCornerRadius", m_plot->plotArea()->borderCornerRadius()), m_worksheetUnit) );
1830     ui.sbBorderOpacity->setValue( group.readEntry("BorderOpacity", m_plot->plotArea()->borderOpacity())*100 );
1831 
1832     m_initializing = true;
1833     GuiTools::updatePenStyles(ui.cbBorderStyle, ui.kcbBorderColor->color());
1834     GuiTools::updatePenStyles(ui.cbCursorLineStyle, m_plot->cursorPen().color());
1835     m_initializing = false;
1836 }
1837 
1838 void CartesianPlotDock::saveConfigAsTemplate(KConfig& config) {
1839     KConfigGroup group = config.group("CartesianPlot");
1840 
1841     //General
1842     //we don't load/save the settings in the general-tab, since they are not style related.
1843     //It doesn't make sense to load/save them in the template.
1844 
1845     //Title
1846     KConfigGroup plotTitleGroup = config.group("CartesianPlotTitle");
1847     labelWidget->saveConfig(plotTitleGroup);
1848 
1849     //Scale breakings
1850     //TODO
1851 
1852     //Background
1853     group.writeEntry("BackgroundType", ui.cbBackgroundType->currentIndex());
1854     group.writeEntry("BackgroundColorStyle", ui.cbBackgroundColorStyle->currentIndex());
1855     group.writeEntry("BackgroundImageStyle", ui.cbBackgroundImageStyle->currentIndex());
1856     group.writeEntry("BackgroundBrushStyle", ui.cbBackgroundBrushStyle->currentIndex());
1857     group.writeEntry("BackgroundFileName", ui.leBackgroundFileName->text());
1858     group.writeEntry("BackgroundFirstColor", ui.kcbBackgroundFirstColor->color());
1859     group.writeEntry("BackgroundSecondColor", ui.kcbBackgroundSecondColor->color());
1860     group.writeEntry("BackgroundOpacity", ui.sbBackgroundOpacity->value()/100.0);
1861     group.writeEntry("HorizontalPadding", Worksheet::convertToSceneUnits(ui.sbPaddingHorizontal->value(), m_worksheetUnit));
1862     group.writeEntry("VerticalPadding", Worksheet::convertToSceneUnits(ui.sbPaddingVertical->value(), m_worksheetUnit));
1863     group.writeEntry("RightPadding", Worksheet::convertToSceneUnits(ui.sbPaddingRight->value(), m_worksheetUnit));
1864     group.writeEntry("BottomPadding", Worksheet::convertToSceneUnits(ui.sbPaddingBottom->value(), m_worksheetUnit));
1865     group.writeEntry("SymmetricPadding", ui.cbPaddingSymmetric->isChecked());
1866 
1867     //Border
1868     group.writeEntry("BorderStyle", ui.cbBorderStyle->currentIndex());
1869     group.writeEntry("BorderColor", ui.kcbBorderColor->color());
1870     group.writeEntry("BorderWidth", Worksheet::convertToSceneUnits(ui.sbBorderWidth->value(), Worksheet::Unit::Point));
1871     group.writeEntry("BorderCornerRadius", Worksheet::convertToSceneUnits(ui.sbBorderCornerRadius->value(), m_worksheetUnit));
1872     group.writeEntry("BorderOpacity", ui.sbBorderOpacity->value()/100.0);
1873 
1874     config.sync();
1875 }
1876 
1877 void CartesianPlotDock::loadTheme(const QString& theme) {
1878     for (auto* plot : m_plotList)
1879         plot->setTheme(theme);
1880 }
1881 
1882 void CartesianPlotDock::saveTheme(KConfig& config) const {
1883     if (!m_plotList.isEmpty())
1884         m_plotList.at(0)->saveTheme(config);
1885 }