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 }