File indexing completed on 2024-05-19 15:02:23

0001 /***************************************************************************
0002     File                 : WorksheetView.cpp
0003     Project              : LabPlot
0004     Description          : Worksheet view
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2009-2019 Alexander Semke (alexander.semke@web.de)
0007     Copyright            : (C) 2016-2018 Stefan-Gerlach (stefan.gerlach@uni.kn)
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 #include "commonfrontend/worksheet/WorksheetView.h"
0030 #include "backend/core/AbstractColumn.h"
0031 #include "backend/core/Project.h"
0032 #include "backend/worksheet/plots/cartesian/Axis.h"
0033 #include "backend/worksheet/plots/cartesian/XYCurve.h"
0034 #include "backend/worksheet/plots/cartesian/XYCurvePrivate.h"
0035 #include "backend/worksheet/Image.h"
0036 #include "backend/worksheet/TextLabel.h"
0037 #include "commonfrontend/core/PartMdiView.h"
0038 #include "kdefrontend/widgets/ThemesWidget.h"
0039 #include "kdefrontend/worksheet/GridDialog.h"
0040 #include "kdefrontend/worksheet/PresenterWidget.h"
0041 #include "kdefrontend/worksheet/DynamicPresenterWidget.h"
0042 #include "backend/lib/trace.h"
0043 
0044 #include <QApplication>
0045 #include <QDesktopWidget>
0046 #include <QMdiArea>
0047 #include <QMenu>
0048 #include <QToolBar>
0049 #include <QScreen>
0050 #include <QWheelEvent>
0051 #include <QPrinter>
0052 #include <QSvgGenerator>
0053 #include <QImage>
0054 #include <QToolButton>
0055 #include <QGraphicsOpacityEffect>
0056 #include <QTimeLine>
0057 #include <QClipboard>
0058 #include <QMimeData>
0059 #include <QWidgetAction>
0060 
0061 #include <KColorScheme>
0062 #include <KLocalizedString>
0063 #include <KMessageBox>
0064 #include <KConfigGroup>
0065 
0066 #ifdef Q_OS_MAC
0067 #include "3rdparty/kdmactouchbar/src/kdmactouchbar.h"
0068 #endif
0069 
0070 #include <limits>
0071 
0072 /**
0073  * \class WorksheetView
0074  * \brief Worksheet view
0075  */
0076 
0077 /*!
0078   Constructur of the class.
0079   Creates a view for the Worksheet \c worksheet and initializes the internal model.
0080 */
0081 WorksheetView::WorksheetView(Worksheet* worksheet) : QGraphicsView(), m_worksheet(worksheet) {
0082     setScene(m_worksheet->scene());
0083 
0084     setRenderHint(QPainter::Antialiasing);
0085     setRubberBandSelectionMode(Qt::ContainsItemBoundingRect);
0086     setTransformationAnchor(QGraphicsView::AnchorViewCenter);
0087     setResizeAnchor(QGraphicsView::AnchorViewCenter);
0088     setMinimumSize(16, 16);
0089     setFocusPolicy(Qt::StrongFocus);
0090 
0091     if (m_worksheet->useViewSize()) {
0092         setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0093         setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0094     }
0095 
0096     viewport()->setAttribute( Qt::WA_OpaquePaintEvent );
0097     viewport()->setAttribute( Qt::WA_NoSystemBackground );
0098     setAcceptDrops(true);
0099     setCacheMode(QGraphicsView::CacheBackground);
0100 
0101     m_gridSettings.style = GridStyle::NoGrid;
0102 
0103     //signal/slot connections
0104     connect(m_worksheet, &Worksheet::requestProjectContextMenu, this, &WorksheetView::createContextMenu);
0105     connect(m_worksheet, &Worksheet::itemSelected, this, &WorksheetView::selectItem);
0106     connect(m_worksheet, &Worksheet::itemDeselected, this, &WorksheetView::deselectItem);
0107     connect(m_worksheet, &Worksheet::requestUpdate, this, &WorksheetView::updateBackground);
0108     connect(m_worksheet, &Worksheet::aspectAboutToBeRemoved, this, &WorksheetView::aspectAboutToBeRemoved);
0109     connect(m_worksheet, &Worksheet::useViewSizeRequested, this, &WorksheetView::useViewSizeRequested);
0110     connect(m_worksheet, &Worksheet::layoutChanged, this, &WorksheetView::layoutChanged);
0111     connect(scene(), &QGraphicsScene::selectionChanged, this, &WorksheetView::selectionChanged);
0112 
0113     //resize the view to make the complete scene visible.
0114     //no need to resize the view when the project is being opened,
0115     //all views will be resized to the stored values at the end
0116     if (!m_worksheet->isLoading()) {
0117         float w = Worksheet::convertFromSceneUnits(sceneRect().width(), Worksheet::Unit::Inch);
0118         float h = Worksheet::convertFromSceneUnits(sceneRect().height(), Worksheet::Unit::Inch);
0119         w *= QApplication::desktop()->physicalDpiX();
0120         h *= QApplication::desktop()->physicalDpiY();
0121         resize(w*1.1, h*1.1);
0122     }
0123 
0124     //rescale to the original size
0125     static const qreal hscale = QApplication::desktop()->physicalDpiX()/(Worksheet::convertToSceneUnits(1, Worksheet::Unit::Inch));
0126     static const qreal vscale = QApplication::desktop()->physicalDpiY()/(Worksheet::convertToSceneUnits(1, Worksheet::Unit::Inch));
0127     setTransform(QTransform::fromScale(hscale, vscale));
0128 
0129     initBasicActions();
0130 }
0131 
0132 /*!
0133  * initializes couple of actions that have shortcuts assigned in the constructor as opposed
0134  * to other actions in initAction() that are create on demand only if the context menu is requested
0135  */
0136 void WorksheetView::initBasicActions() {
0137     selectAllAction = new QAction(QIcon::fromTheme("edit-select-all"), i18n("Select All"), this);
0138     this->addAction(selectAllAction);
0139     connect(selectAllAction, &QAction::triggered, this, &WorksheetView::selectAllElements);
0140 
0141     deleteAction = new QAction(QIcon::fromTheme("edit-delete"), i18n("Delete"), this);
0142     this->addAction(deleteAction);
0143     connect(deleteAction, &QAction::triggered, this, &WorksheetView::deleteElement);
0144 
0145     backspaceAction = new QAction(this);
0146     this->addAction(backspaceAction);
0147     connect(backspaceAction, &QAction::triggered, this, &WorksheetView::deleteElement);
0148 
0149     //Zoom actions
0150     zoomInViewAction = new QAction(QIcon::fromTheme("zoom-in"), i18n("Zoom In"), this);
0151 
0152     zoomOutViewAction = new QAction(QIcon::fromTheme("zoom-out"), i18n("Zoom Out"), this);
0153 
0154     zoomOriginAction = new QAction(QIcon::fromTheme("zoom-original"), i18n("Original Size"), this);
0155 }
0156 
0157 void WorksheetView::initActions() {
0158     auto* addNewActionGroup = new QActionGroup(this);
0159     auto* zoomActionGroup = new QActionGroup(this);
0160     auto* mouseModeActionGroup = new QActionGroup(this);
0161     auto* layoutActionGroup = new QActionGroup(this);
0162     auto* gridActionGroup = new QActionGroup(this);
0163     gridActionGroup->setExclusive(true);
0164     auto* magnificationActionGroup = new QActionGroup(this);
0165 
0166     zoomActionGroup->addAction(zoomInViewAction);
0167     zoomActionGroup->addAction(zoomOutViewAction);
0168     zoomActionGroup->addAction(zoomOriginAction);
0169 
0170     zoomFitPageHeightAction = new QAction(QIcon::fromTheme("zoom-fit-height"), i18n("Fit to Height"), zoomActionGroup);
0171     zoomFitPageWidthAction = new QAction(QIcon::fromTheme("zoom-fit-width"), i18n("Fit to Width"), zoomActionGroup);
0172     zoomFitSelectionAction = new QAction(i18n("Fit to Selection"), zoomActionGroup);
0173 
0174     // Mouse mode actions
0175     selectionModeAction = new QAction(QIcon::fromTheme("labplot-cursor-arrow"), i18n("Select and Edit"), mouseModeActionGroup);
0176     selectionModeAction->setCheckable(true);
0177 
0178     navigationModeAction = new QAction(QIcon::fromTheme("input-mouse"), i18n("Navigate"), mouseModeActionGroup);
0179     navigationModeAction->setCheckable(true);
0180 
0181     zoomSelectionModeAction = new QAction(QIcon::fromTheme("page-zoom"), i18n("Select and Zoom"), mouseModeActionGroup);
0182     zoomSelectionModeAction->setCheckable(true);
0183 
0184     //Magnification actions
0185     noMagnificationAction = new QAction(QIcon::fromTheme("labplot-1x-zoom"), i18n("No Magnification"), magnificationActionGroup);
0186     noMagnificationAction->setCheckable(true);
0187     noMagnificationAction->setChecked(true);
0188 
0189     twoTimesMagnificationAction = new QAction(QIcon::fromTheme("labplot-2x-zoom"), i18n("2x Magnification"), magnificationActionGroup);
0190     twoTimesMagnificationAction->setCheckable(true);
0191 
0192     threeTimesMagnificationAction = new QAction(QIcon::fromTheme("labplot-3x-zoom"), i18n("3x Magnification"), magnificationActionGroup);
0193     threeTimesMagnificationAction->setCheckable(true);
0194 
0195     fourTimesMagnificationAction = new QAction(QIcon::fromTheme("labplot-4x-zoom"), i18n("4x Magnification"), magnificationActionGroup);
0196     fourTimesMagnificationAction->setCheckable(true);
0197 
0198     fiveTimesMagnificationAction = new QAction(QIcon::fromTheme("labplot-5x-zoom"), i18n("5x Magnification"), magnificationActionGroup);
0199     fiveTimesMagnificationAction->setCheckable(true);
0200 
0201     //TODO implement later "group selection action" where multiple objects can be selected by drawing a rectangular
0202 //  selectionModeAction = new QAction(QIcon::fromTheme("select-rectangular"), i18n("Selection"), mouseModeActionGroup);
0203 //  selectionModeAction->setCheckable(true);
0204 
0205     //"Add new" related actions
0206     addCartesianPlot1Action = new QAction(QIcon::fromTheme("labplot-xy-plot-four-axes"), i18n("Box Plot, Four Axes"), addNewActionGroup);
0207     addCartesianPlot2Action = new QAction(QIcon::fromTheme("labplot-xy-plot-two-axes"), i18n("Box Plot, Two Axes"), addNewActionGroup);
0208     addCartesianPlot3Action = new QAction(QIcon::fromTheme("labplot-xy-plot-two-axes-centered"), i18n("Two Axes, Centered"), addNewActionGroup);
0209     addCartesianPlot4Action = new QAction(QIcon::fromTheme("labplot-xy-plot-two-axes-centered-origin"), i18n("Two Axes, Crossing at Origin"), addNewActionGroup);
0210     addTextLabelAction = new QAction(QIcon::fromTheme("draw-text"), i18n("Text"), addNewActionGroup);
0211     addImageAction = new QAction(QIcon::fromTheme("viewimage"), i18n("Image"), addNewActionGroup);
0212 
0213     //Layout actions
0214     //TODO: the icons labplot-editvlayout and labplot-edithlayout are confusing for the user.
0215     //the orientation is visualized as a horizontal or vertical line on the icon, but the user
0216     //percieves the two objects (resembles plots on the worksheet) separated by this line much stronger than the line itself.
0217     //with this, the two objects separated by a vertical line are percieved to be layed out in a _horizontal_ order and the
0218     //same for the vertical line. Because of this we change the icons here. We can rename the icons later in the breeze icon set.
0219     verticalLayoutAction = new QAction(QIcon::fromTheme("labplot-edithlayout"), i18n("Vertical Layout"), layoutActionGroup);
0220     verticalLayoutAction->setCheckable(true);
0221 
0222     horizontalLayoutAction = new QAction(QIcon::fromTheme("labplot-editvlayout"), i18n("Horizontal Layout"), layoutActionGroup);
0223     horizontalLayoutAction->setCheckable(true);
0224 
0225     gridLayoutAction = new QAction(QIcon::fromTheme("labplot-editgrid"), i18n("Grid Layout"), layoutActionGroup);
0226     gridLayoutAction->setCheckable(true);
0227 
0228     breakLayoutAction = new QAction(QIcon::fromTheme("labplot-editbreaklayout"), i18n("No Layout"), layoutActionGroup);
0229     breakLayoutAction->setEnabled(false);
0230 
0231     //Grid actions
0232     noGridAction = new QAction(i18n("No Grid"), gridActionGroup);
0233     noGridAction->setCheckable(true);
0234     noGridAction->setChecked(true);
0235     noGridAction->setData(static_cast<int>(GridStyle::NoGrid));
0236 
0237     denseLineGridAction = new QAction(i18n("Dense Line Grid"), gridActionGroup);
0238     denseLineGridAction->setCheckable(true);
0239 
0240     sparseLineGridAction = new QAction(i18n("Sparse Line Grid"), gridActionGroup);
0241     sparseLineGridAction->setCheckable(true);
0242 
0243     denseDotGridAction = new QAction(i18n("Dense Dot Grid"), gridActionGroup);
0244     denseDotGridAction->setCheckable(true);
0245 
0246     sparseDotGridAction = new QAction(i18n("Sparse Dot Grid"), gridActionGroup);
0247     sparseDotGridAction->setCheckable(true);
0248 
0249     customGridAction = new QAction(i18n("Custom Grid"), gridActionGroup);
0250     customGridAction->setCheckable(true);
0251 
0252     snapToGridAction = new QAction(i18n("Snap to Grid"), this);
0253     snapToGridAction->setCheckable(true);
0254 
0255     showPresenterMode = new QAction(QIcon::fromTheme("view-fullscreen"), i18n("Show in Presenter Mode"), this);
0256 
0257     //check the action corresponding to the currently active layout in worksheet
0258     this->layoutChanged(m_worksheet->layout());
0259 
0260     connect(addNewActionGroup, &QActionGroup::triggered, this, &WorksheetView::addNew);
0261     connect(mouseModeActionGroup, &QActionGroup::triggered, this, &WorksheetView::mouseModeChanged);
0262     connect(zoomActionGroup, &QActionGroup::triggered, this, &WorksheetView::changeZoom);
0263     connect(magnificationActionGroup, &QActionGroup::triggered, this, &WorksheetView::magnificationChanged);
0264     connect(layoutActionGroup, &QActionGroup::triggered, this, &WorksheetView::changeLayout);
0265     connect(gridActionGroup, &QActionGroup::triggered, this, &WorksheetView::changeGrid);
0266     connect(snapToGridAction, &QAction::triggered, this, &WorksheetView::changeSnapToGrid);
0267     connect(showPresenterMode, &QAction::triggered, this, &WorksheetView::presenterMode);
0268 
0269     //worksheet control actions
0270     plotsLockedAction = new QAction(i18n("Non-interactive Plots"), this);
0271     plotsLockedAction->setToolTip(i18n("If activated, plots on the worksheet don't react on drag and mouse wheel events."));
0272     plotsLockedAction->setCheckable(true);
0273     plotsLockedAction->setChecked(m_worksheet->plotsLocked());
0274     connect(plotsLockedAction, &QAction::triggered, this, &WorksheetView::plotsLockedActionChanged);
0275 
0276     //action for cartesian plots
0277     auto* cartesianPlotActionModeActionGroup = new QActionGroup(this);
0278     cartesianPlotActionModeActionGroup->setExclusive(true);
0279     cartesianPlotApplyToSelectionAction = new QAction(i18n("Selected Plots"), cartesianPlotActionModeActionGroup);
0280     cartesianPlotApplyToSelectionAction->setCheckable(true);
0281     cartesianPlotApplyToAllAction = new QAction(i18n("All Plots"), cartesianPlotActionModeActionGroup);
0282     cartesianPlotApplyToAllAction->setCheckable(true);
0283     setCartesianPlotActionMode(m_worksheet->cartesianPlotActionMode());
0284     connect(cartesianPlotActionModeActionGroup, &QActionGroup::triggered, this, &WorksheetView::cartesianPlotActionModeChanged);
0285 
0286     // cursor apply to all/selected
0287     auto* cartesianPlotActionCursorGroup = new QActionGroup(this);
0288     cartesianPlotActionCursorGroup->setExclusive(true);
0289     cartesianPlotApplyToSelectionCursor = new QAction(i18n("Selected Plots"), cartesianPlotActionCursorGroup);
0290     cartesianPlotApplyToSelectionCursor->setCheckable(true);
0291     cartesianPlotApplyToAllCursor = new QAction(i18n("All Plots"), cartesianPlotActionCursorGroup);
0292     cartesianPlotApplyToAllCursor->setCheckable(true);
0293     setCartesianPlotCursorMode(m_worksheet->cartesianPlotCursorMode());
0294     connect(cartesianPlotActionCursorGroup, &QActionGroup::triggered, this, &WorksheetView::cartesianPlotCursorModeChanged);
0295 
0296     auto* cartesianPlotMouseModeActionGroup = new QActionGroup(this);
0297     cartesianPlotMouseModeActionGroup->setExclusive(true);
0298     cartesianPlotSelectionModeAction = new QAction(QIcon::fromTheme("labplot-cursor-arrow"), i18n("Select and Edit"), cartesianPlotMouseModeActionGroup);
0299     cartesianPlotSelectionModeAction->setCheckable(true);
0300     cartesianPlotSelectionModeAction->setChecked(true);
0301 
0302     cartesianPlotZoomSelectionModeAction = new QAction(QIcon::fromTheme("labplot-zoom-select"), i18n("Select Region and Zoom In"), cartesianPlotMouseModeActionGroup);
0303     cartesianPlotZoomSelectionModeAction->setCheckable(true);
0304 
0305     cartesianPlotZoomXSelectionModeAction = new QAction(QIcon::fromTheme("labplot-zoom-select-x"), i18n("Select x-Region and Zoom In"), cartesianPlotMouseModeActionGroup);
0306     cartesianPlotZoomXSelectionModeAction->setCheckable(true);
0307 
0308     cartesianPlotZoomYSelectionModeAction = new QAction(QIcon::fromTheme("labplot-zoom-select-y"), i18n("Select y-Region and Zoom In"), cartesianPlotMouseModeActionGroup);
0309     cartesianPlotZoomYSelectionModeAction->setCheckable(true);
0310 
0311     // TODO: change ICON
0312     cartesianPlotCursorModeAction = new QAction(QIcon::fromTheme("debug-execute-from-cursor"), i18n("Cursor"), cartesianPlotMouseModeActionGroup);
0313     cartesianPlotCursorModeAction->setCheckable(true);
0314 
0315     connect(cartesianPlotMouseModeActionGroup, &QActionGroup::triggered, this, &WorksheetView::cartesianPlotMouseModeChanged);
0316 
0317     auto* cartesianPlotAddNewActionGroup = new QActionGroup(this);
0318     addCurveAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("xy-Curve"), cartesianPlotAddNewActionGroup);
0319     addHistogramAction = new QAction(QIcon::fromTheme("view-object-histogram-linear"), i18n("Histogram"), cartesianPlotAddNewActionGroup);
0320     addEquationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-equation-curve"), i18n("xy-Curve from a Formula"), cartesianPlotAddNewActionGroup);
0321     // TODO: no own icons yet
0322     addDataOperationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Data Operation"), cartesianPlotAddNewActionGroup);
0323 //  addDataOperationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-data-operation-curve"), i18n("Data Operation"), cartesianPlotAddNewActionGroup);
0324     addDataReductionCurveAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Data Reduction"), cartesianPlotAddNewActionGroup);
0325 //  addDataReductionCurveAction = new QAction(QIcon::fromTheme("labplot-xy-data-reduction-curve"), i18n("Data Reduction"), cartesianPlotAddNewActionGroup);
0326     addDifferentiationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Differentiation"), cartesianPlotAddNewActionGroup);
0327 //  addDifferentiationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-differentiation-curve"), i18n("Differentiation"), cartesianPlotAddNewActionGroup);
0328     addIntegrationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Integration"), cartesianPlotAddNewActionGroup);
0329 //  addIntegrationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-integration-curve"), i18n("Integration"), cartesianPlotAddNewActionGroup);
0330     addConvolutionCurveAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("(De-)Convolution"), cartesianPlotAddNewActionGroup);
0331 //  addConvolutionCurveAction = new QAction(QIcon::fromTheme("labplot-xy-convolution-curve"), i18n("(De-)Convolution"), cartesianPlotAddNewActionGroup);
0332     addCorrelationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Auto-/Cross-Correlation"), cartesianPlotAddNewActionGroup);
0333 //  addCorrelationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-convolution-curve"), i18n("Auto-/Cross-Correlation"), cartesianPlotAddNewActionGroup);
0334     addInterpolationCurveAction = new QAction(QIcon::fromTheme("labplot-xy-interpolation-curve"), i18n("Interpolation"), cartesianPlotAddNewActionGroup);
0335     addSmoothCurveAction = new QAction(QIcon::fromTheme("labplot-xy-smoothing-curve"), i18n("Smooth"), cartesianPlotAddNewActionGroup);
0336     addFitCurveAction = new QAction(QIcon::fromTheme("labplot-xy-fit-curve"), i18n("Fit"), cartesianPlotAddNewActionGroup);
0337     addFourierFilterCurveAction = new QAction(QIcon::fromTheme("labplot-xy-fourier-filter-curve"), i18n("Fourier Filter"), cartesianPlotAddNewActionGroup);
0338     addFourierTransformCurveAction = new QAction(QIcon::fromTheme("labplot-xy-fourier-transform-curve"), i18n("Fourier Transform"), cartesianPlotAddNewActionGroup);
0339     addLegendAction = new QAction(QIcon::fromTheme("text-field"), i18n("Legend"), cartesianPlotAddNewActionGroup);
0340     addHorizontalAxisAction = new QAction(QIcon::fromTheme("labplot-axis-horizontal"), i18n("Horizontal Axis"), cartesianPlotAddNewActionGroup);
0341     addVerticalAxisAction = new QAction(QIcon::fromTheme("labplot-axis-vertical"), i18n("Vertical Axis"), cartesianPlotAddNewActionGroup);
0342     addPlotTextLabelAction = new QAction(QIcon::fromTheme("draw-text"), i18n("Text"), cartesianPlotAddNewActionGroup);
0343     addPlotImageAction = new QAction(QIcon::fromTheme("viewimage"), i18n("Image"), cartesianPlotAddNewActionGroup);
0344     addCustomPointAction = new QAction(QIcon::fromTheme("draw-cross"), i18n("Custom Point"), cartesianPlotAddNewActionGroup);
0345 
0346     // Analysis menu
0347     // TODO: no own icons yet
0348     addDataOperationAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Data Operation"), cartesianPlotAddNewActionGroup);
0349 //  addDataOperationAction = new QAction(QIcon::fromTheme("labplot-xy-data-operation-curve"), i18n("Data Operation"), cartesianPlotAddNewActionGroup);
0350     addDataReductionAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Data Reduction"), cartesianPlotAddNewActionGroup);
0351 //  addDataReductionAction = new QAction(QIcon::fromTheme("labplot-xy-data-reduction-curve"), i18n("Data Reduction"), cartesianPlotAddNewActionGroup);
0352     addDifferentiationAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Differentiation"), cartesianPlotAddNewActionGroup);
0353 //  addDifferentiationAction = new QAction(QIcon::fromTheme("labplot-xy-differentiation-curve"), i18n("Differentiation"), cartesianPlotAddNewActionGroup);
0354     addIntegrationAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Integration"), cartesianPlotAddNewActionGroup);
0355 //  addIntegrationAction = new QAction(QIcon::fromTheme("labplot-xy-integration-curve"), i18n("Integration"), cartesianPlotAddNewActionGroup);
0356     addConvolutionAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Convolution/Deconvolution"), cartesianPlotAddNewActionGroup);
0357 //  addConvolutionAction = new QAction(QIcon::fromTheme("labplot-xy-convolution-curve"), i18n("Convolution/Deconvolution"), cartesianPlotAddNewActionGroup);
0358     addCorrelationAction = new QAction(QIcon::fromTheme("labplot-xy-curve"), i18n("Auto-/Cross-Correlation"), cartesianPlotAddNewActionGroup);
0359 //  addCorrelationAction = new QAction(QIcon::fromTheme("labplot-xy-correlation-curve"), i18n("Auto-/Cross-Correlation"), cartesianPlotAddNewActionGroup);
0360 
0361     addInterpolationAction = new QAction(QIcon::fromTheme("labplot-xy-interpolation-curve"), i18n("Interpolation"), cartesianPlotAddNewActionGroup);
0362     addSmoothAction = new QAction(QIcon::fromTheme("labplot-xy-smoothing-curve"), i18n("Smooth"), cartesianPlotAddNewActionGroup);
0363     addFitAction = new QAction(QIcon::fromTheme("labplot-xy-fit-curve"), i18n("Fit"), cartesianPlotAddNewActionGroup);
0364     addFourierFilterAction = new QAction(QIcon::fromTheme("labplot-xy-fourier-filter-curve"), i18n("Fourier Filter"), cartesianPlotAddNewActionGroup);
0365     addFourierTransformAction = new QAction(QIcon::fromTheme("labplot-xy-fourier-transform-curve"), i18n("Fourier Transform"), cartesianPlotAddNewActionGroup);
0366 
0367     connect(cartesianPlotAddNewActionGroup, &QActionGroup::triggered, this, &WorksheetView::cartesianPlotAddNew);
0368 
0369     auto* cartesianPlotNavigationGroup = new QActionGroup(this);
0370     scaleAutoAction = new QAction(QIcon::fromTheme("labplot-auto-scale-all"), i18n("Auto Scale"), cartesianPlotNavigationGroup);
0371     scaleAutoAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ScaleAuto));
0372     scaleAutoXAction = new QAction(QIcon::fromTheme("labplot-auto-scale-x"), i18n("Auto Scale X"), cartesianPlotNavigationGroup);
0373     scaleAutoXAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ScaleAutoX));
0374     scaleAutoYAction = new QAction(QIcon::fromTheme("labplot-auto-scale-y"), i18n("Auto Scale Y"), cartesianPlotNavigationGroup);
0375     scaleAutoYAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ScaleAutoY));
0376     zoomInAction = new QAction(QIcon::fromTheme("zoom-in"), i18n("Zoom In"), cartesianPlotNavigationGroup);
0377     zoomInAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ZoomIn));
0378     zoomOutAction = new QAction(QIcon::fromTheme("zoom-out"), i18n("Zoom Out"), cartesianPlotNavigationGroup);
0379     zoomOutAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ZoomOut));
0380     zoomInXAction = new QAction(QIcon::fromTheme("labplot-zoom-in-x"), i18n("Zoom In X"), cartesianPlotNavigationGroup);
0381     zoomInXAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ZoomInX));
0382     zoomOutXAction = new QAction(QIcon::fromTheme("labplot-zoom-out-x"), i18n("Zoom Out X"), cartesianPlotNavigationGroup);
0383     zoomOutXAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ZoomOutX));
0384     zoomInYAction = new QAction(QIcon::fromTheme("labplot-zoom-in-y"), i18n("Zoom In Y"), cartesianPlotNavigationGroup);
0385     zoomInYAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ZoomInY));
0386     zoomOutYAction = new QAction(QIcon::fromTheme("labplot-zoom-out-y"), i18n("Zoom Out Y"), cartesianPlotNavigationGroup);
0387     zoomOutYAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ZoomOutY));
0388     shiftLeftXAction = new QAction(QIcon::fromTheme("labplot-shift-left-x"), i18n("Shift Left X"), cartesianPlotNavigationGroup);
0389     shiftLeftXAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ShiftLeftX));
0390     shiftRightXAction = new QAction(QIcon::fromTheme("labplot-shift-right-x"), i18n("Shift Right X"), cartesianPlotNavigationGroup);
0391     shiftRightXAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ShiftRightX));
0392     shiftUpYAction = new QAction(QIcon::fromTheme("labplot-shift-up-y"), i18n("Shift Up Y"), cartesianPlotNavigationGroup);
0393     shiftUpYAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ShiftUpY));
0394     shiftDownYAction = new QAction(QIcon::fromTheme("labplot-shift-down-y"), i18n("Shift Down Y"), cartesianPlotNavigationGroup);
0395     shiftDownYAction->setData(static_cast<int>(CartesianPlot::NavigationOperation::ShiftDownY));
0396 
0397     connect(cartesianPlotNavigationGroup, &QActionGroup::triggered, this, &WorksheetView::cartesianPlotNavigationChanged);
0398 
0399     //set some default values
0400     selectionModeAction->setChecked(true);
0401     handleCartesianPlotActions();
0402     currentZoomAction = zoomInViewAction;
0403     currentMagnificationAction = noMagnificationAction;
0404 
0405     m_actionsInitialized = true;
0406 }
0407 
0408 void WorksheetView::initMenus() {
0409     if (!m_actionsInitialized)
0410         initActions();
0411 
0412     m_addNewCartesianPlotMenu = new QMenu(i18n("xy-plot"), this);
0413     m_addNewCartesianPlotMenu->addAction(addCartesianPlot1Action);
0414     m_addNewCartesianPlotMenu->addAction(addCartesianPlot2Action);
0415     m_addNewCartesianPlotMenu->addAction(addCartesianPlot3Action);
0416     m_addNewCartesianPlotMenu->addAction(addCartesianPlot4Action);
0417 
0418     m_addNewMenu = new QMenu(i18n("Add New"), this);
0419     m_addNewMenu->setIcon(QIcon::fromTheme("list-add"));
0420     m_addNewMenu->addMenu(m_addNewCartesianPlotMenu)->setIcon(QIcon::fromTheme("office-chart-line"));
0421     m_addNewMenu->addSeparator();
0422     m_addNewMenu->addAction(addTextLabelAction);
0423     m_addNewMenu->addAction(addImageAction);
0424 
0425     m_viewMouseModeMenu = new QMenu(i18n("Mouse Mode"), this);
0426     m_viewMouseModeMenu->setIcon(QIcon::fromTheme("input-mouse"));
0427     m_viewMouseModeMenu->addAction(selectionModeAction);
0428     m_viewMouseModeMenu->addAction(navigationModeAction);
0429     m_viewMouseModeMenu->addAction(zoomSelectionModeAction);
0430 
0431     m_zoomMenu = new QMenu(i18n("Zoom"), this);
0432     m_zoomMenu->setIcon(QIcon::fromTheme("zoom-draw"));
0433     m_zoomMenu->addAction(zoomInViewAction);
0434     m_zoomMenu->addAction(zoomOutViewAction);
0435     m_zoomMenu->addAction(zoomOriginAction);
0436     m_zoomMenu->addAction(zoomFitPageHeightAction);
0437     m_zoomMenu->addAction(zoomFitPageWidthAction);
0438     m_zoomMenu->addAction(zoomFitSelectionAction);
0439 
0440     m_magnificationMenu = new QMenu(i18n("Magnification"), this);
0441     m_magnificationMenu->setIcon(QIcon::fromTheme("zoom-in"));
0442     m_magnificationMenu->addAction(noMagnificationAction);
0443     m_magnificationMenu->addAction(twoTimesMagnificationAction);
0444     m_magnificationMenu->addAction(threeTimesMagnificationAction);
0445     m_magnificationMenu->addAction(fourTimesMagnificationAction);
0446     m_magnificationMenu->addAction(fiveTimesMagnificationAction);
0447 
0448     m_layoutMenu = new QMenu(i18n("Layout"), this);
0449     m_layoutMenu->setIcon(QIcon::fromTheme("labplot-editbreaklayout"));
0450     m_layoutMenu->addAction(verticalLayoutAction);
0451     m_layoutMenu->addAction(horizontalLayoutAction);
0452     m_layoutMenu->addAction(gridLayoutAction);
0453     m_layoutMenu->addSeparator();
0454     m_layoutMenu->addAction(breakLayoutAction);
0455 
0456     m_gridMenu = new QMenu(i18n("Grid"), this);
0457     m_gridMenu->setIcon(QIcon::fromTheme("view-grid"));
0458     m_gridMenu->addAction(noGridAction);
0459     m_gridMenu->addSeparator();
0460     m_gridMenu->addAction(sparseLineGridAction);
0461     m_gridMenu->addAction(denseLineGridAction);
0462     m_gridMenu->addSeparator();
0463     m_gridMenu->addAction(sparseDotGridAction);
0464     m_gridMenu->addAction(denseDotGridAction);
0465     m_gridMenu->addSeparator();
0466     m_gridMenu->addAction(customGridAction);
0467     //TODO: implement "snap to grid" and activate this action
0468 //  m_gridMenu->addSeparator();
0469 //  m_gridMenu->addAction(snapToGridAction);
0470 
0471     m_cartesianPlotMenu = new QMenu(i18n("Cartesian Plot"), this);
0472     m_cartesianPlotMenu->setIcon(QIcon::fromTheme("office-chart-line"));
0473 
0474     m_cartesianPlotMouseModeMenu = new QMenu(i18n("Mouse Mode"), this);
0475     m_cartesianPlotMouseModeMenu->setIcon(QIcon::fromTheme("input-mouse"));
0476     m_cartesianPlotMouseModeMenu->addAction(cartesianPlotSelectionModeAction);
0477     m_cartesianPlotMouseModeMenu->addAction(cartesianPlotZoomSelectionModeAction);
0478     m_cartesianPlotMouseModeMenu->addAction(cartesianPlotZoomXSelectionModeAction);
0479     m_cartesianPlotMouseModeMenu->addAction(cartesianPlotZoomYSelectionModeAction);
0480     m_cartesianPlotMouseModeMenu->addSeparator();
0481     m_cartesianPlotMouseModeMenu->addAction(cartesianPlotCursorModeAction);
0482     m_cartesianPlotMouseModeMenu->addSeparator();
0483 
0484     m_cartesianPlotAddNewMenu = new QMenu(i18n("Add New"), this);
0485     m_cartesianPlotAddNewMenu->setIcon(QIcon::fromTheme("list-add"));
0486     m_cartesianPlotAddNewMenu->addAction(addCurveAction);
0487     m_cartesianPlotAddNewMenu->addAction(addHistogramAction);
0488     m_cartesianPlotAddNewMenu->addAction(addEquationCurveAction);
0489     m_cartesianPlotAddNewMenu->addSeparator();
0490 
0491     m_cartesianPlotAddNewAnalysisMenu = new QMenu(i18n("Analysis Curve"));
0492     m_cartesianPlotAddNewAnalysisMenu->addAction(addFitCurveAction);
0493     m_cartesianPlotAddNewAnalysisMenu->addSeparator();
0494     m_cartesianPlotAddNewAnalysisMenu->addAction(addDifferentiationCurveAction);
0495     m_cartesianPlotAddNewAnalysisMenu->addAction(addIntegrationCurveAction);
0496     m_cartesianPlotAddNewAnalysisMenu->addSeparator();
0497     m_cartesianPlotAddNewAnalysisMenu->addAction(addInterpolationCurveAction);
0498     m_cartesianPlotAddNewAnalysisMenu->addAction(addSmoothCurveAction);
0499     m_cartesianPlotAddNewAnalysisMenu->addSeparator();
0500     m_cartesianPlotAddNewAnalysisMenu->addAction(addFourierFilterCurveAction);
0501     m_cartesianPlotAddNewAnalysisMenu->addAction(addFourierTransformCurveAction);
0502     m_cartesianPlotAddNewAnalysisMenu->addSeparator();
0503     m_cartesianPlotAddNewAnalysisMenu->addAction(addConvolutionCurveAction);
0504     m_cartesianPlotAddNewAnalysisMenu->addAction(addCorrelationCurveAction);
0505     m_cartesianPlotAddNewAnalysisMenu->addSeparator();
0506 //  m_cartesianPlotAddNewAnalysisMenu->addAction(addDataOperationCurveAction);
0507     m_cartesianPlotAddNewAnalysisMenu->addAction(addDataReductionCurveAction);
0508     m_cartesianPlotAddNewMenu->addMenu(m_cartesianPlotAddNewAnalysisMenu);
0509 
0510     m_cartesianPlotAddNewMenu->addSeparator();
0511     m_cartesianPlotAddNewMenu->addAction(addLegendAction);
0512     m_cartesianPlotAddNewMenu->addSeparator();
0513     m_cartesianPlotAddNewMenu->addAction(addHorizontalAxisAction);
0514     m_cartesianPlotAddNewMenu->addAction(addVerticalAxisAction);
0515     m_cartesianPlotAddNewMenu->addSeparator();
0516     m_cartesianPlotAddNewMenu->addAction(addPlotTextLabelAction);
0517     m_cartesianPlotAddNewMenu->addAction(addPlotImageAction);
0518     m_cartesianPlotAddNewMenu->addSeparator();
0519     m_cartesianPlotAddNewMenu->addAction(addCustomPointAction);
0520 
0521     m_cartesianPlotZoomMenu = new QMenu(i18n("Zoom/Navigate"), this);
0522     m_cartesianPlotZoomMenu->setIcon(QIcon::fromTheme("zoom-draw"));
0523     m_cartesianPlotZoomMenu->addAction(scaleAutoAction);
0524     m_cartesianPlotZoomMenu->addAction(scaleAutoXAction);
0525     m_cartesianPlotZoomMenu->addAction(scaleAutoYAction);
0526     m_cartesianPlotZoomMenu->addSeparator();
0527     m_cartesianPlotZoomMenu->addAction(zoomInAction);
0528     m_cartesianPlotZoomMenu->addAction(zoomOutAction);
0529     m_cartesianPlotZoomMenu->addSeparator();
0530     m_cartesianPlotZoomMenu->addAction(zoomInXAction);
0531     m_cartesianPlotZoomMenu->addAction(zoomOutXAction);
0532     m_cartesianPlotZoomMenu->addSeparator();
0533     m_cartesianPlotZoomMenu->addAction(zoomInYAction);
0534     m_cartesianPlotZoomMenu->addAction(zoomOutYAction);
0535     m_cartesianPlotZoomMenu->addSeparator();
0536     m_cartesianPlotZoomMenu->addAction(shiftLeftXAction);
0537     m_cartesianPlotZoomMenu->addAction(shiftRightXAction);
0538     m_cartesianPlotZoomMenu->addSeparator();
0539     m_cartesianPlotZoomMenu->addAction(shiftUpYAction);
0540     m_cartesianPlotZoomMenu->addAction(shiftDownYAction);
0541 
0542     m_cartesianPlotActionModeMenu = new QMenu(i18n("Apply Actions to"), this);
0543     m_cartesianPlotActionModeMenu->setIcon(QIcon::fromTheme("dialog-ok-apply"));
0544     m_cartesianPlotActionModeMenu->addAction(cartesianPlotApplyToSelectionAction);
0545     m_cartesianPlotActionModeMenu->addAction(cartesianPlotApplyToAllAction);
0546 
0547     m_cartesianPlotCursorModeMenu = new QMenu(i18n("Apply Cursor to"), this);
0548     m_cartesianPlotCursorModeMenu->addAction(cartesianPlotApplyToSelectionCursor);
0549     m_cartesianPlotCursorModeMenu->addAction(cartesianPlotApplyToAllCursor);
0550 
0551     m_cartesianPlotMenu->addMenu(m_cartesianPlotAddNewMenu);
0552     m_cartesianPlotMenu->addSeparator();
0553     m_cartesianPlotMenu->addMenu(m_cartesianPlotMouseModeMenu);
0554     m_cartesianPlotMenu->addMenu(m_cartesianPlotZoomMenu);
0555     m_cartesianPlotMenu->addSeparator();
0556     m_cartesianPlotMenu->addMenu(m_cartesianPlotActionModeMenu);
0557     m_cartesianPlotMenu->addMenu(m_cartesianPlotCursorModeMenu);
0558     m_cartesianPlotMenu->addSeparator();
0559     m_cartesianPlotMenu->addAction(plotsLockedAction);
0560 
0561     // Data manipulation menu
0562     m_dataManipulationMenu = new QMenu(i18n("Data Manipulation") ,this);
0563     m_dataManipulationMenu->setIcon(QIcon::fromTheme("zoom-draw"));
0564     m_dataManipulationMenu->addAction(addDataOperationAction);
0565     m_dataManipulationMenu->addAction(addDataReductionAction);
0566 
0567     //themes menu
0568     m_themeMenu = new QMenu(i18n("Apply Theme"), this);
0569     m_themeMenu->setIcon(QIcon::fromTheme("color-management"));
0570     auto* themeWidget = new ThemesWidget(nullptr);
0571     themeWidget->setFixedMode();
0572     connect(themeWidget, &ThemesWidget::themeSelected, m_worksheet, &Worksheet::setTheme);
0573     connect(themeWidget, &ThemesWidget::themeSelected, m_themeMenu, &QMenu::close);
0574 
0575     auto* widgetAction = new QWidgetAction(this);
0576     widgetAction->setDefaultWidget(themeWidget);
0577     m_themeMenu->addAction(widgetAction);
0578 
0579     m_menusInitialized = true;
0580 }
0581 
0582 /*!
0583  * Populates the menu \c menu with the worksheet and worksheet view relevant actions.
0584  * The menu is used
0585  *   - as the context menu in WorksheetView
0586  *   - as the "worksheet menu" in the main menu-bar (called form MainWin)
0587  *   - as a part of the worksheet context menu in project explorer
0588  */
0589 void WorksheetView::createContextMenu(QMenu* menu) {
0590     Q_ASSERT(menu != nullptr);
0591 
0592     if (!m_menusInitialized)
0593         initMenus();
0594 
0595     QAction* firstAction = nullptr;
0596     // if we're populating the context menu for the project explorer, then
0597     //there're already actions available there. Skip the first title-action
0598     //and insert the action at the beginning of the menu.
0599     if (menu->actions().size() > 1)
0600         firstAction = menu->actions().at(1);
0601 
0602     menu->insertMenu(firstAction, m_addNewMenu);
0603     menu->insertSeparator(firstAction);
0604     menu->insertMenu(firstAction, m_viewMouseModeMenu);
0605     menu->insertMenu(firstAction, m_zoomMenu);
0606     menu->insertMenu(firstAction, m_magnificationMenu);
0607     menu->insertMenu(firstAction, m_layoutMenu);
0608     menu->insertMenu(firstAction, m_gridMenu);
0609     menu->insertMenu(firstAction, m_themeMenu);
0610     menu->insertSeparator(firstAction);
0611     menu->insertAction(firstAction, plotsLockedAction);
0612     menu->insertSeparator(firstAction);
0613     menu->insertMenu(firstAction, m_cartesianPlotMenu);
0614     menu->insertSeparator(firstAction);
0615     menu->insertAction(firstAction, showPresenterMode);
0616     menu->insertSeparator(firstAction);
0617 }
0618 
0619 void WorksheetView::createAnalysisMenu(QMenu* menu) {
0620     Q_ASSERT(menu != nullptr);
0621 
0622     if (!m_menusInitialized)
0623         initMenus();
0624 
0625     // Data manipulation menu
0626 //  menu->insertMenu(nullptr, m_dataManipulationMenu);
0627 
0628     menu->addAction(addFitAction);
0629     menu->addSeparator();
0630     menu->addAction(addDifferentiationAction);
0631     menu->addAction(addIntegrationAction);
0632     menu->addSeparator();
0633     menu->addAction(addInterpolationAction);
0634     menu->addAction(addSmoothAction);
0635     menu->addSeparator();
0636     menu->addAction(addFourierFilterAction);
0637     menu->addAction(addFourierTransformAction);
0638     menu->addSeparator();
0639     menu->addAction(addConvolutionAction);
0640     menu->addAction(addCorrelationAction);
0641     menu->addSeparator();
0642     menu->addAction(addDataReductionAction);
0643 }
0644 
0645 void WorksheetView::fillToolBar(QToolBar* toolBar) {
0646     toolBar->addSeparator();
0647     tbNewCartesianPlot = new QToolButton(toolBar);
0648     tbNewCartesianPlot->setPopupMode(QToolButton::MenuButtonPopup);
0649     tbNewCartesianPlot->setMenu(m_addNewCartesianPlotMenu);
0650     tbNewCartesianPlot->setDefaultAction(addCartesianPlot1Action);
0651     toolBar->addWidget(tbNewCartesianPlot);
0652     toolBar->addAction(addTextLabelAction);
0653     toolBar->addAction(addImageAction);
0654 
0655     toolBar->addSeparator();
0656     toolBar->addAction(verticalLayoutAction);
0657     toolBar->addAction(horizontalLayoutAction);
0658     toolBar->addAction(gridLayoutAction);
0659     toolBar->addAction(breakLayoutAction);
0660 
0661     toolBar->addSeparator();
0662     toolBar->addAction(selectionModeAction);
0663     toolBar->addAction(navigationModeAction);
0664     toolBar->addAction(zoomSelectionModeAction);
0665     toolBar->addSeparator();
0666     tbZoom = new QToolButton(toolBar);
0667     tbZoom->setPopupMode(QToolButton::MenuButtonPopup);
0668     tbZoom->setMenu(m_zoomMenu);
0669     tbZoom->setDefaultAction(currentZoomAction);
0670     toolBar->addWidget(tbZoom);
0671 
0672     tbMagnification = new QToolButton(toolBar);
0673     tbMagnification->setPopupMode(QToolButton::MenuButtonPopup);
0674     tbMagnification->setMenu(m_magnificationMenu);
0675     tbMagnification->setDefaultAction(currentMagnificationAction);
0676     toolBar->addWidget(tbMagnification);
0677 }
0678 
0679 #ifdef Q_OS_MAC
0680 void WorksheetView::fillTouchBar(KDMacTouchBar* touchBar){
0681     //touchBar->addAction(addCartesianPlot1Action);
0682     touchBar->addAction(zoomInViewAction);
0683     touchBar->addAction(zoomOutViewAction);
0684     touchBar->addAction(showPresenterMode);
0685 }
0686 #endif
0687 
0688 void WorksheetView::fillCartesianPlotToolBar(QToolBar* toolBar) {
0689     toolBar->addAction(cartesianPlotSelectionModeAction);
0690     toolBar->addAction(cartesianPlotZoomSelectionModeAction);
0691     toolBar->addAction(cartesianPlotZoomXSelectionModeAction);
0692     toolBar->addAction(cartesianPlotZoomYSelectionModeAction);
0693     toolBar->addAction(cartesianPlotCursorModeAction);
0694     toolBar->addSeparator();
0695     toolBar->addAction(addCurveAction);
0696     toolBar->addAction(addHistogramAction);
0697     toolBar->addAction(addEquationCurveAction);
0698 // don't over-populate the tool bar
0699 //  toolBar->addAction(addDifferentiationCurveAction);
0700 //  toolBar->addAction(addIntegrationCurveAction);
0701 //  toolBar->addAction(addDataOperationCurveAction);
0702 //  toolBar->addAction(addDataReductionCurveAction);
0703 //  toolBar->addAction(addInterpolationCurveAction);
0704 //  toolBar->addAction(addSmoothCurveAction);
0705 //  toolBar->addAction(addFitCurveAction);
0706 //  toolBar->addAction(addFourierFilterCurveAction);
0707 //  toolBar->addAction(addFourierTransformCurveAction);
0708 //  toolBar->addAction(addConvolutionCurveAction);
0709 //  toolBar->addAction(addCorrelationCurveAction);
0710     toolBar->addSeparator();
0711     toolBar->addAction(addLegendAction);
0712     toolBar->addSeparator();
0713     toolBar->addAction(addHorizontalAxisAction);
0714     toolBar->addAction(addVerticalAxisAction);
0715     toolBar->addSeparator();
0716     toolBar->addAction(addPlotTextLabelAction);
0717     toolBar->addAction(addPlotImageAction);
0718     toolBar->addSeparator();
0719     toolBar->addAction(scaleAutoAction);
0720     toolBar->addAction(scaleAutoXAction);
0721     toolBar->addAction(scaleAutoYAction);
0722     toolBar->addAction(zoomInAction);
0723     toolBar->addAction(zoomOutAction);
0724     toolBar->addAction(zoomInXAction);
0725     toolBar->addAction(zoomOutXAction);
0726     toolBar->addAction(zoomInYAction);
0727     toolBar->addAction(zoomOutYAction);
0728     toolBar->addAction(shiftLeftXAction);
0729     toolBar->addAction(shiftRightXAction);
0730     toolBar->addAction(shiftUpYAction);
0731     toolBar->addAction(shiftDownYAction);
0732     toolBar->addSeparator();
0733 
0734     handleCartesianPlotActions();
0735 }
0736 
0737 void WorksheetView::setScene(QGraphicsScene* scene) {
0738     QGraphicsView::setScene(scene);
0739 }
0740 
0741 void WorksheetView::setIsClosing() {
0742     m_isClosing = true;
0743 }
0744 
0745 void WorksheetView::setCartesianPlotActionMode(Worksheet::CartesianPlotActionMode mode) {
0746     if (mode == Worksheet::CartesianPlotActionMode::ApplyActionToAll)
0747         cartesianPlotApplyToAllAction->setChecked(true);
0748     else
0749         cartesianPlotApplyToSelectionAction->setChecked(true);
0750 }
0751 
0752 void WorksheetView::setCartesianPlotCursorMode(Worksheet::CartesianPlotActionMode mode) {
0753     if (mode == Worksheet::CartesianPlotActionMode::ApplyActionToAll)
0754         cartesianPlotApplyToAllCursor->setChecked(true);
0755     else
0756         cartesianPlotApplyToSelectionCursor->setChecked(true);
0757 }
0758 
0759 void WorksheetView::setPlotLock(bool lock) {
0760     plotsLockedAction->setChecked(lock);
0761 }
0762 
0763 void WorksheetView::drawForeground(QPainter* painter, const QRectF& rect) {
0764     if (m_mouseMode == MouseMode::ZoomSelection && m_selectionBandIsShown) {
0765         painter->save();
0766         const QRectF& selRect = mapToScene(QRect(m_selectionStart, m_selectionEnd).normalized()).boundingRect();
0767         //TODO: don't hardcode for black here, use a a different color depending on the theme of the worksheet/plot under the mouse cursor?
0768         painter->setPen(QPen(Qt::black, 5/transform().m11()));
0769         painter->drawRect(selRect);
0770         painter->setBrush(QApplication::palette().color(QPalette::Highlight));
0771         painter->setOpacity(0.2);
0772         painter->drawRect(selRect);
0773         painter->restore();
0774     }
0775     QGraphicsView::drawForeground(painter, rect);
0776 }
0777 
0778 void WorksheetView::drawBackgroundItems(QPainter* painter, const QRectF& scene_rect) {
0779     // canvas
0780     painter->setOpacity(m_worksheet->backgroundOpacity());
0781     if (m_worksheet->backgroundType() == PlotArea::BackgroundType::Color) {
0782         switch (m_worksheet->backgroundColorStyle()) {
0783         case PlotArea::BackgroundColorStyle::SingleColor: {
0784                 painter->setBrush(QBrush(m_worksheet->backgroundFirstColor()));
0785                 break;
0786             }
0787         case PlotArea::BackgroundColorStyle::HorizontalLinearGradient: {
0788                 QLinearGradient linearGrad(scene_rect.topLeft(), scene_rect.topRight());
0789                 linearGrad.setColorAt(0, m_worksheet->backgroundFirstColor());
0790                 linearGrad.setColorAt(1, m_worksheet->backgroundSecondColor());
0791                 painter->setBrush(QBrush(linearGrad));
0792                 break;
0793             }
0794         case PlotArea::BackgroundColorStyle::VerticalLinearGradient: {
0795                 QLinearGradient linearGrad(scene_rect.topLeft(), scene_rect.bottomLeft());
0796                 linearGrad.setColorAt(0, m_worksheet->backgroundFirstColor());
0797                 linearGrad.setColorAt(1, m_worksheet->backgroundSecondColor());
0798                 painter->setBrush(QBrush(linearGrad));
0799                 break;
0800             }
0801         case PlotArea::BackgroundColorStyle::TopLeftDiagonalLinearGradient: {
0802                 QLinearGradient linearGrad(scene_rect.topLeft(), scene_rect.bottomRight());
0803                 linearGrad.setColorAt(0, m_worksheet->backgroundFirstColor());
0804                 linearGrad.setColorAt(1, m_worksheet->backgroundSecondColor());
0805                 painter->setBrush(QBrush(linearGrad));
0806                 break;
0807             }
0808         case PlotArea::BackgroundColorStyle::BottomLeftDiagonalLinearGradient: {
0809                 QLinearGradient linearGrad(scene_rect.bottomLeft(), scene_rect.topRight());
0810                 linearGrad.setColorAt(0, m_worksheet->backgroundFirstColor());
0811                 linearGrad.setColorAt(1, m_worksheet->backgroundSecondColor());
0812                 painter->setBrush(QBrush(linearGrad));
0813                 break;
0814             }
0815         case PlotArea::BackgroundColorStyle::RadialGradient: {
0816                 QRadialGradient radialGrad(scene_rect.center(), scene_rect.width()/2);
0817                 radialGrad.setColorAt(0, m_worksheet->backgroundFirstColor());
0818                 radialGrad.setColorAt(1, m_worksheet->backgroundSecondColor());
0819                 painter->setBrush(QBrush(radialGrad));
0820                 break;
0821             }
0822             //default:
0823             //  painter->setBrush(QBrush(m_worksheet->backgroundFirstColor()));
0824         }
0825         painter->drawRect(scene_rect);
0826     } else if (m_worksheet->backgroundType() == PlotArea::BackgroundType::Image) {  // background image
0827         const QString& backgroundFileName = m_worksheet->backgroundFileName().trimmed();
0828         if ( !backgroundFileName.isEmpty() ) {
0829             QPixmap pix(backgroundFileName);
0830             switch (m_worksheet->backgroundImageStyle()) {
0831             case PlotArea::BackgroundImageStyle::ScaledCropped:
0832                 pix = pix.scaled(scene_rect.size().toSize(),Qt::KeepAspectRatioByExpanding,Qt::SmoothTransformation);
0833                 painter->drawPixmap(scene_rect.topLeft(),pix);
0834                 break;
0835             case PlotArea::BackgroundImageStyle::Scaled:
0836                 pix = pix.scaled(scene_rect.size().toSize(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
0837                 painter->drawPixmap(scene_rect.topLeft(),pix);
0838                 break;
0839             case PlotArea::BackgroundImageStyle::ScaledAspectRatio:
0840                 pix = pix.scaled(scene_rect.size().toSize(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
0841                 painter->drawPixmap(scene_rect.topLeft(),pix);
0842                 break;
0843             case PlotArea::BackgroundImageStyle::Centered:
0844                 painter->drawPixmap(QPointF(scene_rect.center().x()-pix.size().width()/2,scene_rect.center().y()-pix.size().height()/2),pix);
0845                 break;
0846             case PlotArea::BackgroundImageStyle::Tiled:
0847                 painter->drawTiledPixmap(scene_rect,pix);
0848                 break;
0849             case PlotArea::BackgroundImageStyle::CenterTiled:
0850                 painter->drawTiledPixmap(scene_rect,pix,QPoint(scene_rect.size().width()/2,scene_rect.size().height()/2));
0851                 break;
0852                 //default:
0853                 //  painter->drawPixmap(scene_rect.topLeft(),pix);
0854             }
0855         }
0856     } else if (m_worksheet->backgroundType() == PlotArea::BackgroundType::Pattern) {    // background pattern
0857         painter->setBrush(QBrush(m_worksheet->backgroundFirstColor(),m_worksheet->backgroundBrushStyle()));
0858         painter->drawRect(scene_rect);
0859     }
0860 
0861     //grid
0862     if (m_gridSettings.style != GridStyle::NoGrid) {
0863         QColor c = m_gridSettings.color;
0864         c.setAlphaF(m_gridSettings.opacity);
0865         painter->setPen(c);
0866 
0867         qreal x, y;
0868         qreal left = scene_rect.left();
0869         qreal right = scene_rect.right();
0870         qreal top = scene_rect.top();
0871         qreal bottom = scene_rect.bottom();
0872 
0873         if (m_gridSettings.style == GridStyle::Line) {
0874             QLineF line;
0875 
0876             //horizontal lines
0877             y = top + m_gridSettings.verticalSpacing;
0878             while (y < bottom) {
0879                 line.setLine( left, y,  right, y );
0880                 painter->drawLine(line);
0881                 y += m_gridSettings.verticalSpacing;
0882             }
0883 
0884             //vertical lines
0885             x = left + m_gridSettings.horizontalSpacing;
0886             while (x < right) {
0887                 line.setLine( x, top,  x, bottom );
0888                 painter->drawLine(line);
0889                 x += m_gridSettings.horizontalSpacing;
0890             }
0891         } else { //DotGrid
0892             y = top + m_gridSettings.verticalSpacing;
0893             while (y < bottom) {
0894                 x = left;// + m_gridSettings.horizontalSpacing;
0895                 while (x < right) {
0896                     x += m_gridSettings.horizontalSpacing;
0897                     painter->drawPoint(x, y);
0898                 }
0899                 y += m_gridSettings.verticalSpacing;
0900             }
0901         }
0902     }
0903 }
0904 
0905 void WorksheetView::drawBackground(QPainter* painter, const QRectF& rect) {
0906     painter->save();
0907 
0908     //painter->setRenderHint(QPainter::Antialiasing);
0909     QRectF scene_rect = sceneRect();
0910 
0911     if (!m_worksheet->useViewSize()) {
0912         // background
0913         KColorScheme scheme(QPalette::Active, KColorScheme::Window);
0914         const QColor& color = scheme.background().color();
0915         if (!scene_rect.contains(rect))
0916             painter->fillRect(rect, color);
0917 
0918         //shadow
0919 //      int shadowSize = scene_rect.width()*0.02;
0920 //      QRectF rightShadowRect(scene_rect.right(), scene_rect.top() + shadowSize, shadowSize, scene_rect.height());
0921 //      QRectF bottomShadowRect(scene_rect.left() + shadowSize, scene_rect.bottom(), scene_rect.width(), shadowSize);
0922 //
0923 //      const QColor& shadeColor = scheme.shade(color, KColorScheme::MidShade);
0924 //      painter->fillRect(rightShadowRect.intersected(rect), shadeColor);
0925 //      painter->fillRect(bottomShadowRect.intersected(rect), shadeColor);
0926     }
0927 
0928     drawBackgroundItems(painter, scene_rect);
0929 
0930     invalidateScene(rect, QGraphicsScene::BackgroundLayer);
0931     painter->restore();
0932 }
0933 
0934 bool WorksheetView::isPlotAtPos(QPoint pos) const {
0935     bool plot = false;
0936     QGraphicsItem* item = itemAt(pos);
0937     if (item) {
0938         plot = item->data(0).toInt() == static_cast<int>(WorksheetElement::WorksheetElementName::NameCartesianPlot);
0939         if (!plot && item->parentItem())
0940             plot = item->parentItem()->data(0).toInt() == static_cast<int>(WorksheetElement::WorksheetElementName::NameCartesianPlot);
0941     }
0942 
0943     return plot;
0944 }
0945 
0946 CartesianPlot* WorksheetView::plotAt(QPoint pos) const {
0947     QGraphicsItem* item = itemAt(pos);
0948     if (!item)
0949         return nullptr;
0950 
0951     QGraphicsItem* plotItem = nullptr;
0952     if (item->data(0).toInt() == static_cast<int>(WorksheetElement::WorksheetElementName::NameCartesianPlot))
0953         plotItem = item;
0954     else {
0955         if (item->parentItem() && item->parentItem()->data(0).toInt() == static_cast<int>(WorksheetElement::WorksheetElementName::NameCartesianPlot))
0956             plotItem = item->parentItem();
0957     }
0958 
0959     if (plotItem == nullptr)
0960         return nullptr;
0961 
0962     CartesianPlot* plot = nullptr;
0963     for (auto* p : m_worksheet->children<CartesianPlot>()) {
0964         if (p->graphicsItem() == plotItem) {
0965             plot = p;
0966             break;
0967         }
0968     }
0969 
0970     return plot;
0971 }
0972 
0973 //##############################################################################
0974 //####################################  Events   ###############################
0975 //##############################################################################
0976 void WorksheetView::resizeEvent(QResizeEvent* event) {
0977     if (m_isClosing)
0978         return;
0979 
0980     if (m_worksheet->useViewSize())
0981         this->processResize();
0982 
0983     QGraphicsView::resizeEvent(event);
0984 }
0985 
0986 void WorksheetView::wheelEvent(QWheelEvent* event) {
0987     //https://wiki.qt.io/Smooth_Zoom_In_QGraphicsView
0988     if (m_mouseMode == MouseMode::ZoomSelection || (QApplication::keyboardModifiers() & Qt::ControlModifier)) {
0989         int numDegrees = event->delta() / 8;
0990         int numSteps = numDegrees / 15; // see QWheelEvent documentation
0991         zoom(numSteps);
0992     } else
0993         QGraphicsView::wheelEvent(event);
0994 }
0995 
0996 void WorksheetView::zoom(int numSteps) {
0997     m_numScheduledScalings += numSteps;
0998     if (m_numScheduledScalings * numSteps < 0) // if user moved the wheel in another direction, we reset previously scheduled scalings
0999         m_numScheduledScalings = numSteps;
1000 
1001     auto* anim = new QTimeLine(350, this);
1002     anim->setUpdateInterval(20);
1003 
1004     connect(anim, &QTimeLine::valueChanged, this, &WorksheetView::scalingTime);
1005     connect(anim, &QTimeLine::finished, this, &WorksheetView::animFinished);
1006     anim->start();
1007 }
1008 
1009 void WorksheetView::scalingTime() {
1010     qreal factor = 1.0 + qreal(m_numScheduledScalings) / 300.0;
1011     scale(factor, factor);
1012 }
1013 
1014 void WorksheetView::animFinished() {
1015     if (m_numScheduledScalings > 0)
1016         m_numScheduledScalings--;
1017     else
1018         m_numScheduledScalings++;
1019     sender()->~QObject();
1020 }
1021 
1022 void WorksheetView::mousePressEvent(QMouseEvent* event) {
1023     //prevent the deselection of items when context menu event
1024     //was triggered (right button click)
1025     if (event->button() == Qt::RightButton) {
1026         event->accept();
1027         return;
1028     }
1029 
1030     if (event->button() == Qt::LeftButton && m_mouseMode == MouseMode::ZoomSelection) {
1031         m_selectionStart = event->pos();
1032         m_selectionEnd = m_selectionStart; //select&zoom'g starts -> reset the end point to the start point
1033         m_selectionBandIsShown = true;
1034         QGraphicsView::mousePressEvent(event);
1035         return;
1036     }
1037 
1038     // select the worksheet in the project explorer if the view was clicked
1039     // and there is no selection currently. We need this for the case when
1040     // there is a single worksheet in the project and we change from the project-node
1041     // in the project explorer to the worksheet-node by clicking the view.
1042     if ( scene()->selectedItems().isEmpty() )
1043         m_worksheet->setSelectedInView(true);
1044 
1045     QGraphicsView::mousePressEvent(event);
1046 }
1047 
1048 void WorksheetView::mouseReleaseEvent(QMouseEvent* event) {
1049     if (event->button() == Qt::LeftButton && m_mouseMode == MouseMode::ZoomSelection) {
1050         m_selectionBandIsShown = false;
1051         viewport()->repaint(QRect(m_selectionStart, m_selectionEnd).normalized());
1052 
1053         //don't zoom if very small region was selected, avoid occasional/unwanted zooming
1054         m_selectionEnd = event->pos();
1055         if ( abs(m_selectionEnd.x() - m_selectionStart.x()) > 20 && abs(m_selectionEnd.y() - m_selectionStart.y()) > 20 )
1056             fitInView(mapToScene(QRect(m_selectionStart, m_selectionEnd).normalized()).boundingRect(), Qt::KeepAspectRatio);
1057     }
1058 
1059     QGraphicsView::mouseReleaseEvent(event);
1060 }
1061 
1062 void WorksheetView::mouseDoubleClickEvent(QMouseEvent*) {
1063     emit propertiesExplorerRequested();
1064 }
1065 
1066 void WorksheetView::mouseMoveEvent(QMouseEvent* event) {
1067     if (m_mouseMode == MouseMode::Selection && m_cartesianPlotMouseMode != CartesianPlot::MouseMode::Selection) {
1068         //check whether there is a cartesian plot under the cursor
1069         //and set the cursor appearance according to the current mouse mode for the cartesian plots
1070         if ( isPlotAtPos(event->pos()) ) {
1071             if (m_cartesianPlotMouseMode == CartesianPlot::MouseMode::ZoomSelection)
1072                 setCursor(Qt::CrossCursor);
1073             else if (m_cartesianPlotMouseMode == CartesianPlot::MouseMode::ZoomXSelection)
1074                 setCursor(Qt::SizeHorCursor);
1075             else if (m_cartesianPlotMouseMode == CartesianPlot::MouseMode::ZoomYSelection)
1076                 setCursor(Qt::SizeVerCursor);
1077         } else
1078             setCursor(Qt::ArrowCursor);
1079     } else if (m_mouseMode == MouseMode::Selection && m_cartesianPlotMouseMode == CartesianPlot::MouseMode::Selection)
1080         setCursor(Qt::ArrowCursor);
1081     else if (m_selectionBandIsShown) {
1082         QRect rect = QRect(m_selectionStart, m_selectionEnd).normalized();
1083         m_selectionEnd = event->pos();
1084         rect = rect.united(QRect(m_selectionStart, m_selectionEnd).normalized());
1085         qreal penWidth = 5/transform().m11();
1086         rect.setX(rect.x()-penWidth);
1087         rect.setY(rect.y()-penWidth);
1088         rect.setHeight(rect.height()+2*penWidth);
1089         rect.setWidth(rect.width()+2*penWidth);
1090         viewport()->repaint(rect);
1091     }
1092 
1093     //show the magnification window
1094     if (magnificationFactor /*&& m_mouseMode == SelectAndEditMode*/) {
1095         if (!m_magnificationWindow) {
1096             m_magnificationWindow = new QGraphicsPixmapItem(nullptr);
1097             m_magnificationWindow->setZValue(std::numeric_limits<int>::max());
1098             scene()->addItem(m_magnificationWindow);
1099         }
1100 
1101         m_magnificationWindow->setVisible(false);
1102 
1103         //copy the part of the view to be shown magnified
1104         QPointF pos = mapToScene(event->pos());
1105         const int size = Worksheet::convertToSceneUnits(2.0, Worksheet::Unit::Centimeter)/transform().m11();
1106 
1107         const QRectF copyRect(pos.x() - size/(2*magnificationFactor), pos.y() - size/(2*magnificationFactor), size/magnificationFactor, size/magnificationFactor);
1108         QPixmap px = grab(mapFromScene(copyRect).boundingRect());
1109         px = px.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1110 
1111         //draw the bounding rect
1112         QPainter painter(&px);
1113         const QPen pen = QPen(Qt::lightGray, 2/transform().m11());
1114         painter.setPen(pen);
1115         QRect rect = px.rect();
1116         rect.setWidth(rect.width()-pen.widthF()/2);
1117         rect.setHeight(rect.height()-pen.widthF()/2);
1118         painter.drawRect(rect);
1119 
1120         //set the pixmap
1121         m_magnificationWindow->setPixmap(px);
1122         m_magnificationWindow->setPos(pos.x()- px.width()/2, pos.y()- px.height()/2);
1123 
1124         m_magnificationWindow->setVisible(true);
1125     } else if (m_magnificationWindow)
1126         m_magnificationWindow->setVisible(false);
1127 
1128     QGraphicsView::mouseMoveEvent(event);
1129 }
1130 
1131 void WorksheetView::contextMenuEvent(QContextMenuEvent* e) {
1132     if ( (m_magnificationWindow && m_magnificationWindow->isVisible() && items(e->pos()).size() == 1) || !itemAt(e->pos()) ) {
1133         //no item or only the magnification window under the cursor -> show the context menu for the worksheet
1134         QMenu *menu = new QMenu(this);
1135         this->createContextMenu(menu);
1136         menu->exec(QCursor::pos());
1137     } else {
1138         //propagate the event to the scene and graphics items
1139         QGraphicsView::contextMenuEvent(e);
1140     }
1141 }
1142 
1143 void WorksheetView::keyPressEvent(QKeyEvent* event) {
1144     if (event->matches(QKeySequence::Copy)) {
1145         //add here copying of objects
1146         exportToClipboard();
1147     }
1148 
1149     QGraphicsView::keyPressEvent(event);
1150 }
1151 
1152 void WorksheetView::keyReleaseEvent(QKeyEvent* event) {
1153     QGraphicsView::keyReleaseEvent(event);
1154 }
1155 
1156 void WorksheetView::dragEnterEvent(QDragEnterEvent* event) {
1157     //ignore events not related to internal drags of columns etc., e.g. dropping of external files onto LabPlot
1158     const QMimeData* mimeData = event->mimeData();
1159     if (!mimeData) {
1160         event->ignore();
1161         return;
1162     }
1163 
1164     if (mimeData->formats().at(0) != QLatin1String("labplot-dnd")) {
1165         event->ignore();
1166         return;
1167     }
1168 
1169     //select the worksheet in the project explorer and bring the view to the foreground
1170     m_worksheet->setSelectedInView(true);
1171     m_worksheet->mdiSubWindow()->mdiArea()->setActiveSubWindow(m_worksheet->mdiSubWindow());
1172 
1173     event->setAccepted(true);
1174 }
1175 
1176 void WorksheetView::dragMoveEvent(QDragMoveEvent* event) {
1177     // only accept drop events if we have a plot under the cursor where we can drop columns onto
1178     bool plot = isPlotAtPos(event->pos());
1179     event->setAccepted(plot);
1180 }
1181 
1182 void WorksheetView::dropEvent(QDropEvent* event) {
1183     CartesianPlot* plot = plotAt(event->pos());
1184     if (!plot)
1185         return;
1186 
1187     const QMimeData* mimeData = event->mimeData();
1188     plot->processDropEvent(plot->project()->droppedAspects(mimeData));
1189 }
1190 
1191 //##############################################################################
1192 //####################################  SLOTs   ################################
1193 //##############################################################################
1194 void WorksheetView::useViewSizeRequested() {
1195     if (!m_actionsInitialized)
1196         initActions();
1197 
1198     if (m_worksheet->useViewSize()) {
1199         setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1200         setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1201         zoomFitPageHeightAction->setVisible(false);
1202         zoomFitPageWidthAction->setVisible(false);
1203         currentZoomAction = zoomInViewAction;
1204         if (tbZoom)
1205             tbZoom->setDefaultAction(zoomInViewAction);
1206 
1207         //determine and set the current view size
1208         this->processResize();
1209     } else {
1210         setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1211         setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1212         zoomFitPageHeightAction->setVisible(true);
1213         zoomFitPageWidthAction->setVisible(true);
1214     }
1215 }
1216 
1217 void WorksheetView::processResize() {
1218     if (size() != sceneRect().size()) {
1219         static const float hscale = QApplication::desktop()->physicalDpiX()/(Worksheet::convertToSceneUnits(1, Worksheet::Unit::Inch));
1220         static const float vscale = QApplication::desktop()->physicalDpiY()/(Worksheet::convertToSceneUnits(1, Worksheet::Unit::Inch));
1221         m_worksheet->setUndoAware(false);
1222         m_worksheet->setPageRect(QRectF(0.0, 0.0, width()/hscale, height()/vscale));
1223         m_worksheet->setUndoAware(true);
1224     }
1225 }
1226 
1227 void WorksheetView::changeZoom(QAction* action) {
1228     if (action == zoomInViewAction)
1229         zoom(1);
1230     else if (action == zoomOutViewAction)
1231         zoom(-1);
1232     else if (action == zoomOriginAction) {
1233         static const float hscale = QApplication::desktop()->physicalDpiX()/(Worksheet::convertToSceneUnits(1, Worksheet::Unit::Inch));
1234         static const float vscale = QApplication::desktop()->physicalDpiY()/(Worksheet::convertToSceneUnits(1, Worksheet::Unit::Inch));
1235         setTransform(QTransform::fromScale(hscale, vscale));
1236     } else if (action == zoomFitPageWidthAction) {
1237         float scaleFactor = viewport()->width()/scene()->sceneRect().width();
1238         setTransform(QTransform::fromScale(scaleFactor, scaleFactor));
1239     } else if (action == zoomFitPageHeightAction) {
1240         float scaleFactor = viewport()->height()/scene()->sceneRect().height();
1241         setTransform(QTransform::fromScale(scaleFactor, scaleFactor));
1242     } else if (action == zoomFitSelectionAction)
1243         fitInView(scene()->selectionArea().boundingRect(),Qt::KeepAspectRatio);
1244     currentZoomAction = action;
1245     if (tbZoom)
1246         tbZoom->setDefaultAction(action);
1247 }
1248 
1249 void WorksheetView::magnificationChanged(QAction* action) {
1250     if (action == noMagnificationAction)
1251         magnificationFactor = 0;
1252     else if (action == twoTimesMagnificationAction)
1253         magnificationFactor = 2;
1254     else if (action == threeTimesMagnificationAction)
1255         magnificationFactor = 3;
1256     else if (action == fourTimesMagnificationAction)
1257         magnificationFactor = 4;
1258     else if (action == fiveTimesMagnificationAction)
1259         magnificationFactor = 5;
1260 
1261     currentMagnificationAction = action;
1262     if (tbMagnification)
1263         tbMagnification->setDefaultAction(action);
1264 }
1265 
1266 void WorksheetView::mouseModeChanged(QAction* action) {
1267     if (action == selectionModeAction) {
1268         m_mouseMode = MouseMode::Selection;
1269         setInteractive(true);
1270         setDragMode(QGraphicsView::NoDrag);
1271     } else if (action == navigationModeAction) {
1272         m_mouseMode = MouseMode::Navigation;
1273         setInteractive(false);
1274         setDragMode(QGraphicsView::ScrollHandDrag);
1275     } else {
1276         m_mouseMode = MouseMode::ZoomSelection;
1277         setInteractive(false);
1278         setDragMode(QGraphicsView::NoDrag);
1279     }
1280 }
1281 
1282 //"Add new" related slots
1283 void WorksheetView::addNew(QAction* action) {
1284     WorksheetElement* aspect = nullptr;
1285     if (action == addCartesianPlot1Action) {
1286         CartesianPlot* plot = new CartesianPlot(i18n("xy-plot"));
1287         plot->setType(CartesianPlot::Type::FourAxes);
1288         plot->setMouseMode(m_cartesianPlotMouseMode);
1289         aspect = plot;
1290         if (tbNewCartesianPlot)
1291             tbNewCartesianPlot->setDefaultAction(addCartesianPlot1Action);
1292     } else if (action == addCartesianPlot2Action) {
1293         CartesianPlot* plot = new CartesianPlot(i18n("xy-plot"));
1294         plot->setType(CartesianPlot::Type::TwoAxes);
1295         plot->setMouseMode(m_cartesianPlotMouseMode);
1296         aspect = plot;
1297         if (tbNewCartesianPlot)
1298             tbNewCartesianPlot->setDefaultAction(addCartesianPlot2Action);
1299     } else if (action == addCartesianPlot3Action) {
1300         CartesianPlot* plot = new CartesianPlot(i18n("xy-plot"));
1301         plot->setType(CartesianPlot::Type::TwoAxesCentered);
1302         plot->setMouseMode(m_cartesianPlotMouseMode);
1303         aspect = plot;
1304         if (tbNewCartesianPlot)
1305             tbNewCartesianPlot->setDefaultAction(addCartesianPlot3Action);
1306     } else if (action == addCartesianPlot4Action) {
1307         CartesianPlot* plot = new CartesianPlot(i18n("xy-plot"));
1308         plot->setType(CartesianPlot::Type::TwoAxesCenteredZero);
1309         plot->setMouseMode(m_cartesianPlotMouseMode);
1310         aspect = plot;
1311         if (tbNewCartesianPlot)
1312             tbNewCartesianPlot->setDefaultAction(addCartesianPlot4Action);
1313     } else if (action == addTextLabelAction) {
1314         TextLabel* l = new TextLabel(i18n("Text Label"));
1315         l->setText(i18n("Text Label"));
1316         aspect = l;
1317     } else if (action == addImageAction) {
1318         Image* l = new Image(i18n("Image"));
1319         aspect = l;
1320     }
1321     if (!aspect)
1322         return;
1323 
1324     m_worksheet->addChild(aspect);
1325 
1326     //labels and images with their initial positions need to be retransformed
1327     //ater they have gotten a parent
1328     if (aspect->type() == AspectType::TextLabel || aspect->type() == AspectType::Image)
1329         aspect->retransform();
1330 
1331     handleCartesianPlotActions();
1332 
1333     if (!m_fadeInTimeLine) {
1334         m_fadeInTimeLine = new QTimeLine(1000, this);
1335         m_fadeInTimeLine->setFrameRange(0, 100);
1336         connect(m_fadeInTimeLine, &QTimeLine::valueChanged, this, &WorksheetView::fadeIn);
1337     }
1338 
1339     //if there is already an element fading in, stop the time line and show the element with the full opacity.
1340     if (m_fadeInTimeLine->state() == QTimeLine::Running) {
1341         m_fadeInTimeLine->stop();
1342         auto* effect = new QGraphicsOpacityEffect();
1343         effect->setOpacity(1);
1344         lastAddedWorksheetElement->graphicsItem()->setGraphicsEffect(effect);
1345     }
1346 
1347     //fade-in the newly added element
1348     lastAddedWorksheetElement = aspect;
1349     auto* effect = new QGraphicsOpacityEffect();
1350     effect->setOpacity(0);
1351     lastAddedWorksheetElement->graphicsItem()->setGraphicsEffect(effect);
1352     m_fadeInTimeLine->start();
1353 }
1354 
1355 /*!
1356  * select all top-level items
1357  */
1358 void WorksheetView::selectAllElements() {
1359     //deselect all previously selected items since there can be some non top-level items belong them
1360     m_suppressSelectionChangedEvent = true;
1361     for (auto* item : m_selectedItems)
1362         m_worksheet->setItemSelectedInView(item, false);
1363 
1364     //select top-level items
1365     for (auto* item : scene()->items()) {
1366         if (!item->parentItem())
1367             item->setSelected(true);
1368     }
1369     m_suppressSelectionChangedEvent = false;
1370     this->selectionChanged();
1371 }
1372 
1373 /*!
1374  * deletes selected worksheet elements
1375  */
1376 void WorksheetView::deleteElement() {
1377     if (m_selectedItems.isEmpty())
1378         return;
1379 
1380     int rc = KMessageBox::warningYesNo( this, i18np("Do you really want to delete the selected object?", "Do you really want to delete the selected %1 objects?", m_selectedItems.size()),
1381                 i18np("Delete selected object", "Delete selected objects", m_selectedItems.size()));
1382 
1383     if (rc == KMessageBox::No)
1384         return;
1385 
1386     m_suppressSelectionChangedEvent = true;
1387     m_worksheet->beginMacro(i18n("%1: Remove selected worksheet elements.", m_worksheet->name()));
1388     for (auto* item : m_selectedItems)
1389         m_worksheet->deleteAspectFromGraphicsItem(item);
1390     m_worksheet->endMacro();
1391     m_suppressSelectionChangedEvent = false;
1392 }
1393 
1394 void WorksheetView::aspectAboutToBeRemoved(const AbstractAspect* aspect) {
1395     lastAddedWorksheetElement = dynamic_cast<WorksheetElement*>(const_cast<AbstractAspect*>(aspect));
1396     if (!lastAddedWorksheetElement)
1397         return;
1398 
1399     //FIXME: fading-out doesn't work
1400     //also, the following code collides with undo/redo of the deletion
1401     //of a worksheet element (after redoing the element is not shown with the full opacity
1402     /*
1403         if (!m_fadeOutTimeLine) {
1404             m_fadeOutTimeLine = new QTimeLine(1000, this);
1405             m_fadeOutTimeLine->setFrameRange(0, 100);
1406             connect(m_fadeOutTimeLine, SIGNAL(valueChanged(qreal)), this, SLOT(fadeOut(qreal)));
1407         }
1408 
1409         //if there is already an element fading out, stop the time line
1410         if (m_fadeOutTimeLine->state() == QTimeLine::Running)
1411             m_fadeOutTimeLine->stop();
1412 
1413         m_fadeOutTimeLine->start();
1414     */
1415 }
1416 
1417 void WorksheetView::fadeIn(qreal value) {
1418     auto* effect = new QGraphicsOpacityEffect();
1419     effect->setOpacity(value);
1420     lastAddedWorksheetElement->graphicsItem()->setGraphicsEffect(effect);
1421 }
1422 
1423 void WorksheetView::fadeOut(qreal value) {
1424     auto* effect = new QGraphicsOpacityEffect();
1425     effect->setOpacity(1 - value);
1426     lastAddedWorksheetElement->graphicsItem()->setGraphicsEffect(effect);
1427 }
1428 
1429 /*!
1430  * called when one of the layout-actions in WorkseetView was triggered.
1431  * sets the layout in Worksheet and enables/disables the layout actions.
1432  */
1433 void WorksheetView::changeLayout(QAction* action) {
1434     if (action == breakLayoutAction) {
1435         verticalLayoutAction->setEnabled(true);
1436         verticalLayoutAction->setChecked(false);
1437 
1438         horizontalLayoutAction->setEnabled(true);
1439         horizontalLayoutAction->setChecked(false);
1440 
1441         gridLayoutAction->setEnabled(true);
1442         gridLayoutAction->setChecked(false);
1443 
1444         breakLayoutAction->setEnabled(false);
1445 
1446         m_worksheet->setLayout(Worksheet::Layout::NoLayout);
1447     } else {
1448         verticalLayoutAction->setEnabled(false);
1449         horizontalLayoutAction->setEnabled(false);
1450         gridLayoutAction->setEnabled(false);
1451         breakLayoutAction->setEnabled(true);
1452 
1453         if (action == verticalLayoutAction) {
1454             verticalLayoutAction->setChecked(true);
1455             m_worksheet->setLayout(Worksheet::Layout::VerticalLayout);
1456         } else if (action == horizontalLayoutAction) {
1457             horizontalLayoutAction->setChecked(true);
1458             m_worksheet->setLayout(Worksheet::Layout::HorizontalLayout);
1459         } else {
1460             gridLayoutAction->setChecked(true);
1461             m_worksheet->setLayout(Worksheet::Layout::GridLayout);
1462         }
1463     }
1464 }
1465 
1466 void WorksheetView::changeGrid(QAction* action) {
1467     if (action == noGridAction) {
1468         m_gridSettings.style = GridStyle::NoGrid;
1469         snapToGridAction->setEnabled(false);
1470     } else if (action == sparseLineGridAction) {
1471         m_gridSettings.style = GridStyle::Line;
1472         m_gridSettings.color = Qt::gray;
1473         m_gridSettings.opacity = 0.7;
1474         m_gridSettings.horizontalSpacing = 15;
1475         m_gridSettings.verticalSpacing = 15;
1476     } else if (action == denseLineGridAction) {
1477         m_gridSettings.style = GridStyle::Line;
1478         m_gridSettings.color = Qt::gray;
1479         m_gridSettings.opacity = 0.7;
1480         m_gridSettings.horizontalSpacing = 5;
1481         m_gridSettings.verticalSpacing = 5;
1482     } else if (action == denseDotGridAction) {
1483         m_gridSettings.style = GridStyle::Dot;
1484         m_gridSettings.color = Qt::black;
1485         m_gridSettings.opacity = 0.7;
1486         m_gridSettings.horizontalSpacing = 5;
1487         m_gridSettings.verticalSpacing = 5;
1488     } else if (action == sparseDotGridAction) {
1489         m_gridSettings.style = GridStyle::Dot;
1490         m_gridSettings.color = Qt::black;
1491         m_gridSettings.opacity = 0.7;
1492         m_gridSettings.horizontalSpacing = 15;
1493         m_gridSettings.verticalSpacing = 15;
1494     } else if (action == customGridAction) {
1495         auto* dlg = new GridDialog(this);
1496         if (dlg->exec() == QDialog::Accepted)
1497             dlg->save(m_gridSettings);
1498         else
1499             return;
1500     }
1501 
1502     if (m_gridSettings.style == GridStyle::NoGrid)
1503         snapToGridAction->setEnabled(false);
1504     else
1505         snapToGridAction->setEnabled(true);
1506 
1507     invalidateScene(sceneRect(), QGraphicsScene::BackgroundLayer);
1508 }
1509 
1510 //TODO
1511 void WorksheetView::changeSnapToGrid() {
1512 
1513 }
1514 
1515 /*!
1516  *  Selects the QGraphicsItem \c item in \c WorksheetView.
1517  *  The selection in \c ProjectExplorer is forwarded to  \c Worksheet
1518  *  and is finally handled here.
1519  */
1520 void WorksheetView::selectItem(QGraphicsItem* item) {
1521     m_suppressSelectionChangedEvent = true;
1522     item->setSelected(true);
1523     m_selectedItems<<item;
1524     handleCartesianPlotActions();
1525     m_suppressSelectionChangedEvent = false;
1526 }
1527 
1528 /*!
1529  *  Deselects the \c QGraphicsItem \c item in \c WorksheetView.
1530  *  The deselection in \c ProjectExplorer is forwarded to \c Worksheet
1531  *  and is finally handled here.
1532  */
1533 void WorksheetView::deselectItem(QGraphicsItem* item) {
1534     m_suppressSelectionChangedEvent = true;
1535     item->setSelected(false);
1536     m_selectedItems.removeOne(item);
1537     handleCartesianPlotActions();
1538     m_suppressSelectionChangedEvent = false;
1539 }
1540 
1541 /*!
1542  *  Called on selection changes in the view.
1543  *   Determines which items were selected and deselected
1544  *  and forwards these changes to \c Worksheet
1545  */
1546 void WorksheetView::selectionChanged() {
1547     //if the project is being closed, the scene items are being removed and the selection can change.
1548     //don't react on these changes since this can lead crashes (worksheet object is already in the destructor).
1549     if (m_isClosing)
1550         return;
1551 
1552     if (m_suppressSelectionChangedEvent)
1553         return;
1554 
1555     QList<QGraphicsItem*> items = scene()->selectedItems();
1556 
1557     //check, whether the previously selected items were deselected now.
1558     //Forward the deselection prior to the selection of new items
1559     //in order to avoid the unwanted multiple selection in project explorer
1560     for (auto* item : m_selectedItems ) {
1561         if ( items.indexOf(item) == -1 )
1562             m_worksheet->setItemSelectedInView(item, false);
1563     }
1564 
1565     //select new items
1566     if (items.isEmpty()) {
1567         //no items selected -> select the worksheet again.
1568         m_worksheet->setSelectedInView(true);
1569 
1570         //if one of the "zoom&select" plot mouse modes was selected before, activate the default "selection mode" again
1571         //since no plots are selected now.
1572         if (m_mouseMode == MouseMode::Selection && m_cartesianPlotMouseMode != CartesianPlot::MouseMode::Selection) {
1573             cartesianPlotSelectionModeAction->setChecked(true);
1574             cartesianPlotMouseModeChanged(cartesianPlotSelectionModeAction);
1575         }
1576     } else {
1577         for (const auto* item : items)
1578             m_worksheet->setItemSelectedInView(item, true);
1579 
1580         //items selected -> deselect the worksheet in the project explorer
1581         //prevents unwanted multiple selection with worksheet (if it was selected before)
1582         m_worksheet->setSelectedInView(false);
1583     }
1584 
1585     m_selectedItems = items;
1586     handleCartesianPlotActions();
1587 }
1588 
1589 //check whether we have cartesian plots selected and activate/deactivate
1590 void WorksheetView::handleCartesianPlotActions() {
1591     if (!m_menusInitialized)
1592         return;
1593 
1594     bool plot = false;
1595     if (m_worksheet->cartesianPlotActionMode() == Worksheet::CartesianPlotActionMode::ApplyActionToSelection) {
1596         //check whether we have cartesian plots selected
1597         for (auto* item : m_selectedItems) {
1598             //TODO: or if a children of a plot is selected
1599             if (item->data(0).toInt() == static_cast<int>(WorksheetElement::WorksheetElementName::NameCartesianPlot)) {
1600                 plot = true;
1601                 break;
1602             }
1603         }
1604     } else {
1605         //actions are applied to all available plots -> check whether we have plots
1606         plot = (m_worksheet->children<CartesianPlot>().size() != 0);
1607     }
1608 
1609     cartesianPlotSelectionModeAction->setEnabled(plot);
1610     cartesianPlotZoomSelectionModeAction->setEnabled(plot);
1611     cartesianPlotZoomXSelectionModeAction->setEnabled(plot);
1612     cartesianPlotZoomYSelectionModeAction->setEnabled(plot);
1613     cartesianPlotCursorModeAction->setEnabled(plot);
1614 
1615     m_cartesianPlotAddNewMenu->setEnabled(plot);
1616     m_cartesianPlotZoomMenu->setEnabled(plot);
1617     m_cartesianPlotMouseModeMenu->setEnabled(plot);
1618 
1619     // analysis menu
1620     //TODO: enable also if children of plots are selected
1621 //  m_dataManipulationMenu->setEnabled(plot);
1622 //  addDataOperationAction->setEnabled(false);
1623     addDataReductionAction->setEnabled(false);
1624     addDifferentiationAction->setEnabled(plot);
1625     addIntegrationAction->setEnabled(plot);
1626     addInterpolationAction->setEnabled(plot);
1627     addSmoothAction->setEnabled(plot);
1628     addFitAction->setEnabled(plot);
1629     addFourierFilterAction->setEnabled(plot);
1630     addFourierTransformAction->setEnabled(plot);
1631     addConvolutionAction->setEnabled(plot);
1632     addCorrelationAction->setEnabled(plot);
1633 }
1634 
1635 void WorksheetView::exportToFile(const QString& path, const ExportFormat format, const ExportArea area, const bool background, const int resolution) {
1636     QRectF sourceRect;
1637 
1638     //determine the rectangular to print
1639     if (area == ExportArea::BoundingBox)
1640         sourceRect = scene()->itemsBoundingRect();
1641     else if (area == ExportArea::Selection) {
1642         //TODO doesn't work: rect = scene()->selectionArea().boundingRect();
1643         for (const auto* item : m_selectedItems)
1644             sourceRect = sourceRect.united( item->mapToScene(item->boundingRect()).boundingRect() );
1645     } else
1646         sourceRect = scene()->sceneRect();
1647 
1648     //save
1649     switch (format) {
1650     case ExportFormat::PDF: {
1651         QPrinter printer(QPrinter::HighResolution);
1652         printer.setOutputFormat(QPrinter::PdfFormat);
1653 
1654         printer.setOutputFileName(path);
1655         int w = Worksheet::convertFromSceneUnits(sourceRect.width(), Worksheet::Unit::Millimeter);
1656         int h = Worksheet::convertFromSceneUnits(sourceRect.height(), Worksheet::Unit::Millimeter);
1657         printer.setPaperSize( QSizeF(w, h), QPrinter::Millimeter);
1658         printer.setPageMargins(0,0,0,0, QPrinter::Millimeter);
1659         printer.setPrintRange(QPrinter::PageRange);
1660         printer.setCreator(QLatin1String("LabPlot ") + LVERSION);
1661 
1662         QPainter painter(&printer);
1663         painter.setRenderHint(QPainter::Antialiasing);
1664         QRectF targetRect(0, 0, painter.device()->width(),painter.device()->height());
1665         painter.begin(&printer);
1666         exportPaint(&painter, targetRect, sourceRect, background);
1667         painter.end();
1668         break;
1669     }
1670     case ExportFormat::SVG: {
1671         QSvgGenerator generator;
1672         generator.setFileName(path);
1673 //      if (!generator.isValid()) {
1674 //          RESET_CURSOR;
1675 //          QMessageBox::critical(nullptr, i18n("Failed to export"), i18n("Failed to write to '%1'. Please check the path.", path));
1676 //      }
1677         int w = Worksheet::convertFromSceneUnits(sourceRect.width(), Worksheet::Unit::Millimeter);
1678         int h = Worksheet::convertFromSceneUnits(sourceRect.height(), Worksheet::Unit::Millimeter);
1679         w = w*QApplication::desktop()->physicalDpiX()/25.4;
1680         h = h*QApplication::desktop()->physicalDpiY()/25.4;
1681 
1682         generator.setSize(QSize(w, h));
1683         QRectF targetRect(0, 0, w, h);
1684         generator.setViewBox(targetRect);
1685 
1686         QPainter painter;
1687         painter.begin(&generator);
1688         exportPaint(&painter, targetRect, sourceRect, background);
1689         painter.end();
1690         break;
1691     }
1692     case  ExportFormat::PNG:
1693     case  ExportFormat::JPG:
1694     case  ExportFormat::BMP:
1695     case  ExportFormat::PPM:
1696     case  ExportFormat::XBM:
1697     case  ExportFormat::XPM: {
1698         int w = Worksheet::convertFromSceneUnits(sourceRect.width(), Worksheet::Unit::Millimeter);
1699         int h = Worksheet::convertFromSceneUnits(sourceRect.height(), Worksheet::Unit::Millimeter);
1700         w = w*resolution/25.4;
1701         h = h*resolution/25.4;
1702         QImage image(QSize(w, h), QImage::Format_ARGB32_Premultiplied);
1703         image.fill(Qt::transparent);
1704         QRectF targetRect(0, 0, w, h);
1705 
1706         QPainter painter;
1707         painter.begin(&image);
1708         painter.setRenderHint(QPainter::Antialiasing);
1709         exportPaint(&painter, targetRect, sourceRect, background);
1710         painter.end();
1711 
1712         if (!path.isEmpty()) {
1713             bool rc{false};
1714             switch (format) {
1715             case  ExportFormat::PNG:
1716                 rc = image.save(path, "PNG");
1717                 break;
1718             case  ExportFormat::JPG:
1719                 rc = image.save(path, "JPG");
1720                 break;
1721             case  ExportFormat::BMP:
1722                 rc = image.save(path, "BMP");
1723                 break;
1724             case  ExportFormat::PPM:
1725                 rc = image.save(path, "PPM");
1726                 break;
1727             case  ExportFormat::XBM:
1728                 rc = image.save(path, "XBM");
1729                 break;
1730             case  ExportFormat::XPM:
1731                 rc = image.save(path, "XPM");
1732                 break;
1733             case ExportFormat::PDF:
1734             case ExportFormat::SVG:
1735                 break;
1736             }
1737             if (!rc) {
1738                 RESET_CURSOR;
1739                 QMessageBox::critical(nullptr, i18n("Failed to export"), i18n("Failed to write to '%1'. Please check the path.", path));
1740             }
1741         } else
1742             QApplication::clipboard()->setImage(image, QClipboard::Clipboard);
1743     }
1744     }
1745 }
1746 
1747 void WorksheetView::exportToClipboard() {
1748     QRectF sourceRect;
1749 
1750     if (m_selectedItems.size() == 0)
1751         sourceRect = scene()->itemsBoundingRect();
1752     else {
1753         //export selection
1754         for (const auto* item : m_selectedItems)
1755             sourceRect = sourceRect.united( item->mapToScene(item->boundingRect()).boundingRect() );
1756     }
1757 
1758     int w = Worksheet::convertFromSceneUnits(sourceRect.width(), Worksheet::Unit::Millimeter);
1759     int h = Worksheet::convertFromSceneUnits(sourceRect.height(), Worksheet::Unit::Millimeter);
1760     w = w*QApplication::desktop()->physicalDpiX()/25.4;
1761     h = h*QApplication::desktop()->physicalDpiY()/25.4;
1762     QImage image(QSize(w, h), QImage::Format_ARGB32_Premultiplied);
1763     image.fill(Qt::transparent);
1764     QRectF targetRect(0, 0, w, h);
1765 
1766     QPainter painter;
1767     painter.begin(&image);
1768     painter.setRenderHint(QPainter::Antialiasing);
1769     exportPaint(&painter, targetRect, sourceRect, true);
1770     painter.end();
1771 
1772     QApplication::clipboard()->setImage(image, QClipboard::Clipboard);
1773 }
1774 
1775 void WorksheetView::exportPaint(QPainter* painter, const QRectF& targetRect, const QRectF& sourceRect, const bool background) {
1776     //draw the background
1777     if (background) {
1778         painter->save();
1779         painter->scale(targetRect.width()/sourceRect.width(), targetRect.height()/sourceRect.height());
1780         drawBackground(painter, sourceRect);
1781         painter->restore();
1782     }
1783 
1784     //draw the scene items
1785     m_worksheet->setPrinting(true);
1786     scene()->render(painter, QRectF(), sourceRect);
1787     m_worksheet->setPrinting(false);
1788 }
1789 
1790 void WorksheetView::print(QPrinter* printer) {
1791     m_worksheet->setPrinting(true);
1792     QPainter painter(printer);
1793     painter.setRenderHint(QPainter::Antialiasing);
1794 
1795     // draw background
1796     QRectF page_rect = printer->pageRect();
1797     QRectF scene_rect = scene()->sceneRect();
1798     float scale = qMax(scene_rect.width()/page_rect.width(),scene_rect.height()/page_rect.height());
1799     drawBackgroundItems(&painter, QRectF(0,0,scene_rect.width()/scale,scene_rect.height()/scale));
1800 
1801     // draw scene
1802     scene()->render(&painter);
1803     m_worksheet->setPrinting(false);
1804 }
1805 
1806 void WorksheetView::updateBackground() {
1807     invalidateScene(sceneRect(), QGraphicsScene::BackgroundLayer);
1808 }
1809 
1810 /*!
1811  * called when the layout was changed in Worksheet,
1812  * enables the corresponding action
1813  */
1814 void WorksheetView::layoutChanged(Worksheet::Layout layout) {
1815     if (layout == Worksheet::Layout::NoLayout) {
1816         verticalLayoutAction->setEnabled(true);
1817         verticalLayoutAction->setChecked(false);
1818 
1819         horizontalLayoutAction->setEnabled(true);
1820         horizontalLayoutAction->setChecked(false);
1821 
1822         gridLayoutAction->setEnabled(true);
1823         gridLayoutAction->setChecked(false);
1824 
1825         breakLayoutAction->setEnabled(false);
1826     } else {
1827         verticalLayoutAction->setEnabled(false);
1828         horizontalLayoutAction->setEnabled(false);
1829         gridLayoutAction->setEnabled(false);
1830         breakLayoutAction->setEnabled(true);
1831 
1832         if (layout == Worksheet::Layout::VerticalLayout)
1833             verticalLayoutAction->setChecked(true);
1834         else if (layout == Worksheet::Layout::HorizontalLayout)
1835             horizontalLayoutAction->setChecked(true);
1836         else
1837             gridLayoutAction->setChecked(true);
1838     }
1839 }
1840 
1841 void WorksheetView::suppressSelectionChangedEvent(bool value) {
1842     m_suppressSelectionChangedEvent = value;
1843 }
1844 
1845 void WorksheetView::registerShortcuts() {
1846     selectAllAction->setShortcut(Qt::CTRL+Qt::Key_A);
1847     deleteAction->setShortcut(Qt::Key_Delete);
1848     backspaceAction->setShortcut(Qt::Key_Backspace);
1849     zoomInViewAction->setShortcut(Qt::CTRL+Qt::Key_Plus);
1850     zoomOutViewAction->setShortcut(Qt::CTRL+Qt::Key_Minus);
1851     zoomOriginAction->setShortcut(Qt::CTRL+Qt::Key_1);
1852 }
1853 
1854 void WorksheetView::unregisterShortcuts() {
1855     selectAllAction->setShortcut(QKeySequence());
1856     deleteAction->setShortcut(QKeySequence());
1857     backspaceAction->setShortcut(QKeySequence());
1858     zoomInViewAction->setShortcut(QKeySequence());
1859     zoomOutViewAction->setShortcut(QKeySequence());
1860     zoomOriginAction->setShortcut(QKeySequence());
1861 }
1862 
1863 //##############################################################################
1864 //########################  SLOTs for cartesian plots   ########################
1865 //##############################################################################
1866 void WorksheetView::cartesianPlotActionModeChanged(QAction* action) {
1867     if (action == cartesianPlotApplyToSelectionAction)
1868         m_worksheet->setCartesianPlotActionMode(Worksheet::CartesianPlotActionMode::ApplyActionToSelection);
1869     else
1870         m_worksheet->setCartesianPlotActionMode(Worksheet::CartesianPlotActionMode::ApplyActionToAll);
1871 
1872     handleCartesianPlotActions();
1873 }
1874 
1875 void WorksheetView::cartesianPlotCursorModeChanged(QAction* action) {
1876     if (action == cartesianPlotApplyToSelectionCursor)
1877         m_worksheet->setCartesianPlotCursorMode(Worksheet::CartesianPlotActionMode::ApplyActionToSelection);
1878     else
1879         m_worksheet->setCartesianPlotCursorMode(Worksheet::CartesianPlotActionMode::ApplyActionToAll);
1880 
1881     handleCartesianPlotActions();
1882 }
1883 
1884 void WorksheetView::plotsLockedActionChanged(bool checked) {
1885     m_worksheet->setPlotsLocked(checked);
1886 }
1887 
1888 void WorksheetView::cartesianPlotMouseModeChanged(QAction* action) {
1889     if (m_suppressMouseModeChange)
1890         return;
1891 
1892     if (action == cartesianPlotSelectionModeAction)
1893         m_cartesianPlotMouseMode = CartesianPlot::MouseMode::Selection;
1894     else if (action == cartesianPlotZoomSelectionModeAction)
1895         m_cartesianPlotMouseMode = CartesianPlot::MouseMode::ZoomSelection;
1896     else if (action == cartesianPlotZoomXSelectionModeAction)
1897         m_cartesianPlotMouseMode = CartesianPlot::MouseMode::ZoomXSelection;
1898     else if (action == cartesianPlotZoomYSelectionModeAction)
1899         m_cartesianPlotMouseMode = CartesianPlot::MouseMode::ZoomYSelection;
1900     else if (action == cartesianPlotCursorModeAction)
1901         m_cartesianPlotMouseMode = CartesianPlot::MouseMode::Cursor;
1902 
1903     for (auto* plot : m_worksheet->children<CartesianPlot>() )
1904         plot->setMouseMode(m_cartesianPlotMouseMode);
1905 }
1906 
1907 void WorksheetView::cartesianPlotMouseModeChangedSlot(CartesianPlot::MouseMode mouseMode) {
1908     if (!m_menusInitialized)
1909         return;
1910 
1911     m_suppressMouseModeChange = true;
1912     if (mouseMode == CartesianPlot::MouseMode::Selection)
1913         cartesianPlotSelectionModeAction->setChecked(true);
1914     else if (mouseMode == CartesianPlot::MouseMode::ZoomSelection)
1915         cartesianPlotZoomSelectionModeAction->setChecked(true);
1916     else if (mouseMode == CartesianPlot::MouseMode::ZoomXSelection)
1917         cartesianPlotZoomXSelectionModeAction->setChecked(true);
1918     else if (mouseMode == CartesianPlot::MouseMode::ZoomYSelection)
1919         cartesianPlotZoomYSelectionModeAction->setChecked(true);
1920     else if (mouseMode == CartesianPlot::MouseMode::Cursor)
1921         cartesianPlotCursorModeAction->setChecked(true);
1922     m_suppressMouseModeChange = false;
1923 }
1924 
1925 void WorksheetView::cartesianPlotAddNew(QAction* action) {
1926     QVector<CartesianPlot*> plots = m_worksheet->children<CartesianPlot>();
1927     if (m_worksheet->cartesianPlotActionMode() == Worksheet::CartesianPlotActionMode::ApplyActionToSelection) {
1928         int selectedPlots = 0;
1929         for (auto* plot : plots) {
1930             if (m_selectedItems.indexOf(plot->graphicsItem()) != -1)
1931                 ++selectedPlots;
1932             else {
1933                 //current plot is not selected, check if one of its children is selected
1934                 auto children = plot->children<WorksheetElement>();
1935                 for (auto* child : children) {
1936                     if (m_selectedItems.indexOf(child->graphicsItem()) != -1) {
1937                         ++selectedPlots;
1938                         break;
1939                     }
1940                 }
1941             }
1942         }
1943 
1944         if  (selectedPlots > 1)
1945             m_worksheet->beginMacro(i18n("%1: Add curve to %2 plots", m_worksheet->name(), selectedPlots));
1946 
1947         for (auto* plot : plots) {
1948             if (m_selectedItems.indexOf(plot->graphicsItem()) != -1)
1949                 this->cartesianPlotAdd(plot, action);
1950             else {
1951                 //current plot is not selected, check if one of its children is selected
1952                 auto children = plot->children<WorksheetElement>();
1953                 for (auto* child : children) {
1954                     if (m_selectedItems.indexOf(child->graphicsItem()) != -1) {
1955                         this->cartesianPlotAdd(plot, action);
1956                         break;
1957                     }
1958                 }
1959             }
1960         }
1961 
1962         if (selectedPlots > 1)
1963             m_worksheet->endMacro();
1964     } else {
1965         if  (plots.size() > 1)
1966             m_worksheet->beginMacro(i18n("%1: Add curve to %2 plots", m_worksheet->name(), plots.size()));
1967 
1968         for (auto* plot : plots)
1969             this->cartesianPlotAdd(plot, action);
1970 
1971         if  (plots.size() > 1)
1972             m_worksheet->endMacro();
1973     }
1974 }
1975 
1976 void WorksheetView::cartesianPlotAdd(CartesianPlot* plot, QAction* action) {
1977     DEBUG("WorksheetView::cartesianPlotAdd()");
1978     if (action == addCurveAction)
1979         plot->addCurve();
1980     else if (action == addHistogramAction)
1981         plot->addHistogram();
1982     else if (action == addEquationCurveAction)
1983         plot->addEquationCurve();
1984     else if (action == addDataReductionCurveAction)
1985         plot->addDataReductionCurve();
1986     else if (action == addDifferentiationCurveAction)
1987         plot->addDifferentiationCurve();
1988     else if (action == addIntegrationCurveAction)
1989         plot->addIntegrationCurve();
1990     else if (action == addInterpolationCurveAction)
1991         plot->addInterpolationCurve();
1992     else if (action == addSmoothCurveAction)
1993         plot->addSmoothCurve();
1994     else if (action == addFitCurveAction)
1995         plot->addFitCurve();
1996     else if (action == addFourierFilterCurveAction)
1997         plot->addFourierFilterCurve();
1998     else if (action == addFourierTransformCurveAction)
1999         plot->addFourierTransformCurve();
2000     else if (action == addConvolutionCurveAction)
2001         plot->addConvolutionCurve();
2002     else if (action == addCorrelationCurveAction)
2003         plot->addCorrelationCurve();
2004     else if (action == addLegendAction)
2005         plot->addLegend();
2006     else if (action == addHorizontalAxisAction)
2007         plot->addHorizontalAxis();
2008     else if (action == addVerticalAxisAction)
2009         plot->addVerticalAxis();
2010     else if (action == addPlotTextLabelAction)
2011         plot->addTextLabel();
2012     else if (action == addPlotImageAction)
2013         plot->addImage();
2014     else if (action == addCustomPointAction)
2015         plot->addCustomPoint();
2016 // analysis actions
2017     else if (action == addDataReductionAction)
2018         plot->addDataReductionCurve();
2019     else if (action == addDifferentiationAction)
2020         plot->addDifferentiationCurve();
2021     else if (action == addIntegrationAction)
2022         plot->addIntegrationCurve();
2023     else if (action == addInterpolationAction)
2024         plot->addInterpolationCurve();
2025     else if (action == addSmoothAction)
2026         plot->addSmoothCurve();
2027     else if (action == addFitAction)
2028         plot->addFitCurve();
2029     else if (action == addFourierFilterAction)
2030         plot->addFourierFilterCurve();
2031     else if (action == addFourierTransformAction)
2032         plot->addFourierTransformCurve();
2033     else if (action == addConvolutionAction)
2034         plot->addConvolutionCurve();
2035     else if (action == addCorrelationAction)
2036         plot->addCorrelationCurve();
2037 }
2038 
2039 void WorksheetView::cartesianPlotNavigationChanged(QAction* action) {
2040     CartesianPlot::NavigationOperation op = (CartesianPlot::NavigationOperation)action->data().toInt();
2041     if (m_worksheet->cartesianPlotActionMode() == Worksheet::CartesianPlotActionMode::ApplyActionToSelection) {
2042         for (auto* plot : m_worksheet->children<CartesianPlot>() ) {
2043             if (m_selectedItems.indexOf(plot->graphicsItem()) != -1)
2044                 plot->navigate(op);
2045             else {
2046                 // check if one of the plots childrend is selected. Do the operation there too.
2047                 for (auto* child : plot->children<WorksheetElement>()) {
2048                     if (m_selectedItems.indexOf(child->graphicsItem()) != -1) {
2049                         plot->navigate(op);
2050                         break;
2051                     }
2052                 }
2053             }
2054         }
2055     } else {
2056         for (auto* plot : m_worksheet->children<CartesianPlot>() )
2057             plot->navigate(op);
2058     }
2059 }
2060 
2061 Worksheet::CartesianPlotActionMode WorksheetView::getCartesianPlotActionMode() {
2062     return m_worksheet->cartesianPlotActionMode();
2063 }
2064 
2065 void WorksheetView::presenterMode() {
2066     KConfigGroup group = KSharedConfig::openConfig()->group("Settings_Worksheet");
2067 
2068     //show dynamic presenter widget, if enabled
2069     if (group.readEntry("PresenterModeInteractive", false)) {
2070         auto* dynamicPresenterWidget = new DynamicPresenterWidget(m_worksheet);
2071         dynamicPresenterWidget->showFullScreen();
2072         return;
2073     }
2074 
2075     //show static presenter widget (default)
2076     QRectF sourceRect(scene()->sceneRect());
2077 
2078     int w = Worksheet::convertFromSceneUnits(sourceRect.width(), Worksheet::Unit::Millimeter);
2079     int h = Worksheet::convertFromSceneUnits(sourceRect.height(), Worksheet::Unit::Millimeter);
2080     w *= QApplication::desktop()->physicalDpiX()/25.4;
2081     h *= QApplication::desktop()->physicalDpiY()/25.4;
2082 
2083     QRectF targetRect(0, 0, w, h);
2084     const QRectF& screenSize = QGuiApplication::primaryScreen()->availableGeometry();;
2085 
2086     if (targetRect.width() > screenSize.width() || ((targetRect.height() > screenSize.height()))) {
2087         const double ratio = qMin(screenSize.width() / targetRect.width(), screenSize.height() / targetRect.height());
2088         targetRect.setWidth(targetRect.width()* ratio);
2089         targetRect.setHeight(targetRect.height() * ratio);
2090     }
2091 
2092     QImage image(QSize(targetRect.width(), targetRect.height()), QImage::Format_ARGB32_Premultiplied);
2093     image.fill(Qt::transparent);
2094     QPainter painter;
2095     painter.begin(&image);
2096     painter.setRenderHint(QPainter::Antialiasing);
2097     exportPaint(&painter, targetRect, sourceRect, true);
2098     painter.end();
2099 
2100     auto* presenterWidget = new PresenterWidget(QPixmap::fromImage(image), m_worksheet->name());
2101     presenterWidget->showFullScreen();
2102 }