File indexing completed on 2024-12-22 04:17:41

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  ***************************************************************************/
0012 
0013 #include "plotitem.h"
0014 #include "colorsequence.h"
0015 
0016 #include "plotitemmanager.h"
0017 #include "plotrenderitem.h"
0018 
0019 #include "image.h"
0020 
0021 #include "layoutboxitem.h"
0022 #include "viewgridlayout.h"
0023 #include "debug.h"
0024 
0025 #include "application.h"
0026 #include "mainwindow.h"
0027 #include "document.h"
0028 #include "tabwidget.h"
0029 #include "labelrenderer.h"
0030 
0031 #include "datacollection.h"
0032 #include "cartesianrenderitem.h"
0033 
0034 #include "plotitemdialog.h"
0035 #include "dialoglauncher.h"
0036 #include "sharedaxisboxitem.h"
0037 
0038 #include "applicationsettings.h"
0039 #include "updatemanager.h"
0040 #include "plotscriptinterface.h"
0041 #include "math_kst.h"
0042 
0043 #include "dialogdefaults.h"
0044 
0045 #include <QMenu>
0046 #include <QDebug>
0047 #include <QGraphicsSceneMouseEvent>
0048 #include <QClipboard>
0049 
0050 // Benchmark drawing
0051 // undefined = None, 1 = PlotItem, 2 = More Details
0052 //#define BENCHMARK 1
0053 
0054 static const int PLOT_MAXIMIZED_ZORDER = 1000;
0055 
0056 namespace Kst {
0057 
0058 PlotItem::PlotItem(View *parent)
0059   : ViewItem(parent), PlotItemInterface(),
0060   _isInSharedAxisBox(false),
0061   _manuallyHideLeftAxisLabel(false),
0062   _manuallyHideRightAxisLabel(false),
0063   _manuallyHideTopAxisLabel(false),
0064   _manuallyHideBottomAxisLabel(false),
0065   _plotRectsDirty(true),
0066   _calculatedLeftLabelMargin(0.0),
0067   _calculatedLeftLabelWidth(0.0),
0068   _calculatedLeftBaseOffset(0.0),
0069   _calculatedRightLabelMargin(0.0),
0070   _calculatedTopLabelMargin(0.0),
0071   _calculatedTopLabelHeight(0.0),
0072   _calculatedBottomLabelMargin(0.0),
0073   _calculatedBottomLabelWidth(0.0),
0074   _calculatedLabelMarginWidth(0.0),
0075   _calculatedLabelMarginHeight(0.0),
0076   _calculatedAxisMarginWidth(0.0),
0077   _calculatedAxisMarginHeight(0.0),
0078   _calculatedAxisMarginVLead(0.0),
0079   _calculatedAxisMarginHLead(0.0),
0080   _calculatedAxisMarginROverflow(0.0),
0081   _calculatedAxisMarginTOverflow(0.0),
0082   _leftPadding(0.0),
0083   _bottomPadding(0.0),
0084   _rightPadding(0.0),
0085   _topPadding(0.0),
0086   _globalFontScale(14.0),
0087   _numberAxisLabelScaleFactor(1.0),
0088   _useNumberAxisLabelScale(true),
0089   _showLegend(false),
0090   _allowUpdates(true),
0091   _legend(0),
0092   _zoomMenu(0),
0093   _filterMenu(0),
0094   _fitMenu(0),
0095   _psdMenu(0),
0096   _histogramMenu(0),
0097   _editMenu(0),
0098   _sharedAxisBoxMenu(0),
0099   _copyMenu(0),
0100   _sharedBox(0),
0101   _axisLabelsDirty(true),
0102 
0103   _plotPixmapDirty(true),
0104   _i_per(0)
0105 {
0106   setTypeName(tr("Plot", "a plot of data"));
0107   _initializeShortName();
0108 
0109   setBrush(Qt::white);
0110 
0111   setSupportsTiedZoom(true);
0112 
0113   _xAxis = new PlotAxis(this, Qt::Horizontal);
0114   _yAxis = new PlotAxis(this, Qt::Vertical);
0115 
0116   connect(this, SIGNAL(geometryChanged()), _xAxis, SLOT(setTicksUpdated()));
0117   connect(this, SIGNAL(geometryChanged()), _yAxis, SLOT(setTicksUpdated()));
0118   connect(this, SIGNAL(geometryChanged()), this, SLOT(setPlotRectsDirty()));
0119 
0120   _leftLabelDetails = new PlotLabel(this);
0121   _rightLabelDetails = new PlotLabel(this);
0122   _topLabelDetails = new PlotLabel(this);
0123   _bottomLabelDetails = new PlotLabel(this);
0124   _numberLabelDetails = new PlotLabel(this);
0125 
0126   //view()->configurePlotFontDefaults(this);
0127 
0128   connect(_leftLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
0129   connect(_leftLabelDetails, SIGNAL(labelChanged()), this, SLOT(setLeftLabelDirty()));
0130   connect(_rightLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
0131   connect(_rightLabelDetails, SIGNAL(labelChanged()), this, SLOT(setRightLabelDirty()));
0132   connect(_topLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
0133   connect(_topLabelDetails, SIGNAL(labelChanged()), this, SLOT(setTopLabelDirty()));
0134   connect(_bottomLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
0135   connect(_bottomLabelDetails, SIGNAL(labelChanged()), this, SLOT(setBottomLabelDirty()));
0136   connect(_numberLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
0137   connect(_numberLabelDetails, SIGNAL(labelChanged()), this, SLOT(setAxisLabelsDirty()));
0138 
0139   _undoStack = new QUndoStack(this);
0140 
0141   createActions();
0142 
0143   // Set the initial projection.
0144   setProjectionRect(QRectF(QPointF(-0.1, -0.1), QPointF(0.1, 0.1)));
0145   renderItem(PlotRenderItem::Cartesian);
0146 
0147   setPlotBordersDirty(true);
0148   connect(this, SIGNAL(triggerRedraw()), this, SLOT(redrawPlot()));
0149   connect(this, SIGNAL(geometryChanged()), this, SLOT(setLabelsDirty()));
0150   connect(this, SIGNAL(updateAxes()), this, SLOT(setPlotPixmapDirty()));
0151   connect(this, SIGNAL(geometryChanged()), this, SLOT(setPlotPixmapDirty()));
0152 
0153   applyDefaults();
0154   applyDialogDefaultsStroke();
0155   applyDialogDefaultsFill();
0156   applyDialogDefaultsLockPosToData();
0157 }
0158 
0159 ScriptInterface* PlotItem::createScriptInterface() {
0160   return new PlotSI(this);
0161 }
0162 
0163 
0164 QColor PlotItem::nextColor() {
0165     ColorSequence::self().setIndex(curveList().count());
0166     return ColorSequence::self().current();
0167 }
0168 
0169 
0170 void PlotItem::applyDefaults() {
0171   QFont font;
0172 
0173   // Global Font Settings
0174   QFont globalfont;
0175   globalfont.fromString(dialogDefaults().value(defaultsGroupName()+"/globalFontFamily",globalfont.toString()).toString());
0176   setGlobalFont(globalfont);
0177   setGlobalFontScale(dialogDefaults().value(defaultsGroupName()+"/globalFontScale", 13).toDouble());
0178   QColor color;
0179   color = dialogDefaults().value(defaultsGroupName()+"/globalFontColor", QColor(Qt::black)).value<QColor>();
0180   setGlobalFontColor(color);
0181 
0182   // Left Font Settings
0183   leftLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/leftFontGlobal", true).toBool());
0184   font.fromString(dialogDefaults().value(defaultsGroupName()+"/leftFontFamily",globalfont.toString()).toString());
0185   leftLabelDetails()->setFont(font);
0186   leftLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/leftFontScale", 13).toDouble());
0187   color = dialogDefaults().value(defaultsGroupName()+"/leftFontColor", QColor(Qt::black)).value<QColor>();
0188   leftLabelDetails()->setFontColor(color);
0189 
0190   // right Font Settings
0191   rightLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/rightFontGlobal", true).toBool());
0192   font.fromString(dialogDefaults().value(defaultsGroupName()+"/rightFontFamily",globalfont.toString()).toString());
0193   rightLabelDetails()->setFont(font);
0194   rightLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/rightFontScale", 13).toDouble());
0195   color = dialogDefaults().value(defaultsGroupName()+"/rightFontColor", QColor(Qt::black)).value<QColor>();
0196   rightLabelDetails()->setFontColor(color);
0197 
0198   // top Font Settings
0199   topLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/topFontGlobal", true).toBool());
0200   font.fromString(dialogDefaults().value(defaultsGroupName()+"/topFontFamily",globalfont.toString()).toString());
0201   topLabelDetails()->setFont(font);
0202   topLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/topFontScale", 13).toDouble());
0203   color = dialogDefaults().value(defaultsGroupName()+"/topFontColor", QColor(Qt::black)).value<QColor>();
0204   topLabelDetails()->setFontColor(color);
0205 
0206   // bottom Font Settings
0207   bottomLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/bottomFontGlobal", true).toBool());
0208   font.fromString(dialogDefaults().value(defaultsGroupName()+"/bottomFontFamily",globalfont.toString()).toString());
0209   bottomLabelDetails()->setFont(font);
0210   bottomLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/bottomFontScale", 13).toDouble());
0211   color = dialogDefaults().value(defaultsGroupName()+"/bottomFontColor", QColor(Qt::black)).value<QColor>();
0212   bottomLabelDetails()->setFontColor(color);
0213 
0214   // number Font Settings
0215   numberLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/numberFontGlobal", true).toBool());
0216   font.fromString(dialogDefaults().value(defaultsGroupName()+"/numberFontFamily",globalfont.toString()).toString());
0217   numberLabelDetails()->setFont(font);
0218   numberLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/numberFontScale", 13).toDouble());
0219   color = dialogDefaults().value(defaultsGroupName()+"/numberFontColor", QColor(Qt::black)).value<QColor>();
0220   numberLabelDetails()->setFontColor(color);
0221 
0222   xAxis()->setAxisVisible(dialogDefaults().value(defaultsGroupName()+"/xAxisVisible", true).toBool());
0223   xAxis()->setAxisLog(dialogDefaults().value(defaultsGroupName()+"/xAxisLog", false).toBool());
0224   xAxis()->setAxisReversed(dialogDefaults().value(defaultsGroupName()+"/xAxisReversed", false).toBool());
0225   xAxis()->setAxisAutoBaseOffset(dialogDefaults().value(defaultsGroupName()+"/xAxisAutoBaseOffset", true).toBool());
0226   xAxis()->setAxisBaseOffset(dialogDefaults().value(defaultsGroupName()+"/xAxisBaseOffset", false).toBool());
0227   xAxis()->setAxisForceOffsetMin(dialogDefaults().value(defaultsGroupName()+"/xAxisForceOffsetMin", false).toBool());
0228   xAxis()->setAxisInterpret(dialogDefaults().value(defaultsGroupName()+"/xAxisInterpret", false).toBool());
0229   xAxis()->setAxisInterpretation((AxisInterpretationType)dialogDefaults().value(defaultsGroupName()+"/xAxisInterpretation", 1).toInt());
0230   xAxis()->setAxisDisplay((AxisDisplayType)dialogDefaults().value(defaultsGroupName()+"/xAxisDisplay", 4).toInt());
0231   xAxis()->setTimezoneName(dialogDefaults().value(defaultsGroupName()+"/xAxisTimezone", "GMT").toString());
0232   xAxis()->setAxisMajorTickMode((MajorTickMode)dialogDefaults().value(defaultsGroupName()+"/xAxisMajorTickMode", 5).toInt());
0233   xAxis()->setAxisMinorTickCount(dialogDefaults().value(defaultsGroupName()+"/xAxisMinorTickCount", 5).toInt());
0234   xAxis()->setAxisAutoMinorTicks(dialogDefaults().value(defaultsGroupName()+"/xAxisautoMinorTickCount", true).toBool());
0235   xAxis()->setDrawAxisMajorTicks(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorTicks", true).toBool());
0236   xAxis()->setDrawAxisMinorTicks(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorTicks", true).toBool());
0237   xAxis()->setDrawAxisMajorGridLines(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLines", true).toBool());
0238   xAxis()->setDrawAxisMinorGridLines(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLines", false).toBool());
0239 
0240   xAxis()->setAxisMajorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLineStyle", 2).toInt());
0241   xAxis()->setAxisMajorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLineWidth",1).toDouble());
0242   color = dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLineColor", "#a0a0a4").value<QColor>();
0243   xAxis()->setAxisMajorGridLineColor(color);
0244 
0245   xAxis()->setAxisMinorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLineStyle", 2).toInt());
0246   xAxis()->setAxisMinorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLineWidth",1).toDouble());
0247   color = dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLineColor", "#a0a0a4").value<QColor>();
0248   xAxis()->setAxisMinorGridLineColor(color);
0249 
0250   xAxis()->setAxisSignificantDigits(dialogDefaults().value(defaultsGroupName()+"/xAxisSignificantDigits",9).toInt());
0251   xAxis()->setAxisLabelRotation(dialogDefaults().value(defaultsGroupName()+"/xAxisRotation",0).toDouble());
0252 
0253 
0254   yAxis()->setAxisVisible(dialogDefaults().value(defaultsGroupName()+"/yAxisVisible", true).toBool());
0255   yAxis()->setAxisLog(dialogDefaults().value(defaultsGroupName()+"/yAxisLog", false).toBool());
0256   yAxis()->setAxisReversed(dialogDefaults().value(defaultsGroupName()+"/yAxisReversed", false).toBool());
0257   yAxis()->setAxisAutoBaseOffset(dialogDefaults().value(defaultsGroupName()+"/yAxisAutoBaseOffset", true).toBool());
0258   yAxis()->setAxisBaseOffset(dialogDefaults().value(defaultsGroupName()+"/yAxisBaseOffset", false).toBool());
0259   yAxis()->setAxisForceOffsetMin(dialogDefaults().value(defaultsGroupName()+"/yAxisForceOffsetMin", false).toBool());
0260   yAxis()->setAxisInterpret(dialogDefaults().value(defaultsGroupName()+"/yAxisInterpret", false).toBool());
0261   yAxis()->setAxisInterpretation((AxisInterpretationType)dialogDefaults().value(defaultsGroupName()+"/yAxisInterpretation", 1).toInt());
0262   yAxis()->setAxisDisplay((AxisDisplayType)dialogDefaults().value(defaultsGroupName()+"/yAxisDisplay", 4).toInt());
0263   yAxis()->setTimezoneName(dialogDefaults().value(defaultsGroupName()+"/yAxisTimezone", "GMT").toString());
0264   yAxis()->setAxisMajorTickMode((MajorTickMode)dialogDefaults().value(defaultsGroupName()+"/yAxisMajorTickMode", 5).toInt());
0265   yAxis()->setAxisMinorTickCount(dialogDefaults().value(defaultsGroupName()+"/yAxisMinorTickCount", 5).toInt());
0266   yAxis()->setAxisAutoMinorTicks(dialogDefaults().value(defaultsGroupName()+"/yAxisautoMinorTickCount", true).toBool());
0267   yAxis()->setDrawAxisMajorTicks(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorTicks", true).toBool());
0268   yAxis()->setDrawAxisMinorTicks(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorTicks", true).toBool());
0269   yAxis()->setDrawAxisMajorGridLines(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLines", true).toBool());
0270   yAxis()->setDrawAxisMinorGridLines(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLines", false).toBool());
0271 
0272   yAxis()->setAxisMajorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLineStyle", 2).toInt());
0273   yAxis()->setAxisMajorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLineWidth",1).toDouble());
0274   color = dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLineColor", "#a0a0a4").value<QColor>();
0275   yAxis()->setAxisMajorGridLineColor(color);
0276 
0277   yAxis()->setAxisMinorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLineStyle", 2).toInt());
0278   yAxis()->setAxisMinorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLineWidth",1).toDouble());
0279   color = dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLineColor", "#a0a0a4").value<QColor>();
0280   yAxis()->setAxisMinorGridLineColor(color);
0281 
0282   yAxis()->setAxisSignificantDigits(dialogDefaults().value(defaultsGroupName()+"/yAxisSignificantDigits",9).toInt());
0283   yAxis()->setAxisLabelRotation(dialogDefaults().value(defaultsGroupName()+"/yAxisRotation",0).toDouble());
0284 
0285 }
0286 
0287 
0288 PlotItem::~PlotItem() {
0289   delete _xAxis;
0290   delete _yAxis;
0291   delete _leftLabelDetails;
0292   delete _rightLabelDetails;
0293   delete _topLabelDetails;
0294   delete _bottomLabelDetails;
0295   delete _numberLabelDetails;
0296   delete _zoomMenu;
0297   delete _filterMenu;
0298   delete _fitMenu;
0299   delete _editMenu;
0300 
0301   if (_sharedAxisBoxMenu) {
0302     delete _sharedAxisBoxMenu;
0303   }
0304   if (_copyMenu) {
0305     delete _copyMenu;
0306   }
0307 
0308 }
0309 
0310 void PlotItem::_initializeShortName() {
0311   _shortName = 'P'+QString::number(_plotnum);
0312   if (_plotnum>max_plotnum) {
0313     max_plotnum = _plotnum;
0314   }
0315   _plotnum++;
0316 }
0317 
0318 QString PlotItem::plotName() const {
0319   return Name();
0320 }
0321 
0322 QString PlotItem::plotCleanedName() const {
0323   return CleanedName();
0324 }
0325 
0326 void PlotItem::save(QXmlStreamWriter &xml) {
0327   if (isVisible()) {
0328     bool plot_maximized = _plotMaximized;
0329     // We don't save 'plot maximized' mode - so un-do it before saving
0330     if (plot_maximized) {
0331       plotMaximize();
0332     }
0333     xml.writeStartElement("plot");
0334     xml.writeAttribute("tiedxzoom", QVariant(isXTiedZoom()).toString());
0335     xml.writeAttribute("tiedyzoom", QVariant(isYTiedZoom()).toString());
0336     xml.writeAttribute("leftlabelvisible", QVariant(_leftLabelDetails->isVisible()).toString());
0337     xml.writeAttribute("bottomlabelvisible", QVariant(_bottomLabelDetails->isVisible()).toString());
0338     xml.writeAttribute("rightlabelvisible", QVariant(_rightLabelDetails->isVisible()).toString());
0339     xml.writeAttribute("toplabelvisible", QVariant(_topLabelDetails->isVisible()).toString());
0340     xml.writeAttribute("globalfont", QVariant(_globalFont).toString());
0341     xml.writeAttribute("globalfontscale", QVariant(_globalFontScale).toString());
0342     xml.writeAttribute("globalfontcolor", QVariant(_globalFontColor).toString());
0343     xml.writeAttribute("showlegend", QVariant(_showLegend).toString());
0344     xml.writeAttribute("hidebottomaxislabel", QVariant(_manuallyHideBottomAxisLabel).toString());
0345     xml.writeAttribute("hidetopaxislabel", QVariant(_manuallyHideTopAxisLabel).toString());
0346     xml.writeAttribute("hideleftaxislabel", QVariant(_manuallyHideLeftAxisLabel).toString());
0347     xml.writeAttribute("hiderightaxislabel", QVariant(_manuallyHideRightAxisLabel).toString());
0348     xml.writeAttribute("numberaxislabelscale", QVariant(_useNumberAxisLabelScale).toString());
0349     saveNameInfo(xml, PLOTNUM);
0350 
0351     ViewItem::save(xml);
0352     legend()->saveInPlot(xml);
0353 
0354     foreach (PlotRenderItem *renderer, renderItems()) {
0355       renderer->saveInPlot(xml);
0356     }
0357     _xAxis->saveInPlot(xml, QString("xaxis"));
0358     _yAxis->saveInPlot(xml, QString("yaxis"));
0359     _leftLabelDetails->saveInPlot(xml, QString("leftlabel"));
0360     _rightLabelDetails->saveInPlot(xml, QString("rightlabel"));
0361     _topLabelDetails->saveInPlot(xml, QString("toplabel"));
0362     _bottomLabelDetails->saveInPlot(xml, QString("bottomlabel"));
0363     _numberLabelDetails->saveInPlot(xml, QString("numberlabel"));
0364 
0365     xml.writeStartElement("projectionrect");
0366     xml.writeAttribute("x", QVariant(projectionRect().x()).toString());
0367     xml.writeAttribute("y", QVariant(projectionRect().y()).toString());
0368     xml.writeAttribute("width", QVariant(projectionRect().width()).toString());
0369     xml.writeAttribute("height", QVariant(projectionRect().height()).toString());
0370     xml.writeEndElement();
0371     xml.writeEndElement();
0372     if (plot_maximized) {
0373       plotMaximize(); // re-maximize it if we just un-maximized it.
0374     }
0375   }
0376 }
0377 
0378 
0379 void PlotItem::edit(PlotClickEditRegion region) {
0380   PlotItemDialog *editDialog = new PlotItemDialog(this, kstApp->mainWindow());
0381   if (region == LABEL) {
0382     editDialog->selectLabelsPage();
0383   } else if (region == XAXIS) {
0384     editDialog->selectXAxisPage();
0385   } else if (region == YAXIS) {
0386     editDialog->selectYAxisPage();
0387   }
0388   editDialog->show();
0389 }
0390 
0391 
0392 void PlotItem::createActions() {
0393 
0394   _createCurve = new QAction(tr("Create Curve"), this);
0395   connect(_createCurve, SIGNAL(triggered()), this, SLOT(showCurveDialog()));
0396 
0397   _zoomMaximum = new QAction(tr("Zoom Maximum"), this);
0398   _zoomMaximum->setShortcut(Qt::Key_M);
0399   registerShortcut(_zoomMaximum);
0400   connect(_zoomMaximum, SIGNAL(triggered()), this, SLOT(zoomMaximum()));
0401 
0402   _zoomMaxSpikeInsensitive = new QAction(tr("Zoom Max Spike Insensitive"), this);
0403   _zoomMaxSpikeInsensitive->setShortcut(Qt::Key_S);
0404   registerShortcut(_zoomMaxSpikeInsensitive);
0405   connect(_zoomMaxSpikeInsensitive, SIGNAL(triggered()), this, SLOT(zoomMaxSpikeInsensitive()));
0406 
0407   _zoomPrevious = _undoStack->createUndoAction(this, tr("Zoom Previous"));
0408   _zoomPrevious->setShortcut(Qt::Key_R);
0409   registerShortcut(_zoomPrevious);
0410 
0411   _zoomTied = new QAction(tr("Zoom Tied"), this);
0412   _zoomTied->setShortcut(Qt::Key_T);
0413   _zoomTied->setCheckable(true);
0414   registerShortcut(_zoomTied);
0415   connect(_zoomTied, SIGNAL(triggered()), this, SLOT(zoomTied()));
0416 
0417   _zoomOut = new QAction(tr("Zoom Out"), this);
0418   _zoomOut->setShortcut(Qt::Key_Minus);
0419   registerShortcut(_zoomOut);
0420   connect(_zoomOut, SIGNAL(triggered()), this, SLOT(zoomOut()));
0421 
0422   _zoomIn = new QAction(tr("Zoom In"), this);
0423   _zoomIn->setShortcut(Qt::Key_Plus);
0424   registerShortcut(_zoomIn);
0425   connect(_zoomIn, SIGNAL(triggered()), this, SLOT(zoomIn()));
0426 
0427   _zoomXTied = new QAction(tr("Zoom X Tied"), this);
0428   _zoomXTied->setShortcut(Qt::CTRL+Qt::Key_T);
0429   _zoomXTied->setCheckable(true);
0430   registerShortcut(_zoomXTied);
0431   connect(_zoomXTied, SIGNAL(triggered()), this, SLOT(zoomXTied()));
0432 
0433   _zoomYTied = new QAction(tr("Zoom Y Tied"), this);
0434   _zoomYTied->setShortcut(Qt::SHIFT+Qt::Key_T);
0435   _zoomYTied->setCheckable(true);
0436   registerShortcut(_zoomYTied);
0437   connect(_zoomYTied, SIGNAL(triggered()), this, SLOT(zoomYTied()));
0438 
0439   _zoomMeanCentered = new QAction(tr("Zoom Mean-centered Y"), this);
0440   _zoomMeanCentered->setShortcut(Qt::Key_A);
0441   registerShortcut(_zoomMeanCentered);
0442   connect(_zoomMeanCentered, SIGNAL(triggered()), this, SLOT(zoomMeanCentered()));
0443 
0444   _zoomXMaximum = new QAction(tr("X-Zoom Maximum"), this);
0445   _zoomXMaximum->setShortcut(Qt::CTRL+Qt::Key_M);
0446   registerShortcut(_zoomXMaximum);
0447   connect(_zoomXMaximum, SIGNAL(triggered()), this, SLOT(zoomXMaximum()));
0448 
0449   _zoomXAutoBorder = new QAction(tr("X-Zoom Auto Border"), this);
0450   _zoomXAutoBorder->setShortcut(Qt::CTRL+Qt::Key_B);
0451   registerShortcut(_zoomXAutoBorder);
0452   connect(_zoomXAutoBorder, SIGNAL(triggered()), this, SLOT(zoomXAutoBorder()));
0453 
0454   _zoomXNoSpike = new QAction(tr("X-Zoom Spike Insensitive"), this);
0455   //_zoomXNoSpike->setShortcut(Qt::CTRL+Qt::Key_S);
0456   registerShortcut(_zoomXNoSpike);
0457   connect(_zoomXNoSpike, SIGNAL(triggered()), this, SLOT(zoomXNoSpike()));
0458 
0459   _zoomXRight = new QAction(tr("X-Zoom Right"), this);
0460   _zoomXRight->setShortcut(Qt::Key_Right);
0461   registerShortcut(_zoomXRight);
0462   connect(_zoomXRight, SIGNAL(triggered()), this, SLOT(zoomXRight()));
0463 
0464   _zoomXFarRight = new QAction(tr("X-Zoom Right by one screen"), this);
0465   _zoomXFarRight->setShortcut(Qt::CTRL+Qt::Key_Right);
0466   registerShortcut(_zoomXFarRight);
0467   connect(_zoomXFarRight, SIGNAL(triggered()), this, SLOT(zoomXFarRight()));
0468 
0469   _zoomXLeft= new QAction(tr("X-Zoom Left"), this);
0470   _zoomXLeft->setShortcut(Qt::Key_Left);
0471   registerShortcut(_zoomXLeft);
0472   connect(_zoomXLeft, SIGNAL(triggered()), this, SLOT(zoomXLeft()));
0473 
0474   _zoomXFarLeft= new QAction(tr("X-Zoom Left by one screen"), this);
0475   _zoomXFarLeft->setShortcut(Qt::CTRL+Qt::Key_Left);
0476   registerShortcut(_zoomXFarLeft);
0477   connect(_zoomXFarLeft, SIGNAL(triggered()), this, SLOT(zoomXFarLeft()));
0478 
0479   _zoomXOut = new QAction(tr("X-Zoom Out"), this);
0480   _zoomXOut->setShortcut(Qt::SHIFT+Qt::Key_Right);
0481   registerShortcut(_zoomXOut);
0482   connect(_zoomXOut, SIGNAL(triggered()), this, SLOT(zoomXOut()));
0483 
0484   _zoomXIn = new QAction(tr("X-Zoom In"), this);
0485   _zoomXIn->setShortcut(Qt::SHIFT+Qt::Key_Left);
0486   registerShortcut(_zoomXIn);
0487   connect(_zoomXIn, SIGNAL(triggered()), this, SLOT(zoomXIn()));
0488 
0489   _zoomNormalizeXtoY = new QAction(tr("Normalize X-axis to Y-axis"), this);
0490   _zoomNormalizeXtoY->setShortcut(Qt::Key_N);
0491   registerShortcut(_zoomNormalizeXtoY);
0492   connect(_zoomNormalizeXtoY, SIGNAL(triggered()), this, SLOT(zoomNormalizeXtoY()));
0493 
0494   _zoomLogX = new QAction(tr("Log X-axis"), this);
0495   _zoomLogX->setShortcut(Qt::Key_G);
0496   _zoomLogX->setCheckable(true);
0497   registerShortcut(_zoomLogX);
0498   connect(_zoomLogX, SIGNAL(triggered()), this, SLOT(zoomLogX()));
0499 
0500   _zoomYLocalMaximum = new QAction(tr("Y-Zoom Local Maximum"), this);
0501   _zoomYLocalMaximum->setShortcut(Qt::SHIFT+Qt::Key_L);
0502   registerShortcut(_zoomYLocalMaximum);
0503   connect(_zoomYLocalMaximum, SIGNAL(triggered()), this, SLOT(zoomYLocalMaximum()));
0504 
0505   _zoomYMaximum = new QAction(tr("Y-Zoom Maximum"), this);
0506   _zoomYMaximum->setShortcut(Qt::SHIFT+Qt::Key_M);
0507   registerShortcut(_zoomYMaximum);
0508   connect(_zoomYMaximum, SIGNAL(triggered()), this, SLOT(zoomYMaximum()));
0509 
0510   _zoomYAutoBorder = new QAction(tr("Y-Zoom Auto Border"), this);
0511   _zoomYAutoBorder->setShortcut(Qt::SHIFT+Qt::Key_B);
0512   registerShortcut(_zoomYAutoBorder);
0513   connect(_zoomYAutoBorder, SIGNAL(triggered()), this, SLOT(zoomYAutoBorder()));
0514 
0515   _zoomYNoSpike = new QAction(tr("Y-Zoom Spike Insensitive"), this);
0516   _zoomYNoSpike->setShortcut(Qt::SHIFT+Qt::Key_S);
0517   registerShortcut(_zoomYNoSpike);
0518   connect(_zoomYNoSpike, SIGNAL(triggered()), this, SLOT(zoomYNoSpike()));
0519 
0520   _zoomYUp= new QAction(tr("Y-Zoom Up"), this);
0521   _zoomYUp->setShortcut(Qt::Key_Up);
0522   registerShortcut(_zoomYUp);
0523   connect(_zoomYUp, SIGNAL(triggered()), this, SLOT(zoomYUp()));
0524 
0525   _zoomYDown= new QAction(tr("Y-Zoom Down"), this);
0526   _zoomYDown->setShortcut(Qt::Key_Down);
0527   registerShortcut(_zoomYDown);
0528   connect(_zoomYDown, SIGNAL(triggered()), this, SLOT(zoomYDown()));
0529 
0530   _zoomYOut = new QAction(tr("Y-Zoom Out"), this);
0531   _zoomYOut->setShortcut(Qt::SHIFT+Qt::Key_Up);
0532   registerShortcut(_zoomYOut);
0533   connect(_zoomYOut, SIGNAL(triggered()), this, SLOT(zoomYOut()));
0534 
0535   _zoomYIn = new QAction(tr("Y-Zoom In"), this);
0536   _zoomYIn->setShortcut(Qt::SHIFT+Qt::Key_Down);
0537   registerShortcut(_zoomYIn);
0538   connect(_zoomYIn, SIGNAL(triggered()), this, SLOT(zoomYIn()));
0539 
0540   _zoomNormalizeYtoX = new QAction(tr("Normalize Y-axis to X-axis"), this);
0541   _zoomNormalizeYtoX->setShortcut(Qt::SHIFT+Qt::Key_N);
0542   registerShortcut(_zoomNormalizeYtoX);
0543   connect(_zoomNormalizeYtoX, SIGNAL(triggered()), this, SLOT(zoomNormalizeYtoX()));
0544 
0545   _zoomLogY = new QAction(tr("Log Y Axis"), this);
0546   _zoomLogY->setShortcut(Qt::Key_L);
0547   _zoomLogY->setCheckable(true);
0548   registerShortcut(_zoomLogY);
0549   connect(_zoomLogY, SIGNAL(triggered()), this, SLOT(zoomLogY()));
0550 
0551   _adjustImageColorscale = new QAction(tr("Adjust Image Color Scale"), this);
0552   _adjustImageColorscale->setShortcut(Qt::Key_I);
0553   registerShortcut(_adjustImageColorscale);
0554   connect(_adjustImageColorscale, SIGNAL(triggered()), this, SLOT(adjustImageColorScale()));
0555 
0556   createZoomMenu();
0557 
0558   _plotMaximize = new QAction(tr("Maximize Plot"), this);
0559   _plotMaximize->setShortcut(Qt::Key_Z);
0560   _plotMaximize->setCheckable(true);
0561   registerShortcut(_plotMaximize);
0562   connect(_plotMaximize, SIGNAL(triggered()), this, SLOT(plotMaximize()));
0563 
0564   
0565   _shareBoxShareX = new QAction(tr("Share Plots on X-Axis"), this);
0566   _shareBoxShareX->setCheckable(true);
0567   registerShortcut(_shareBoxShareX);
0568   connect(_shareBoxShareX, SIGNAL(triggered()), this, SIGNAL(shareXAxisTriggered()));
0569 
0570   _shareBoxShareY = new QAction(tr("Share Plots on Y-Axis"), this);
0571   _shareBoxShareY->setCheckable(true);
0572   registerShortcut(_shareBoxShareY);
0573   connect(_shareBoxShareY, SIGNAL(triggered()), this, SIGNAL(shareYAxisTriggered()));
0574 
0575   _breakSharedBox = new QAction(tr("Break Shared Axis Box"), this);
0576   registerShortcut(_breakSharedBox);
0577   connect(_breakSharedBox, SIGNAL(triggered()), this, SIGNAL(breakShareTriggered()));
0578 
0579   _copyStatus = new QAction(tr("Copy Coordinates"), this);
0580   _copyStatus->setShortcut(Qt::CTRL + Qt::Key_C);
0581   registerShortcut(_copyStatus);
0582   connect(_copyStatus, SIGNAL(triggered()), this, SLOT(copyStatus()));
0583 
0584   _copyXCoord = new QAction(tr("Copy X Coordinate"), this);
0585   _copyXCoord->setShortcut(Qt::Key_X);
0586   registerShortcut(_copyXCoord);
0587   connect(_copyXCoord, SIGNAL(triggered()), this, SLOT(copyXCoord()));
0588 
0589   _copyYCoord = new QAction(tr("Copy Y Coordinate"), this);
0590   _copyYCoord->setShortcut(Qt::Key_Y);
0591   registerShortcut(_copyYCoord);
0592   connect(_copyYCoord, SIGNAL(triggered()), this, SLOT(copyYCoord()));
0593 
0594   createCopyMenu();
0595 
0596   referenceMode = new QAction(tr("Place Reference Marker"), this);
0597   referenceMode->setShortcut(Qt::Key_C);
0598   registerShortcut(referenceMode);
0599 
0600   referenceModeDisabled = new QAction(tr("Remove Reference Marker"), this);
0601   referenceModeDisabled->setShortcut(Qt::SHIFT + Qt::Key_C);
0602   registerShortcut(referenceModeDisabled);
0603 
0604 }
0605 
0606 void PlotItem::createCopyMenu() {
0607   if (_copyMenu) {
0608     delete _copyMenu;
0609   }
0610 
0611   _copyMenu = new QMenu;
0612   _copyMenu->setTitle(tr("Copy"));
0613 
0614   _copyMenu->addAction(_copyStatus);
0615   _copyMenu->addAction(_copyXCoord);
0616   _copyMenu->addAction(_copyYCoord);
0617 
0618 }
0619 
0620 void PlotItem::createZoomMenu() {
0621   if (_zoomMenu) {
0622     delete _zoomMenu;
0623   }
0624 
0625   _zoomMenu = new QMenu;
0626   _zoomMenu->setTitle(tr("Zoom"));
0627 
0628   QMenu *xyZoomMenu = _zoomMenu->addMenu(tr("XY Zoom", "menu title: zoom in both axis of a plot"));
0629   QMenu *yZoomMenu = _zoomMenu->addMenu(tr("Y Zoom", "menu title: zoom in the horizontal axis of a plot"));
0630   QMenu *xZoomMenu = _zoomMenu->addMenu(tr("X Zoom", "menu title: zoom in the vertical axis of a plot"));
0631 
0632   _zoomMenu->addAction(_zoomPrevious);
0633   _zoomMenu->addAction(_adjustImageColorscale);
0634 
0635   xyZoomMenu->addAction(_zoomMaximum);
0636   xyZoomMenu->addAction(_zoomMaxSpikeInsensitive);
0637   xyZoomMenu->addAction(_zoomMeanCentered);
0638   xyZoomMenu->addAction(_zoomTied);
0639 
0640   xZoomMenu->addAction(_zoomXTied);
0641   xZoomMenu->addAction(_zoomXMaximum);
0642   xZoomMenu->addAction(_zoomXAutoBorder);
0643   xZoomMenu->addAction(_zoomXNoSpike);
0644   xZoomMenu->addAction(_zoomXRight);
0645   xZoomMenu->addAction(_zoomXLeft);
0646   xZoomMenu->addAction(_zoomXFarRight);
0647   xZoomMenu->addAction(_zoomXFarLeft);
0648   xZoomMenu->addAction(_zoomXOut);
0649   xZoomMenu->addAction(_zoomXIn);
0650   xZoomMenu->addAction(_zoomNormalizeXtoY);
0651   xZoomMenu->addAction(_zoomLogX);
0652 
0653 
0654   yZoomMenu->addAction(_zoomYTied);
0655   yZoomMenu->addAction(_zoomYLocalMaximum);
0656   yZoomMenu->addAction(_zoomYMaximum);
0657   yZoomMenu->addAction(_zoomYAutoBorder);
0658   yZoomMenu->addAction(_zoomYNoSpike);
0659   yZoomMenu->addAction(_zoomYUp);
0660   yZoomMenu->addAction(_zoomYDown);
0661   yZoomMenu->addAction(_zoomYOut);
0662   yZoomMenu->addAction(_zoomYIn);
0663   yZoomMenu->addAction(_zoomNormalizeYtoX);
0664   yZoomMenu->addAction(_zoomLogY);
0665 }
0666 
0667 
0668 CurveList PlotItem::curveList() const {
0669   CurveList list;
0670   foreach (PlotRenderItem *renderer, renderItems()) {
0671     foreach (RelationPtr relation, renderer->relationList()) {
0672       if (CurvePtr curve = kst_cast<Curve>(relation)) {
0673         list << curve;
0674       }
0675     }
0676   }
0677   return list;
0678 }
0679 
0680 
0681 RelationList PlotItem::relationList() const {
0682   RelationList list;
0683   foreach (PlotRenderItem *renderer, renderItems()) {
0684     foreach (RelationPtr relation, renderer->relationList()) {
0685       list << relation;
0686     }
0687   }
0688 
0689   return list;
0690 }
0691 
0692 
0693 void PlotItem::createFilterMenu() {
0694   if (_filterMenu) {
0695     delete _filterMenu;
0696   }
0697 
0698   _filterMenu = new QMenu;
0699   _filterMenu->setTitle(tr("Create Filter"));
0700 
0701   CurveList curves = curveList();
0702   foreach (const CurvePtr& curve, curves) {
0703     _filterMenu->addAction(new QAction(curve->Name(), this));
0704   }
0705   connect(_filterMenu, SIGNAL(triggered(QAction*)), this, SLOT(showFilterDialog(QAction*)));
0706 }
0707 
0708 
0709 void PlotItem::createEditMenu() {
0710   if (_editMenu) {
0711     delete _editMenu;
0712   }
0713 
0714   _editMenu = new QMenu;
0715 
0716   int nc = curveList().size();
0717   int nr = relationList().size();
0718   if (nc == nr) {
0719     _editMenu->setTitle(tr("Edit Curve"));
0720   } else if (nc == 0) {
0721     _editMenu->setTitle(tr("Edit Image"));
0722   } else {
0723     _editMenu->setTitle(tr("Edit Curve/Image"));
0724   }
0725 
0726   RelationList relations = relationList();
0727   foreach (const RelationPtr& relation, relations) {
0728     _editMenu->addAction(new QAction(relation->Name(), this));
0729   }
0730   connect(_editMenu, SIGNAL(triggered(QAction*)), this, SLOT(showEditDialog(QAction*)));
0731 }
0732 
0733 
0734 void PlotItem::createFitMenu() {
0735   if (_fitMenu) {
0736     delete _fitMenu;
0737   }
0738 
0739   _fitMenu = new QMenu;
0740   _fitMenu->setTitle(tr("Create Fit"));
0741 
0742   CurveList curves = curveList();
0743   foreach (const CurvePtr& curve, curves) {
0744     _fitMenu->addAction(new QAction(curve->Name(), this));
0745   }
0746 
0747   connect(_fitMenu, SIGNAL(triggered(QAction*)), this, SLOT(showFitDialog(QAction*)));
0748 }
0749 
0750 void PlotItem::createPSDMenu() {
0751   if (_psdMenu) {
0752     delete _psdMenu;
0753   }
0754 
0755   _psdMenu = new QMenu;
0756   _psdMenu->setTitle(tr("Create Spectrum"));
0757 
0758   CurveList curves = curveList();
0759   foreach (const CurvePtr& curve, curves) {
0760     _psdMenu->addAction(new QAction(curve->Name(), this));
0761   }
0762 
0763   connect(_psdMenu, SIGNAL(triggered(QAction*)), this, SLOT(showPSDDialog(QAction*)));
0764 }
0765 
0766 
0767 void PlotItem::createHistogramMenu() {
0768   if (_histogramMenu) {
0769     delete _histogramMenu;
0770   }
0771 
0772   _histogramMenu = new QMenu;
0773   _histogramMenu->setTitle(tr("Create Histogram"));
0774 
0775   CurveList curves = curveList();
0776   foreach (const CurvePtr& curve, curves) {
0777     _histogramMenu->addAction(new QAction(curve->Name(), this));
0778   }
0779 
0780   connect(_histogramMenu, SIGNAL(triggered(QAction*)), this, SLOT(showHistogramDialog(QAction*)));
0781 }
0782 
0783 
0784 
0785 void PlotItem::createSharedAxisBoxMenu() {
0786   if (_sharedAxisBoxMenu) {
0787     delete _sharedAxisBoxMenu;
0788   }
0789   _sharedAxisBoxMenu = new QMenu;
0790   _sharedAxisBoxMenu->setTitle(tr("Shared Axis Box Settings"));
0791 
0792   _sharedAxisBoxMenu->addAction(_shareBoxShareX);
0793   _sharedAxisBoxMenu->addAction(_shareBoxShareY);
0794 }
0795 
0796 
0797 
0798 
0799 void PlotItem::addToMenuForContextEvent(QMenu &menu) {
0800 
0801   menu.addSeparator();
0802   menu.addAction(_createCurve);
0803 
0804   if (curveList().size()>0) {
0805     if (!DataObject::filterPluginList().empty()) {
0806       createFilterMenu();
0807       menu.addMenu(_filterMenu);
0808     }
0809 
0810     if (!DataObject::fitsPluginList().empty()) {
0811       createFitMenu();
0812       menu.addMenu(_fitMenu);
0813     }
0814     createPSDMenu();
0815     menu.addMenu(_psdMenu);
0816 
0817     createHistogramMenu();
0818     menu.addMenu(_histogramMenu);
0819 
0820     createEditMenu();
0821     menu.addMenu(_editMenu);
0822 
0823   } else if (relationList().size()>0) {
0824     menu.addSeparator();
0825     createEditMenu();
0826     menu.addMenu(_editMenu);
0827   }
0828 
0829   if (parentItem() && isInSharedAxisBox() && _sharedBox) {
0830     if (view()->viewMode() == View::Data) {
0831 
0832       menu.addSeparator();
0833       menu.addMenu(_sharedAxisBoxMenu);
0834 
0835       menu.addAction(_breakSharedBox);
0836 
0837       _shareBoxShareX->setChecked(_sharedBox->isXAxisShared());
0838       _shareBoxShareY->setChecked(_sharedBox->isYAxisShared());
0839     }
0840   }
0841 
0842   if (view()->viewMode() == View::Data) {
0843     _plotMaximize->setChecked(_plotMaximized);
0844     menu.addSeparator();
0845     menu.addAction(_plotMaximize);
0846     menu.addAction(referenceMode);
0847     menu.addAction(referenceModeDisabled);
0848   }
0849 
0850   _zoomLogX->setChecked(xAxis()->axisLog());
0851   _zoomLogY->setChecked(yAxis()->axisLog());
0852 
0853   _zoomTied->setChecked(isTiedZoom());
0854   _zoomXTied->setChecked(isXTiedZoom());
0855   _zoomYTied->setChecked(isYTiedZoom());
0856 
0857   _zoomPrevious->setVisible(!isInSharedAxisBox());
0858   menu.addMenu(_zoomMenu);
0859 
0860   menu.addMenu(_copyMenu);
0861 
0862 }
0863 
0864 
0865 void PlotItem::showEditDialog(QAction *action) {
0866   RelationList relations = relationList();
0867   int n = relations.size();
0868   for (int i = 0; i<n; i++) {
0869     RelationPtr relation = relations.at(i);
0870     if (relation->Name() == action->text()) {
0871       DialogLauncher::self()->showObjectDialog(relation);
0872     }
0873   }
0874 }
0875 
0876 
0877 void PlotItem::showFitFilterDialog(QAction* action, const QString& plugin) {
0878   CurveList curves = curveList();
0879   foreach (const CurvePtr& curve, curves) {
0880     if (curve->Name() == action->text()) {
0881       DialogLauncher::self()->showBasicPluginDialog(plugin, 0, curve->xVector(), curve->yVector(), this);      
0882     }
0883   }
0884 }
0885 
0886 void PlotItem::showPSDDialog(QAction* action) {
0887   CurveList curves = curveList();
0888   foreach (const CurvePtr& curve, curves) {
0889     if (curve->Name() == action->text()) {
0890       DialogLauncher::self()->showPowerSpectrumDialog(0, curve->yVector());
0891     }
0892   }
0893 }
0894 
0895 void PlotItem::showCurveDialog() {
0896   DialogLauncher::self()->showCurveDialog(0,0,this);
0897 }
0898 
0899 
0900 void PlotItem::showHistogramDialog(QAction* action) {
0901   CurveList curves = curveList();
0902   foreach (const CurvePtr& curve, curves) {
0903     if (curve->Name() == action->text()) {
0904       DialogLauncher::self()->showHistogramDialog(0, curve->yVector());
0905     }
0906   }
0907 }
0908 
0909 
0910 void PlotItem::showFilterDialog(QAction* action) {
0911   showFitFilterDialog(action, DataObject::filterPluginList().first());
0912 }
0913 
0914 void PlotItem::showFitDialog(QAction* action) {
0915   showFitFilterDialog(action, DataObject::fitsPluginList().first());
0916 }
0917 
0918 void PlotItem::redrawPlot() {
0919   update();
0920 }
0921 
0922 
0923 bool PlotItem::handleChangedInputs(qint64 serial) {
0924   if (!_allowUpdates) {
0925     return false;
0926   }
0927 
0928   // decide if the inputs have changed
0929   bool no_change = true;
0930 
0931   if (_serialOfLastChange==Forced) {
0932     no_change = false;
0933   } else {
0934     foreach (PlotRenderItem *renderer, renderItems()) {
0935       foreach (RelationPtr relation, renderer->relationList()) {
0936         if (relation->serialOfLastChange() > _serialOfLastChange) {
0937           no_change = false;
0938         }
0939       }
0940     }
0941   }
0942 
0943   if (no_change) {
0944     return false;
0945   }
0946 
0947   _serialOfLastChange = serial;
0948 
0949   if (isInSharedAxisBox()) {
0950     // Need to update the box's projectionRect.
0951     sharedAxisBox()->updateZoomForDataUpdate(serial);
0952   }
0953 
0954   QRectF compute = computedProjectionRect();
0955   QRectF newProjectionRec = projectionRect();
0956 
0957   if ((xAxis()->axisZoomMode() == PlotAxis::Auto) ||
0958         (xAxis()->axisZoomMode() == PlotAxis::MeanCentered) ||
0959         (xAxis()->axisZoomMode() == PlotAxis::AutoBorder) ||
0960         (xAxis()->axisZoomMode() == PlotAxis::SpikeInsensitive)) {
0961 
0962     newProjectionRec.setWidth(0.1);
0963     newProjectionRec.setLeft(0.0);
0964     newProjectionRec.setLeft(compute.x());
0965     newProjectionRec.setWidth(compute.width());
0966   }
0967 
0968   if ((yAxis()->axisZoomMode() == PlotAxis::AutoBorder) ||
0969       (yAxis()->axisZoomMode() == PlotAxis::Auto) ||
0970       (yAxis()->axisZoomMode() == PlotAxis::SpikeInsensitive) ||
0971       (yAxis()->axisZoomMode() == PlotAxis::MeanCentered)) {
0972     newProjectionRec.setHeight(0.1);
0973     newProjectionRec.setTop(0.0);
0974     newProjectionRec.setTop(compute.y());
0975     newProjectionRec.setHeight(compute.height());
0976   }
0977 
0978   setProjectionRect(newProjectionRec);
0979 
0980   setLabelsDirty();
0981 
0982   return true;
0983 }
0984 
0985 
0986 QList<PlotRenderItem*> PlotItem::renderItems() const {
0987   return _renderers.values();
0988 }
0989 
0990 
0991 PlotRenderItem *PlotItem::renderItem(PlotRenderItem::RenderType type) {
0992   if ((type == PlotRenderItem::First) && (_renderers.count()>0)) {
0993     return _renderers.values().at(0);
0994   }
0995   if (_renderers.contains(type))
0996     return _renderers.value(type);
0997 
0998   switch (type) {
0999   case PlotRenderItem::Cartesian: 
1000     {
1001       CartesianRenderItem *renderItem = new CartesianRenderItem(this);
1002       _renderers.insert(type, renderItem);
1003       return renderItem;
1004     }
1005   case PlotRenderItem::Polar:
1006   case PlotRenderItem::Sinusoidal:
1007   default:
1008     return 0;
1009   }
1010 }
1011 
1012 
1013 void PlotItem::calculateBorders(QPainter *painter) {
1014 
1015   calculateLeftLabelMargin(painter);
1016   calculateRightLabelMargin(painter);
1017   calculateTopLabelMargin(painter);
1018   calculateBottomLabelMargin(painter);
1019 
1020   calculateBottomTickLabelBound(painter);
1021   calculateLeftTickLabelBound(painter);
1022 
1023   calculateMargins();
1024 
1025   setPlotRectsDirty();
1026 }
1027 
1028 
1029 void PlotItem::updatePlotPixmap() {
1030 #if BENCHMARK
1031   QTime bench_time;
1032   bench_time.start();
1033 #endif
1034 
1035   _plotPixmapDirty = false;
1036   if (maskedByMaximization()) {
1037     return;
1038   }
1039 
1040 #ifdef QT5
1041   int device_pixel_ratio = view()->devicePixelRatio();
1042 #else
1043   int device_pixel_ratio = 1;
1044 #endif
1045 
1046   QPixmap pixmap(device_pixel_ratio*(rect().width()+1), device_pixel_ratio*(rect().height()+1));
1047 #ifdef QT5
1048   pixmap.setDevicePixelRatio(device_pixel_ratio);
1049 #endif
1050 
1051   pixmap.fill(Qt::transparent);
1052   QPainter pixmapPainter(&pixmap);
1053 
1054   //pixmapPainter.setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1055 
1056   pixmapPainter.save();
1057   if (rect().topLeft() != QPointF(0, 0)) {
1058     pixmapPainter.translate(-rect().topLeft());
1059   }
1060   paintPixmap(&pixmapPainter);
1061   pixmapPainter.restore();
1062   
1063   _plotPixmap = pixmap;
1064 #if BENCHMARK
1065   int i = bench_time.elapsed();
1066   qDebug() << "Total Time to update plot pixmap " << (void *)this << ": " << i << "ms";
1067 #endif
1068 }
1069 
1070 
1071 void PlotItem::paint(QPainter *painter) {
1072   if (maskedByMaximization()) {
1073     return;
1074   }
1075 
1076 #if BENCHMARK
1077   QTime bench_time;
1078   bench_time.start();
1079 #endif
1080   if (view()->isPrinting()) {
1081     paintPixmap(painter);
1082   } else {
1083     if (_plotPixmapDirty && rect().isValid()) {
1084       updatePlotPixmap();
1085     }
1086     painter->save();
1087     painter->setPen(Qt::NoPen);
1088     painter->drawRect(rect());
1089     painter->restore();
1090     painter->drawPixmap(rect().topLeft(), _plotPixmap);
1091     if (view()->viewMode() == View::Layout) {
1092       painter->save();
1093       painter->setPen(pen());
1094       painter->setBrush(Qt::NoBrush);
1095       painter->drawRect(rect());
1096       painter->restore();
1097     }
1098   }
1099 #if BENCHMARK
1100   int i = bench_time.elapsed();
1101   qDebug() << "Total Time to paint " << (void *)this << ": " << i << "ms" << endl;
1102 #endif
1103 }
1104 
1105 
1106 void PlotItem::paintPixmap(QPainter *painter) {
1107   if ((view()->plotBordersDirty() || (creationState() == ViewItem::InProgress)) && rect().isValid()) {
1108     ViewGridLayout::standardizePlotMargins(this, painter);
1109     setPlotBordersDirty(false);
1110   }
1111 
1112   painter->save();
1113   painter->setPen(Qt::NoPen);
1114   painter->drawRect(rect());
1115   painter->restore();
1116 
1117   painter->save();
1118   bool xTicksUpdated = xAxis()->ticksUpdated();
1119   bool yTicksUpdated = yAxis()->ticksUpdated();
1120   if (xTicksUpdated ||yTicksUpdated) {
1121     resetScaleAxisLabels();
1122   }
1123 
1124   painter->setFont(numberLabelDetails()->calculatedFont(*painter->device()));
1125 
1126   paintLeftLabel(painter);
1127   paintBottomLabel(painter);
1128   paintRightLabel(painter);
1129 
1130   paintPlot(painter, xTicksUpdated, yTicksUpdated);
1131 
1132   paintTickLabels(painter);
1133 
1134   paintPlotMarkers(painter);
1135 
1136   paintTopLabel(painter);
1137 
1138   painter->restore();
1139 }
1140 
1141 
1142 void PlotItem::paintPlot(QPainter *painter, bool xUpdated, bool yUpdated) {
1143   if (xUpdated) {
1144     xAxis()->validateDrawingRegion(painter);
1145     updateXAxisLines();
1146     updateXAxisLabels(painter);
1147   }
1148   if (yUpdated) {
1149     yAxis()->validateDrawingRegion(painter);
1150     updateYAxisLines();
1151     updateYAxisLabels(painter);
1152   }
1153   if (isUseAxisScale()) {
1154     QFont font(painter->font());
1155     qreal pointSize = qMax((font.pointSizeF() * _numberAxisLabelScaleFactor), ApplicationSettings::self()->minimumFontSize());
1156     
1157     font.setPointSizeF(pointSize);
1158     painter->setFont(font);
1159   }
1160 
1161   if (_axisLabelsDirty) {
1162     if (!xUpdated) {
1163       updateXAxisLabels(painter);
1164     }
1165     if (!yUpdated) {
1166       updateYAxisLabels(painter);
1167     }
1168   }
1169 #if BENCHMARK > 1
1170   QTime bench_time, benchtmp;
1171   int b_1 = 0, b_2 = 0, b_3 = 0, b_4 = 0, b_5 = 0;
1172   bench_time.start();
1173   benchtmp.start();
1174 #endif
1175   paintMajorGridLines(painter);
1176 #if BENCHMARK > 1
1177     b_1 = benchtmp.elapsed();
1178 #endif
1179   paintMinorGridLines(painter);
1180 #if BENCHMARK > 1
1181     b_2 = benchtmp.elapsed();
1182 #endif
1183   painter->save();
1184   painter->setBrush(Qt::NoBrush);
1185   painter->setPen(pen());
1186   QRectF box(plotRect());
1187   box.adjust(-1.0, -1.0, 0.0, 0.0);
1188   painter->drawRect(box);
1189 #if BENCHMARK > 1
1190     b_3 = benchtmp.elapsed();
1191 #endif
1192 
1193   paintMajorTicks(painter);
1194 #if BENCHMARK > 1
1195     b_4 = benchtmp.elapsed();
1196 #endif
1197   paintMinorTicks(painter);
1198 #if BENCHMARK > 1
1199     b_5 = benchtmp.elapsed();
1200 #endif
1201   painter->restore();
1202 
1203 #if BENCHMARK > 1
1204   int i = bench_time.elapsed();
1205   qDebug() << "Painting Plot - PaintPlot " << (void *)this << ": " << i << "ms";
1206   if (b_1 > 0)       qDebug() << "            Major Lines: " << b_1 << "ms";
1207   if (b_2 - b_1 > 0) qDebug() << "            Minor Lines: " << (b_2 - b_1) << "ms";
1208   if (b_3 - b_2 > 0) qDebug() << "                   Rect: " << (b_3 - b_2) << "ms";
1209   if (b_4 - b_3 > 0) qDebug() << "            Major Ticks: " << (b_4 - b_3) << "ms";
1210   if (b_5 - b_4 > 0) qDebug() << "            Minor Ticks: " << (b_5 - b_4) << "ms";
1211 #endif
1212 }
1213 
1214 
1215 void PlotItem::updateXAxisLines() {
1216   qreal majorTickLength = qMin(rect().width(), rect().height()) * .02; //two percent
1217   qreal minorTickLength = qMin(rect().width(), rect().height()) * 0.01; //one percent
1218   QRectF rect = plotRect();
1219 
1220   _xMajorGridLines.clear();
1221   _xMajorTickLines.clear();
1222   foreach (qreal x, _xAxis->axisMajorTicks()) {
1223     QPointF p1 = QPointF(mapXToPlot(x), rect.bottom());
1224     QPointF p2 = p1 - QPointF(0, rect.height());
1225     _xMajorGridLines << QLineF(p1, p2);
1226 
1227     p2 = p1 - QPointF(0, majorTickLength);
1228     _xMajorTickLines << QLineF(p1, p2);
1229 
1230     p1.setY(rect.top());
1231     p2 = p1 + QPointF(0, majorTickLength);
1232     _xMajorTickLines << QLineF(p1, p2);
1233   }
1234   _xMinorGridLines.clear();
1235   _xMinorTickLines.clear();
1236   foreach (qreal x, _xAxis->axisMinorTicks()) {
1237     QPointF p1 = QPointF(mapXToPlot(x), rect.bottom());
1238     QPointF p2 = p1 - QPointF(0, rect.height());
1239     _xMinorGridLines << QLineF(p1, p2);
1240 
1241     p2 = p1 - QPointF(0, minorTickLength);
1242     _xMinorTickLines << QLineF(p1, p2);
1243 
1244     p1.setY(rect.top());
1245     p2 = p1 + QPointF(0, minorTickLength);
1246     _xMinorTickLines << QLineF(p1, p2);
1247   }
1248   _xPlotMarkerLines.clear();
1249   foreach (double x, _xAxis->axisPlotMarkers().markers()) {
1250     double xx = _xAxis->axisLog() ? logXLo(x) : x;
1251     if (xx > _xMin && xx < _xMax) {
1252       QPointF p1 = QPointF(mapXToPlot(x), rect.bottom());
1253       QPointF p2 = p1 - QPointF(0, rect.height());
1254       _xPlotMarkerLines << QLineF(p1, p2);
1255     }
1256   }
1257 }
1258 
1259 
1260 void PlotItem::updateXAxisLabels(QPainter* painter) {
1261   int flags = Qt::TextSingleLine | Qt::AlignCenter;
1262   _xPlotLabels.clear();
1263 
1264   int rotation = _xAxis->axisLabelRotation();
1265   painter->save();
1266   QTransform t;
1267   t.rotate(rotation);
1268 
1269   QMapIterator<double, QString> xLabelIt(_xAxis->axisLabels());
1270   while (xLabelIt.hasNext()) {
1271     xLabelIt.next();
1272 
1273     QRectF bound = painter->boundingRect(QRectF(), flags, xLabelIt.value());
1274     QPointF p;
1275     if (rotation == 0) {
1276       p = QPointF(mapXToPlot(xLabelIt.key()), plotRect().bottom() + bound.height()*0.5 + _calculatedAxisMarginVLead);
1277       bound.moveCenter(p);
1278     } else {
1279       if (rotation < 0) {
1280         qreal theta = (rotation >-30 ? rotation : -30);
1281         qreal right = mapXToPlot(xLabelIt.key()) - bound.height() * (sin(theta*M_PI/180.0));
1282         bound = t.mapRect(bound);
1283         p = QPointF(right, plotRect().bottom() + _calculatedAxisMarginVLead);
1284         bound.moveTopRight(p);
1285       } else {
1286         qreal theta = (rotation <30 ? rotation : 30);
1287         qreal left = mapXToPlot(xLabelIt.key()) - bound.height() * (sin(theta*M_PI/180.0));
1288         bound = t.mapRect(bound);
1289         p = QPointF(left, plotRect().bottom() + _calculatedAxisMarginVLead);
1290         bound.moveTopLeft(p);
1291       }
1292     }
1293 
1294     if (rect().left() > bound.left()) {
1295       bound.setLeft(rect().left());
1296     }
1297 
1298     if (rect().right() >= bound.right()) { // if no overflow to the right...
1299       CachedPlotLabel label;
1300       label.bound = bound;
1301       label.value = xLabelIt.value();
1302       _xPlotLabels.append(label);
1303     }
1304   }
1305   painter->restore();
1306 
1307   if (!_xAxis->baseLabel().isEmpty()) {
1308     QRectF bound = painter->boundingRect(QRectF(), flags, _xAxis->baseLabel());
1309     QPointF p = QPointF(plotRect().left(), plotRect().bottom() + bound.height() * 2.0 + _calculatedAxisMarginVLead);
1310     bound.moveBottomLeft(p);
1311 
1312     CachedPlotLabel label;
1313     label.bound = bound;
1314     label.value = _xAxis->baseLabel();
1315     label.baseLabel = true;
1316     _xPlotLabels.append(label);
1317   }
1318 }
1319 
1320 
1321 void PlotItem::setPlotRectsDirty() {
1322   _plotRectsDirty = true; 
1323   xAxis()->setTicksUpdated(); 
1324   yAxis()->setTicksUpdated();
1325   setPlotPixmapDirty();
1326 }
1327 
1328 
1329 void PlotItem::updateYAxisLines() {
1330   qreal majorTickLength = qMin(rect().width(), rect().height()) * .02; //two percent
1331   qreal minorTickLength = qMin(rect().width(), rect().height()) * 0.01; //one percent
1332   QRectF rect = plotRect();
1333 
1334   _yMajorGridLines.clear();
1335   _yMajorTickLines.clear();
1336   foreach (qreal y, _yAxis->axisMajorTicks()) {
1337     QPointF p1 = QPointF(rect.left(), mapYToPlot(y));
1338     QPointF p2 = p1 + QPointF(rect.width(), 0);
1339     _yMajorGridLines << QLineF(p1, p2);
1340 
1341     p2 = p1 + QPointF(majorTickLength, 0);
1342     _yMajorTickLines << QLineF(p1, p2);
1343 
1344     p1.setX(rect.right());
1345     p2 = p1 - QPointF(majorTickLength, 0);
1346     _yMajorTickLines << QLineF(p1, p2);
1347   }
1348 
1349   _yMinorGridLines.clear();
1350   _yMinorTickLines.clear();
1351   foreach (qreal y, _yAxis->axisMinorTicks()) {
1352     QPointF p1 = QPointF(rect.left(), mapYToPlot(y));
1353     QPointF p2 = p1 + QPointF(rect.width(), 0);
1354     _yMinorGridLines << QLineF(p1, p2);
1355 
1356     p2 = p1 + QPointF(minorTickLength, 0);
1357     _yMinorTickLines << QLineF(p1, p2);
1358 
1359     p1.setX(rect.right());
1360     p2 = p1 - QPointF(minorTickLength, 0);
1361     _yMinorTickLines << QLineF(p1, p2);
1362   }
1363   _yPlotMarkerLines.clear();
1364   foreach (double y, _yAxis->axisPlotMarkers().markers()) {
1365     double yy = _yAxis->axisLog() ? logYLo(y) : y;
1366     if (yy > _yMin && yy < _yMax) {
1367       QPointF p1 = QPointF(rect.left(), mapYToPlot(y));
1368       QPointF p2 = p1 + QPointF(rect.width(), 0);
1369       _yPlotMarkerLines << QLineF(p1, p2);
1370     }
1371   }
1372 }
1373 
1374 
1375 void PlotItem::updateYAxisLabels(QPainter* painter) {
1376   int flags = Qt::TextSingleLine | Qt::AlignCenter;
1377   _yPlotLabels.clear();
1378 
1379   int rotation = _yAxis->axisLabelRotation();
1380 
1381   QTransform t;
1382   t.rotate(rotation);
1383 
1384   QMapIterator<double, QString> yLabelIt(_yAxis->axisLabels());
1385   while (yLabelIt.hasNext()) {
1386     yLabelIt.next();
1387 
1388     QRectF bound = painter->boundingRect(QRectF(), flags, yLabelIt.value());
1389     QPointF p;
1390     if (rotation < 0) {
1391       qreal theta = (rotation >-45.0) ? rotation : -45.0;
1392       qreal top;
1393       if (rotation >-89) {
1394         top = mapYToPlot(yLabelIt.key()) - bound.height()*0.5*cos(theta*2.0*M_PI/180.0);
1395       } else {
1396         top = mapYToPlot(yLabelIt.key()) - bound.width()*0.5;
1397       }
1398       bound = t.mapRect(bound);
1399       bound.moveRight(plotRect().left() - _calculatedAxisMarginHLead);
1400       bound.moveTop(top);
1401     } else if (rotation > 0) {
1402       qreal theta = (rotation <45.0) ? rotation : 45.0;
1403       qreal bottom;
1404       if (rotation < 89) {
1405         bottom = mapYToPlot(yLabelIt.key()) + bound.height()*0.5*cos(theta*2.0*M_PI/180.0);
1406       } else {
1407         bottom = mapYToPlot(yLabelIt.key()) + bound.width()*0.5;
1408       }
1409       bound = t.mapRect(bound);
1410       bound.moveRight(plotRect().left() - _calculatedAxisMarginHLead);
1411       bound.moveBottom(bottom);
1412     } else { // no rotation.
1413       p = QPointF(plotRect().left() - _calculatedAxisMarginHLead,
1414                   mapYToPlot(yLabelIt.key()) - bound.height() * 0.5);
1415       bound.moveTopRight(p);
1416     }
1417 
1418     if (rect().top() > bound.top()) bound.setTop(rect().top());
1419     if (rect().bottom() < bound.bottom()) bound.setBottom(rect().bottom());
1420 
1421     CachedPlotLabel label;
1422     label.bound = bound;
1423     label.value = yLabelIt.value();
1424     _yPlotLabels.append(label);
1425   }
1426 
1427   if (!_yAxis->baseLabel().isEmpty()) {
1428     painter->save();
1429     painter->rotate(-90.0);
1430 
1431     QRectF bound = painter->boundingRect(QRectF(), flags, _yAxis->baseLabel());
1432     bound = QRectF(bound.x(), bound.bottomRight().y() - bound.width(), bound.height(), bound.width());
1433     QPointF p = QPointF(rect().left() + _calculatedLeftBaseOffset, plotRect().bottom());
1434     bound.moveBottomLeft(p);
1435 
1436     CachedPlotLabel label;
1437     label.bound = bound;
1438     label.value = _yAxis->baseLabel();
1439     label.baseLabel = true;
1440     _yPlotLabels.append(label);
1441     painter->restore();
1442   }
1443 }
1444 
1445 
1446 void PlotItem::paintMajorGridLines(QPainter *painter) {
1447   if (xAxis()->drawAxisMajorGridLines()) {
1448     painter->save();
1449     painter->setPen(QPen(QBrush(_xAxis->axisMajorGridLineColor()),
1450                          Curve::lineDim(painter->window(),_xAxis->axisMajorGridLineWidth()),
1451                          _xAxis->axisMajorGridLineStyle()));
1452     painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1453     painter->drawLines(_xMajorGridLines);
1454     painter->restore();
1455   }
1456 
1457   if (yAxis()->drawAxisMajorGridLines()) {
1458     painter->save();
1459     painter->setPen(QPen(QBrush(_yAxis->axisMajorGridLineColor()),
1460                          Curve::lineDim(painter->window(),_yAxis->axisMajorGridLineWidth()),
1461                          _yAxis->axisMajorGridLineStyle()));
1462     painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1463     painter->drawLines(_yMajorGridLines);
1464     painter->restore();
1465   }
1466 }
1467 
1468 
1469 void PlotItem::paintMinorGridLines(QPainter *painter) {
1470   if (xAxis()->drawAxisMinorGridLines()) {
1471     painter->save();
1472     painter->setPen(QPen(QBrush(_xAxis->axisMinorGridLineColor()),
1473                          Curve::lineDim(painter->window(),_xAxis->axisMinorGridLineWidth()),
1474                          _xAxis->axisMinorGridLineStyle()));
1475     painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1476     painter->drawLines(_xMinorGridLines);
1477     painter->restore();
1478   }
1479 
1480   if (yAxis()->drawAxisMinorGridLines()) {
1481     painter->save();
1482     painter->setPen(QPen(QBrush(_yAxis->axisMinorGridLineColor()),
1483                          Curve::lineDim(painter->window(),_yAxis->axisMinorGridLineWidth()),
1484                          _yAxis->axisMinorGridLineStyle()));
1485     painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1486     painter->drawLines(_yMinorGridLines);
1487     painter->restore();
1488   }
1489 }
1490 
1491 
1492 void PlotItem::paintMajorTicks(QPainter *painter) {
1493   painter->save();
1494   painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1495   if (xAxis()->drawAxisMajorTicks()) {
1496     painter->drawLines(_xMajorTickLines);
1497   }
1498 
1499   if (yAxis()->drawAxisMajorTicks()) {
1500     painter->drawLines(_yMajorTickLines);
1501   }
1502   painter->restore();
1503 }
1504 
1505 
1506 void PlotItem::paintMinorTicks(QPainter *painter) {
1507   painter->save();
1508   painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1509   if (xAxis()->drawAxisMinorTicks()) {
1510     painter->drawLines(_xMinorTickLines);
1511   }
1512 
1513   if (yAxis()->drawAxisMinorTicks()) {
1514     painter->drawLines(_yMinorTickLines);
1515   }
1516   painter->restore();
1517 }
1518 
1519 
1520 void PlotItem::scaleAxisLabels(qreal scaleFactor) {
1521   _numberAxisLabelScaleFactor = qMin(_numberAxisLabelScaleFactor, scaleFactor);
1522 }
1523 
1524 
1525 void PlotItem::resetScaleAxisLabels() {
1526   _numberAxisLabelScaleFactor = 1.0;
1527 }
1528 
1529 
1530 bool PlotItem::isUseAxisScale() const {
1531   return _useNumberAxisLabelScale;
1532 }
1533 
1534 
1535 void PlotItem::setUseAxisScale(bool useScale) {
1536   if (_useNumberAxisLabelScale != useScale) {
1537     _useNumberAxisLabelScale = useScale;
1538     setPlotPixmapDirty();
1539   }
1540 }
1541 
1542 
1543 static void PaintNumber(QPainter *painter, const QRectF rec, int flags, const QString &text) {
1544   const double superscript_scale = 0.60;
1545   const double superscript_raise = 0.44;
1546   QRectF r = rec;
1547   QStringList base_mantisa = text.split('e');
1548 
1549   if (base_mantisa.size()>1) {
1550     if (base_mantisa[1][0].isLetter()) {
1551       base_mantisa.clear();
1552       base_mantisa.append(text);
1553     }
1554   }
1555 
1556 
1557   if (base_mantisa.size()<=1) {
1558     painter->drawText(r, flags, text);
1559   } else {
1560     QString base;
1561     if (base_mantisa[0]==QString('x')) {
1562       base = "10";
1563       base_mantisa[0].clear();
1564     } else {
1565       base = "x10";
1566     }
1567     base_mantisa[1].remove('+');
1568     if (base_mantisa[1].contains(']')) {
1569       base_mantisa[1].remove(']');
1570       base_mantisa.append(QString(']'));
1571     }
1572     qreal w = painter->fontMetrics().width(base_mantisa[0] + base) +
1573         painter->fontMetrics().width(base_mantisa[1])*superscript_scale;
1574     if (base_mantisa.size()>2) {
1575       w += painter->fontMetrics().width(base_mantisa[2]);
1576     }
1577     if (flags & Qt::AlignRight) {
1578       qreal right = r.right();
1579       r.setWidth(w);
1580       r.moveRight(right);
1581     } else if (flags & Qt::AlignCenter) {
1582       QPointF center = r.center();
1583       r.setWidth(w);
1584       r.moveCenter(center);
1585     }
1586     QPointF p = QPointF(r.topLeft().x(), r.center().y()+painter->fontMetrics().boundingRect('0').height()/2);
1587     //painter->drawRect(r);
1588     painter->drawText(p, base_mantisa[0]);
1589     p.setX(p.x() + painter->fontMetrics().width(base_mantisa[0]));
1590     painter->drawText(p,base);
1591     qreal ly = p.y();
1592     p.setX(p.x() + painter->fontMetrics().width(base));
1593     p.setY(p.y() - superscript_raise * painter->fontMetrics().height());
1594     painter->save();
1595     QFont f = painter->font();
1596     f.setPointSizeF(f.pointSizeF()*superscript_scale);
1597     painter->setFont(f);
1598     painter->drawText(p,base_mantisa[1]);
1599     p.setX(p.x() + painter->fontMetrics().width(base_mantisa[1]));
1600     painter->restore();
1601     if (base_mantisa.size()>2) {
1602       p.setY(ly);
1603       painter->drawText(p,base_mantisa[2]);
1604     }
1605   }
1606 }
1607 
1608 void PlotItem::paintBottomTickLabels(QPainter *painter) {
1609   int flags = Qt::TextSingleLine/* | Qt::AlignCenter*/;
1610 
1611   painter->save();
1612   painter->setPen(_numberLabelDetails->fontColor());
1613 
1614   int rotation = _xAxis->axisLabelRotation();
1615   foreach(const CachedPlotLabel &label, _xPlotLabels) {
1616     QRectF bound = label.bound;
1617     if (_numberAxisLabelScaleFactor<0.9999) {
1618       bound.translate( bound.width() *(1.0-_numberAxisLabelScaleFactor)*0.5, 0.0);
1619     }
1620     if (rotation != 0) {
1621       painter->save();
1622       QTransform t;
1623       t.rotate(-1*rotation);
1624       painter->rotate(rotation);
1625 
1626       PaintNumber(painter, t.mapRect(bound), Qt::TextSingleLine | Qt::AlignCenter, label.value);
1627       painter->restore();
1628     } else {
1629       PaintNumber(painter, bound, flags, label.value);
1630     }
1631   }
1632   painter->restore();
1633 
1634 }
1635 
1636 
1637 void PlotItem::paintLeftTickLabels(QPainter *painter) {
1638   int flags = Qt::TextSingleLine | Qt::AlignVCenter | Qt::AlignRight;
1639 
1640   painter->save();
1641   painter->setPen(_numberLabelDetails->fontColor());
1642 
1643   int rotation = _yAxis->axisLabelRotation();
1644 
1645   foreach(const CachedPlotLabel &label, _yPlotLabels) {
1646     if (label.baseLabel) {
1647       painter->save();
1648       QTransform t;
1649       t.rotate(90.0);
1650       painter->rotate(-90.0);
1651 
1652       PaintNumber(painter, t.mapRect(label.bound), flags, label.value);
1653       //painter->drawText(t.mapRect(label.bound), flags, label.value);
1654       painter->restore();
1655     } else {
1656       if (rotation != 0) {
1657         painter->save();
1658         QTransform t;
1659         t.rotate(-1*rotation);
1660         painter->rotate(rotation);
1661 
1662         PaintNumber(painter, t.mapRect(label.bound), flags, label.value);
1663         //painter->drawText(t.mapRect(label.bound), flags, label.value);
1664         painter->restore();
1665       } else {
1666         PaintNumber(painter, label.bound, flags, label.value);
1667         //painter->drawText(label.bound, flags, label.value);
1668       }
1669     }
1670   }
1671   painter->restore();
1672 
1673 #if DEBUG_LABEL_REGION
1674   QRectF yLabelRect;
1675   foreach(const CachedPlotLabel &label, _yPlotLabels) {
1676     if (yLabelRect.isValid()) {
1677       yLabelRect = yLabelRect.united(label.bound);
1678     } else {
1679       yLabelRect = label.bound;
1680     }
1681   }
1682   painter->save();
1683   painter->setOpacity(0.3);
1684   qDebug() << "Left Tick Labels - yLabelRect:" << yLabelRect;
1685   painter->fillRect(yLabelRect, Qt::green);
1686   painter->restore();
1687 #endif
1688 }
1689 
1690 
1691 void PlotItem::paintTickLabels(QPainter *painter) {
1692   if (_xAxis->isAxisVisible()) {
1693     paintBottomTickLabels(painter);
1694   }
1695   if (_yAxis->isAxisVisible()) {
1696     paintLeftTickLabels(painter);
1697   }
1698 }
1699 
1700 
1701 void PlotItem::paintPlotMarkers(QPainter *painter) {
1702   if (!_xPlotMarkerLines.isEmpty()) {
1703     painter->save();
1704     painter->setPen(QPen(QBrush(_xAxis->axisPlotMarkers().lineColor()),
1705                          Curve::lineDim(painter->window(),_xAxis->axisPlotMarkers().lineWidth()),
1706                          _xAxis->axisPlotMarkers().lineStyle()));
1707     painter->drawLines(_xPlotMarkerLines);
1708     painter->restore();
1709   }
1710   if (!_yPlotMarkerLines.isEmpty()) {
1711     painter->save();
1712     painter->setPen(QPen(QBrush(_yAxis->axisPlotMarkers().lineColor()),
1713                          Curve::lineDim(painter->window(),_yAxis->axisPlotMarkers().lineWidth()),
1714                          _yAxis->axisPlotMarkers().lineStyle()));
1715     painter->drawLines(_yPlotMarkerLines);
1716     painter->restore();
1717   }
1718 }
1719 
1720 
1721 void PlotItem::calculatePlotRects() {
1722   // Calculate the plotAxisRect first.
1723   qreal left = _leftLabelDetails->isVisible() ? leftLabelMargin() : 0.0;
1724   qreal bottom = _bottomLabelDetails->isVisible() ? bottomLabelMargin() : 0.0;
1725   qreal right = _rightLabelDetails->isVisible() ? rightMarginSize() : 0.0;
1726   qreal top = _topLabelDetails->isVisible() ? topMarginSize() : 0.0;
1727 
1728   QPointF topLeft(rect().topLeft() + QPointF(left, top));
1729   if (_manuallyHideRightAxisLabel && !_isInSharedAxisBox) {
1730     right += 1;
1731   }
1732   if (_manuallyHideBottomAxisLabel && !_isInSharedAxisBox) {
1733     bottom += 1;
1734   }
1735   QPointF bottomRight(rect().bottomRight() - QPointF(right, bottom));
1736 
1737   _calculatedPlotAxisRect = QRectF(topLeft, bottomRight);
1738 
1739   // Use the PlotAxisRect as basis to calculate PlotRect.
1740   QRectF plot = _calculatedPlotAxisRect;
1741   qreal xOffset = _xAxis->isAxisVisible() ? axisMarginHeight() : 0.0;
1742   qreal yOffset = _yAxis->isAxisVisible() ? axisMarginWidth() : 0.0;
1743   qreal bottomPadding = _xAxis->isAxisVisible() ? _bottomPadding : 0.0;
1744   qreal leftPadding = _yAxis->isAxisVisible() ? _leftPadding : 0.0;
1745   qreal rightPadding = _rightLabelDetails->isVisible() ? _rightPadding : 0.0;
1746   qreal topPadding = _topLabelDetails->isVisible() ? _topPadding : 0.0;
1747 
1748   plot.setLeft(plot.left() + yOffset + leftPadding);
1749   plot.setBottom(plot.bottom() - xOffset - bottomPadding);
1750   plot.setRight(plot.right() - rightPadding);
1751   plot.setTop(plot.top() + topPadding);
1752   if (!plot.isValid()) {
1753     if (plot.width() <= 0) {
1754       plot.setWidth(0.1);
1755     }
1756     if (plot.height() <= 0) {
1757       plot.setHeight(0.1);
1758     }
1759   }
1760   _calculatedPlotRect = plot;
1761   _plotRectsDirty = false;
1762   emit updatePlotRect();
1763 }
1764 
1765 
1766 QRectF PlotItem::plotAxisRect() {
1767   if (_plotRectsDirty) {
1768     calculatePlotRects();
1769   }
1770   return _calculatedPlotAxisRect;
1771 }
1772 
1773 
1774 QRectF PlotItem::plotRect() {
1775   if (_plotRectsDirty) {
1776     calculatePlotRects();
1777   }
1778   return _calculatedPlotRect;
1779 }
1780 
1781 
1782 qreal PlotItem::leftMarginSize() const {
1783   qreal margin = _leftLabelDetails->isVisible() ? leftLabelMargin() : 0.0;
1784   margin += _yAxis->isAxisVisible() ? axisMarginWidth() : 0.0;
1785 
1786   return margin;
1787 }
1788 
1789 
1790 qreal PlotItem::bottomMarginSize() const {
1791   qreal margin = _bottomLabelDetails->isVisible() ? bottomLabelMargin() : 0.0;
1792   margin += _xAxis->isAxisVisible() ? axisMarginHeight() : 0.0;
1793 
1794   return margin;
1795 }
1796 
1797 
1798 qreal PlotItem::rightMarginSize() const {
1799   qreal margin = _rightLabelDetails->isVisible() ? rightLabelMargin() : 0.0;
1800   if (supportsTiedZoom() && margin < tiedZoomSize().width()) margin = tiedZoomSize().width();
1801   return margin;
1802 }
1803 
1804 
1805 qreal PlotItem::topMarginSize() const {
1806   qreal margin = _topLabelDetails->isVisible() ? topLabelMargin() : 0.0;
1807   if (supportsTiedZoom() && margin < tiedZoomSize().height()) margin = tiedZoomSize().height();
1808   return margin;
1809 }
1810 
1811 
1812 void PlotItem::setPadding(const qreal left, const qreal right, const qreal top, const qreal bottom) {
1813   if ((left == _leftPadding) && (right == _rightPadding) && (top == _topPadding) && (bottom == _bottomPadding)) {
1814     return;
1815   }
1816   _leftPadding = left;
1817   _rightPadding = right;
1818   _topPadding = top;
1819   _bottomPadding = bottom;
1820   setPlotRectsDirty();
1821   emit triggerRedraw();
1822 }
1823 
1824 
1825 void PlotItem::setLeftPadding(const qreal padding) {
1826   if (padding != _leftPadding) {
1827     _leftPadding = padding;
1828     setPlotRectsDirty();
1829   }
1830 }
1831 
1832 
1833 void PlotItem::setBottomPadding(const qreal padding) {
1834   if (padding != _bottomPadding) {
1835     _bottomPadding = padding;
1836     setPlotRectsDirty();
1837   }
1838 }
1839 
1840 
1841 void PlotItem::setRightPadding(const qreal padding) {
1842   if (padding != _rightPadding) {
1843     _rightPadding = padding;
1844     setPlotRectsDirty();
1845   }
1846 }
1847 
1848 
1849 void PlotItem::setTopPadding(const qreal padding) {
1850   if (padding != _topPadding) {
1851     _topPadding = padding;
1852     setPlotRectsDirty();
1853   }
1854 }
1855 
1856 void PlotItem::setManuallyHideLeftAxisLabel(bool hide) {
1857   _manuallyHideLeftAxisLabel = hide;
1858   if (!_isInSharedAxisBox) {
1859     setLeftSuppressed(hide);
1860   }
1861 }
1862 
1863 void PlotItem::setManuallyHideRightAxisLabel(bool hide) {
1864   _manuallyHideRightAxisLabel = hide;
1865   if (!_isInSharedAxisBox) {
1866     setRightSuppressed(hide);
1867   }
1868 }
1869 
1870 void PlotItem::setManuallyHideTopAxisLabel(bool hide) {
1871   _manuallyHideTopAxisLabel = hide;
1872   if (!_isInSharedAxisBox) {
1873     setTopSuppressed(hide);
1874   }
1875 }
1876 
1877 void PlotItem::setManuallyHideBottomAxisLabel(bool hide) {
1878   _manuallyHideBottomAxisLabel = hide;
1879   if (!_isInSharedAxisBox) {
1880     setBottomSuppressed(hide);
1881   }
1882 }
1883 
1884 
1885 QRectF PlotItem::projectionRect() const {
1886   return _projectionRect;
1887 }
1888 
1889 
1890 void PlotItem::setTiedZoom(bool tiedXZoom, bool tiedYZoom, bool checkAllTied) {
1891   if ((_isXTiedZoom == tiedXZoom) && (_isYTiedZoom == tiedYZoom))
1892     return;
1893 
1894   bool wasTiedZoom = isTiedZoom();
1895 
1896   _isXTiedZoom = tiedXZoom;
1897   _isYTiedZoom = tiedYZoom;
1898 
1899   if (isTiedZoom() && !wasTiedZoom) {
1900     PlotItemManager::self()->addTiedZoomPlot(this, checkAllTied);
1901   } else if (!isTiedZoom() && wasTiedZoom) {
1902     PlotItemManager::self()->removeTiedZoomPlot(this);
1903   }
1904 
1905   //FIXME ugh, this is expensive, but need to redraw the checkboxes...
1906   update();
1907 }
1908 
1909 
1910 bool PlotItem::isInSharedAxisBox() const {
1911   return _isInSharedAxisBox;
1912 }
1913 
1914 
1915 void PlotItem::setInSharedAxisBox(bool inSharedBox) {
1916   _isInSharedAxisBox = inSharedBox;
1917   setLockParent(inSharedBox);
1918 }
1919 
1920 
1921 SharedAxisBoxItem* PlotItem::sharedAxisBox() const {
1922   return _sharedBox;
1923 }
1924 
1925 
1926 void PlotItem::setSharedAxisBox(SharedAxisBoxItem* parent) {
1927   if (parent) {
1928     if (isTiedZoom()) {
1929       setTiedZoom(false, false);
1930     }
1931     setInSharedAxisBox(true);
1932     setAllowedGripModes(0);
1933     setFlags(0);
1934     setParentViewItem(parent);
1935     //setBrush(Qt::transparent);
1936 
1937     _sharedBox = parent;
1938     createSharedAxisBoxMenu();
1939   } else {
1940     setSupportsTiedZoom(true);
1941     setInSharedAxisBox(false);
1942     setAllowedGripModes(Move | Resize | Rotate);
1943     setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);
1944     setParentViewItem(0);
1945     //setBrush(Qt::white);
1946 
1947     _sharedBox = 0;
1948   }
1949 }
1950 
1951 
1952 void PlotItem::setPlotBordersDirty(bool dirty) {
1953   if (isInSharedAxisBox() && dirty && _sharedBox) {
1954     _sharedBox->setDirty();
1955   } else {
1956     view()->setPlotBordersDirty(dirty);
1957   }
1958   if (dirty) {
1959     setPlotRectsDirty();
1960   }
1961 }
1962 
1963 
1964 void PlotItem::updateScale() {
1965   if (_xAxis->axisLog()) {
1966     _xMax = logXHi(projectionRect().right());
1967     _xMin = logXLo(projectionRect().left());
1968   } else {
1969     _xMax = projectionRect().right();
1970     _xMin = projectionRect().left();
1971   }
1972 
1973   if (_yAxis->axisLog()) {
1974     _yMax = logYHi(projectionRect().bottom());
1975     _yMin = logYLo(projectionRect().top());
1976   } else {
1977     _yMax = projectionRect().bottom();
1978     _yMin = projectionRect().top();
1979   }
1980 }
1981 
1982 
1983 QRectF PlotItem::mapToProjection(const QRectF &rect) {
1984   QRectF projRect;
1985 
1986   // Invert and convert points.
1987   QPointF topLeft;
1988   QPointF bottomRight;
1989   if (!(_xAxis->axisReversed() || _yAxis->axisReversed())) {
1990     topLeft = mapToProjection(rect.bottomLeft());
1991     bottomRight = mapToProjection(rect.topRight());
1992   } else if (_xAxis->axisReversed() && _yAxis->axisReversed()) {
1993     topLeft = mapToProjection(rect.topRight());
1994     bottomRight = mapToProjection(rect.bottomLeft());
1995   } else if (_yAxis->axisReversed()) {
1996     topLeft = mapToProjection(rect.topLeft());
1997     bottomRight = mapToProjection(rect.bottomRight());
1998   } else {
1999     topLeft = mapToProjection(rect.bottomRight());
2000     bottomRight = mapToProjection(rect.topLeft());
2001   }
2002 
2003   projRect.setTopLeft(topLeft);
2004 
2005   projRect.setWidth(bottomRight.x() - topLeft.x());
2006   projRect.setHeight(bottomRight.y() - topLeft.y());
2007 
2008   return projRect;
2009 }
2010 
2011 
2012 QPointF PlotItem::mapToProjection(const QPointF &point) {
2013   QRectF pr = plotRect();
2014   double xpos, ypos;
2015 
2016   updateScale();
2017 
2018   if (_xAxis->axisReversed()) {
2019     xpos = (double)(pr.right() - point.x())/(double)pr.width();
2020   } else {
2021     xpos = (double)(point.x() - pr.left())/(double)pr.width();
2022   }
2023   xpos = xpos * (_xMax - _xMin) + _xMin;
2024 
2025   if (_xAxis->axisLog()) {
2026     xpos = pow(10, xpos);
2027   }
2028 
2029   if (_yAxis->axisReversed()) {
2030     ypos = (double)(point.y() - pr.top())/(double)pr.height();
2031   } else {
2032     ypos = (double)(pr.bottom() - point.y())/(double)pr.height();
2033   }
2034   ypos = ypos * (_yMax - _yMin) + _yMin;
2035 
2036   if (_yAxis->axisLog()) {
2037     ypos = pow(10, ypos);
2038   }
2039 
2040   return QPointF(xpos, ypos);
2041 }
2042 
2043 
2044 QPointF PlotItem::mapToPlot(const QPointF &point) {
2045   return QPointF(mapXToPlot(point.x()), mapYToPlot(point.y()));
2046 }
2047 
2048 
2049 qreal PlotItem::mapXToPlot(const qreal &x) {
2050   QRectF pr = plotRect();
2051   double newX = x;
2052 
2053   if (_xAxis->axisLog()) {
2054     newX = logXLo(x);
2055   }
2056 
2057   newX -= _xMin;
2058   newX = newX / (_xMax - _xMin);
2059 
2060   newX = newX * pr.width();
2061 
2062   if (_xAxis->axisLog() && x == -350) {
2063     newX = 0;
2064   }
2065 
2066   if (_xAxis->axisReversed()) {
2067     newX = pr.right() - newX;
2068   } else {
2069     newX = newX + pr.left();
2070   }
2071   return newX;
2072 }
2073 
2074 
2075 qreal PlotItem::mapYToPlot(const qreal &y) {
2076   QRectF pr = plotRect();
2077   double newY = y;
2078 
2079   if (_yAxis->axisLog()) {
2080     newY = logYLo(y);
2081   }
2082 
2083   newY -= _yMin;
2084   newY = newY / (_yMax - _yMin);
2085 
2086   newY = newY * pr.height();
2087 
2088   if (_yAxis->axisLog() && y == -350) {
2089     newY = 0;
2090   }
2091 
2092   if (_yAxis->axisReversed()) {
2093     newY = newY + pr.top();
2094   } else {
2095     newY = pr.bottom() - newY;
2096   }
2097   return newY;
2098 }
2099 
2100 
2101 QFont PlotItem::globalFont() const {
2102   return _globalFont;
2103 }
2104 
2105 
2106 void PlotItem::setGlobalFont(const QFont &font) {
2107   if (font != _globalFont) {
2108     _globalFont = font;
2109     setPlotBordersDirty(true);
2110     setLabelsDirty();
2111   }
2112 }
2113 
2114 
2115 qreal PlotItem::globalFontScale() const {
2116   return _globalFontScale;
2117 }
2118 
2119 
2120 void PlotItem::setGlobalFontScale(const qreal scale) {
2121   if (scale != _globalFontScale) {
2122     _globalFontScale = scale;
2123     setPlotBordersDirty(true);
2124     setLabelsDirty();
2125   }
2126 }
2127 
2128 
2129 QColor PlotItem::globalFontColor() const {
2130   return _globalFontColor;
2131 }
2132 
2133 
2134 void PlotItem::setGlobalFontColor(const QColor &color) {
2135   if (color != _globalFontColor) {
2136     _globalFontColor = color;
2137     setLabelsDirty();
2138   }
2139 }
2140 
2141 
2142 QString PlotItem::leftLabel() const {
2143   if (!leftLabelDetails()->isAuto()) {
2144     return leftLabelDetails()->text();
2145   } else {
2146     return autoLeftLabel();
2147   }
2148 }
2149 
2150 
2151 QString PlotItem::autoLeftLabel() const {
2152   foreach (PlotRenderItem *renderer, renderItems()) {
2153     QString label = renderer->leftLabel();
2154     if (!label.isEmpty()) {
2155       if (_yAxis->axisInterpret()) { // remove units
2156         QRegExp rx(" \\[*\\]");
2157         rx.setPatternSyntax(QRegExp::Wildcard);
2158         return label.remove(rx);
2159       } else {
2160         return label;
2161       }
2162     }
2163   }
2164   return QString();
2165 }
2166 
2167 
2168 QString PlotItem::bottomLabel() const {
2169   if (!bottomLabelDetails()->isAuto()) {
2170     return bottomLabelDetails()->text();
2171   } else {
2172     return autoBottomLabel();
2173   }
2174 }
2175 
2176 
2177 QString PlotItem::autoBottomLabel() const {
2178   foreach (PlotRenderItem *renderer, renderItems()) {
2179     QString label = renderer->bottomLabel();
2180     if (!label.isEmpty()) {
2181       if (_xAxis->axisInterpret()) { // remove units if time interpretation
2182         QRegExp rx(" \\[*\\]");
2183         rx.setPatternSyntax(QRegExp::Wildcard);
2184         return label.remove(rx);
2185       } else {
2186         return label;
2187       }
2188     }
2189   }
2190   return QString();
2191 }
2192 
2193 
2194 QString PlotItem::rightLabel() const {
2195   if (!rightLabelDetails()->isAuto()) {
2196     return rightLabelDetails()->text();
2197   } else {
2198     return autoRightLabel();
2199   }
2200 }
2201 
2202 
2203 QString PlotItem::autoRightLabel() const {
2204   foreach (PlotRenderItem *renderer, renderItems()) {
2205     QString label = renderer->rightLabel();
2206     if (!label.isEmpty())
2207       return label;
2208   }
2209   return QString();
2210 }
2211 
2212 
2213 QString PlotItem::topLabel() const {
2214   if (!topLabelDetails()->isAuto()) {
2215     return topLabelDetails()->text();
2216   } else {
2217     return autoTopLabel();
2218   }
2219 }
2220 
2221 
2222 QString PlotItem::autoTopLabel() const {
2223   if (showLegend()) {
2224     return QString();
2225   } else {
2226     QString label;
2227     int count = renderItems().count();
2228     for (int i=0; i<count; i++) {
2229       label += renderItems().at(i)->topLabel();
2230       if (i<count - 1) {
2231         label += ' ';
2232       }
2233     }
2234     if (label == leftLabel()) {
2235       return QString();
2236     } else {
2237       return label;
2238     }
2239   }
2240 }
2241 
2242 
2243 void PlotItem::setTopSuppressed(bool suppressed) {
2244   if (!_isInSharedAxisBox) {
2245     if (_manuallyHideTopAxisLabel) {
2246       suppressed = true;
2247     }
2248   }
2249   _topLabelDetails->setVisible(!suppressed);
2250 }
2251 
2252 
2253 void PlotItem::setRightSuppressed(bool suppressed) {
2254   if (!_isInSharedAxisBox) {
2255     if (_manuallyHideRightAxisLabel) {
2256      suppressed = true;
2257     }
2258   }
2259   _rightLabelDetails->setVisible(!suppressed);
2260 }
2261 
2262 
2263 void PlotItem::setLeftSuppressed(bool suppressed) {
2264   if (!_isInSharedAxisBox) {
2265     if (_manuallyHideLeftAxisLabel) {
2266       suppressed = true;
2267     }
2268   }
2269   _leftLabelDetails->setVisible(!suppressed);
2270   _yAxis->setAxisVisible(!suppressed);
2271 }
2272 
2273 
2274 void PlotItem::setBottomSuppressed(bool suppressed) {
2275   if (!_isInSharedAxisBox) {
2276     if (_manuallyHideBottomAxisLabel) {
2277       suppressed = true;
2278     }
2279   }
2280   _bottomLabelDetails->setVisible(!suppressed);
2281   _xAxis->setAxisVisible(!suppressed);
2282 }
2283 
2284 
2285 void PlotItem::setLabelsVisible(bool visible) {
2286   _leftLabelDetails->setVisible(visible);
2287   _rightLabelDetails->setVisible(visible);
2288   _topLabelDetails->setVisible(visible);
2289   _bottomLabelDetails->setVisible(visible);
2290   _xAxis->setAxisVisible(visible);
2291   _yAxis->setAxisVisible(visible);
2292 }
2293 
2294 
2295 qreal PlotItem::labelMarginWidth() const {
2296   return _calculatedLabelMarginWidth;
2297 }
2298 
2299 
2300 qreal PlotItem::leftLabelMargin() const {
2301   return _calculatedLeftLabelMargin;
2302 }
2303 
2304 
2305 qreal PlotItem::rightLabelMargin() const {
2306   return _calculatedRightLabelMargin;
2307 }
2308 
2309 
2310 qreal PlotItem::labelMarginHeight() const {
2311   return _calculatedLabelMarginHeight;
2312 }
2313 
2314 
2315 qreal PlotItem::topLabelMargin() const {
2316   return _calculatedTopLabelMargin;
2317 }
2318 
2319 
2320 
2321 qreal PlotItem::bottomLabelMargin() const {
2322   return _calculatedBottomLabelMargin;
2323 }
2324 
2325 
2326 QRectF PlotItem::topLabelRect() const {
2327   if (topLabelMargin()>0) {
2328     return QRectF(0.0, 0.0, width() - leftLabelMargin() - rightLabelMargin(), topLabelMargin());
2329   } else {
2330     return QRectF(0.0, 0.0, width() - leftLabelMargin() - rightLabelMargin(), _calculatedTopLabelHeight);
2331   }
2332 }
2333 
2334 
2335 QRectF PlotItem::bottomLabelRect() const {
2336   return QRectF(0.0, 0.0, width() - leftLabelMargin() - rightLabelMargin(), bottomLabelMargin());
2337 }
2338 
2339 
2340 QRectF PlotItem::leftLabelRect() const {
2341   return QRectF(0.0, 0.0, leftLabelMargin(), height() - topLabelMargin() - bottomLabelMargin());
2342 }
2343 
2344 
2345 QRectF PlotItem::rightLabelRect() const {
2346   return QRectF(0.0, 0.0, rightLabelMargin(), height() - topLabelMargin() - bottomLabelMargin());
2347 }
2348 
2349 
2350 void PlotItem::generateLeftLabel(QPainter *p) {
2351   if (!_leftLabel.dirty) {
2352     return;
2353   }
2354   _leftLabel.valid = false;
2355   _leftLabel.dirty = false;
2356   Label::Parsed *parsed = Label::parse(leftLabel(), _leftLabelDetails->fontColor());
2357   if (parsed) {
2358 
2359     if (_leftLabel.rc) {
2360       delete _leftLabel.rc;
2361     }
2362 
2363     Label::RenderContext *rc = new Label::RenderContext(leftLabelDetails()->calculatedFont(*p->device()), p);
2364     rc->y = rc->fontAscent();
2365     Label::renderLabel(*rc, parsed->chunk, true, false);
2366 
2367     QTransform t;
2368     t.translate(rect().left(),plotRect().center().y() + rc->x/2);
2369     t.rotate(-90.0);
2370 
2371     connect(rc, SIGNAL(labelDirty()), this, SLOT(setLeftLabelDirty()));
2372     connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2373 
2374     _leftLabel.rc = rc;
2375     _leftLabel.transform = t;
2376     _leftLabel.valid = true;
2377 
2378     delete parsed;
2379   }
2380 }
2381 
2382 
2383 void PlotItem::paintLeftLabel(QPainter *painter) {
2384   if (!_leftLabelDetails->isVisible() || leftLabel().isEmpty())
2385     return;
2386 
2387   generateLeftLabel(painter);
2388 
2389   if (_leftLabel.valid) {
2390     painter->save();
2391     painter->setTransform(_leftLabel.transform, true);
2392     Label::paintLabel(*_leftLabel.rc, painter);
2393     painter->restore();
2394   }
2395 }
2396 
2397 
2398 void PlotItem::calculateLeftLabelMargin(QPainter *painter) {
2399   if (!_leftLabelDetails->isVisible()) {
2400     _calculatedLeftLabelMargin = 0;
2401   } else {
2402     painter->save();
2403     QTransform t;
2404     t.rotate(90.0);
2405     painter->rotate(-90.0);
2406 
2407     painter->setFont(leftLabelDetails()->calculatedFont(*painter->device()));
2408     QRectF leftLabelBound = painter->boundingRect(t.mapRect(leftLabelRect()),
2409         Qt::AlignCenter, leftLabel());
2410     painter->restore();
2411 
2412     _calculatedLeftLabelMargin = leftLabelBound.height();
2413     _calculatedLeftLabelWidth = leftLabelBound.width();
2414 
2415     //No more than 1/4 the width of the plot
2416     if (width() < _calculatedLeftLabelMargin * 4)
2417       _calculatedLeftLabelMargin = width() / 4;
2418   }
2419 }
2420 
2421 
2422 void PlotItem::generateBottomLabel(QPainter *p) {
2423   if (!_bottomLabel.dirty) {
2424     return;
2425   }
2426 
2427   _bottomLabel.valid = false;
2428   _bottomLabel.dirty = false;
2429   Label::Parsed *parsed = Label::parse(bottomLabel(),_bottomLabelDetails->fontColor());
2430   if (parsed) {
2431 
2432     if (_bottomLabel.rc) {
2433       delete _bottomLabel.rc;
2434     }
2435 
2436     Label::RenderContext *rc = new Label::RenderContext(bottomLabelDetails()->calculatedFont(*p->device()), p);
2437     rc->y = rc->fontAscent();
2438     Label::renderLabel(*rc, parsed->chunk, true, false);
2439 
2440     QTransform t;
2441     t.translate(plotRect().center().x() - rc->x / 2, plotAxisRect().bottom());
2442 
2443     connect(rc, SIGNAL(labelDirty()), this, SLOT(setBottomLabelDirty()));
2444     connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2445 
2446     _bottomLabel.rc = rc;
2447     _bottomLabel.transform = t;
2448     _bottomLabel.valid = true;
2449 
2450     delete parsed;
2451   }
2452 }
2453 
2454 
2455 void PlotItem::paintBottomLabel(QPainter *painter) {
2456   if (!_bottomLabelDetails->isVisible() || bottomLabel().isEmpty())
2457     return;
2458 
2459   generateBottomLabel(painter);
2460 
2461   if (_bottomLabel.valid) {
2462     painter->save();
2463     painter->setTransform(_bottomLabel.transform, true);
2464     Label::paintLabel(*_bottomLabel.rc, painter);
2465     painter->restore();
2466   }
2467 }
2468 
2469 
2470 void PlotItem::calculateBottomLabelMargin(QPainter *painter) {
2471   if (!_bottomLabelDetails->isVisible()) {
2472     _calculatedBottomLabelMargin = 0;
2473   } else {
2474     painter->save();
2475 
2476     painter->setFont(bottomLabelDetails()->calculatedFont(*painter->device()));
2477 
2478     QRectF bottomLabelBound = painter->boundingRect(bottomLabelRect(),
2479         Qt::AlignCenter, bottomLabel());
2480     painter->restore();
2481 
2482     _calculatedBottomLabelMargin = bottomLabelBound.height();
2483     _calculatedBottomLabelWidth = bottomLabelBound.width();
2484 
2485     //No more than 1/4 the height of the plot
2486     if (height() < _calculatedBottomLabelMargin * 4)
2487       _calculatedLeftLabelMargin = height() / 4;
2488   }
2489 }
2490 
2491 
2492 void PlotItem::generateRightLabel(QPainter *p) {
2493   if (!_rightLabel.dirty) {
2494     return;
2495   }
2496   _rightLabel.valid = false;
2497   _rightLabel.dirty = false;
2498   Label::Parsed *parsed = Label::parse(rightLabel(), _rightLabelDetails->fontColor());
2499   if (parsed && rightLabelRect().isValid()) {
2500 
2501     if (_rightLabel.parsed) {
2502       delete _rightLabel.parsed;
2503     }
2504 
2505     Label::RenderContext *rc = new Label::RenderContext(rightLabelDetails()->calculatedFont(*p->device()), p);
2506     rc->y = rc->fontAscent();
2507     Label::renderLabel(*rc, parsed->chunk, true, false);
2508 
2509     QTransform t;
2510     t.translate(rect().right(), plotRect().center().y() - rc->x/2);
2511 
2512     t.rotate(90.0);
2513 
2514     connect(rc, SIGNAL(labelDirty()), this, SLOT(setRightLabelDirty()));
2515     connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2516 
2517     _rightLabel.rc = rc;
2518     _rightLabel.transform = t;
2519     _rightLabel.valid = true;
2520 
2521     delete parsed;
2522   }
2523 }
2524 
2525 
2526 void PlotItem::paintRightLabel(QPainter *painter) {
2527   if (!_rightLabelDetails->isVisible() || rightLabel().isEmpty())
2528     return;
2529 
2530   generateRightLabel(painter);
2531 
2532   if (_rightLabel.valid) {
2533     painter->save();
2534     painter->setTransform(_rightLabel.transform, true);
2535     Label::paintLabel(*_rightLabel.rc, painter);
2536     painter->restore();
2537   }
2538 
2539 }
2540 
2541 
2542 void PlotItem::calculateRightLabelMargin(QPainter *painter) {
2543   if (!_rightLabelDetails->isVisible()) {
2544     _calculatedRightLabelMargin = 0;
2545   } else {
2546     painter->save();
2547     QTransform t;
2548     t.rotate(-90.0);
2549     painter->rotate(90.0);
2550 
2551     painter->setFont(rightLabelDetails()->calculatedFont(*painter->device()));
2552 
2553     QRectF rightLabelBound = painter->boundingRect(t.mapRect(rightLabelRect()),
2554         Qt::AlignCenter, rightLabel());
2555     painter->restore();
2556 
2557     _calculatedRightLabelMargin = qMax(_calculatedAxisMarginROverflow, rightLabelBound.height());
2558 
2559     //No more than 1/4 the width of the plot
2560     if (width() < _calculatedRightLabelMargin * 4)
2561       _calculatedRightLabelMargin = width() / 4;
2562   }
2563 }
2564 
2565 
2566 void PlotItem::generateTopLabel(QPainter *p) {
2567   if (!_topLabel.dirty) {
2568     return;
2569   }
2570   _topLabel.valid = false;
2571   _topLabel.dirty = false;
2572   Label::Parsed *parsed = Label::parse(topLabel(), _topLabelDetails->fontColor());
2573   if (parsed && topLabelRect().isValid()) {
2574 
2575     if (_topLabel.rc) {
2576       delete _topLabel.rc;
2577     }
2578 
2579     Label::RenderContext *rc = new Label::RenderContext(topLabelDetails()->calculatedFont(*p->device()), p);
2580     rc->y = rc->fontAscent();
2581     Label::renderLabel(*rc, parsed->chunk, true, false);
2582 
2583     QTransform t;
2584     if (_topLabelDetails->isVisible()) {
2585       t.translate(plotRect().center().x() - rc->x / 2, rect().top());
2586     } else {
2587       t.translate(plotRect().center().x() - rc->x / 2, rect().top() + topLabelRect().height()/2);
2588     }
2589     connect(rc, SIGNAL(labelDirty()), this, SLOT(setTopLabelDirty()));
2590     connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2591 
2592     _topLabel.rc = rc;
2593     _topLabel.transform = t;
2594     _topLabel.valid = true;
2595 
2596     delete parsed;
2597     }
2598 }
2599 
2600 
2601 void PlotItem::paintTopLabel(QPainter *painter) {
2602   if (topLabel().isEmpty())
2603     return;
2604 
2605   generateTopLabel(painter);
2606   if (_topLabel.valid) {
2607     painter->save();
2608     painter->setTransform(_topLabel.transform, true);
2609     Label::paintLabel(*_topLabel.rc, painter);
2610     painter->restore();
2611 
2612   }
2613 }
2614 
2615 
2616 void PlotItem::calculateTopLabelMargin(QPainter *painter) {
2617 
2618   painter->save();
2619 
2620   painter->setFont(topLabelDetails()->calculatedFont(*painter->device()));
2621 
2622   QRectF topLabelBound = painter->boundingRect(topLabelRect(),
2623       Qt::AlignCenter, topLabel());
2624 
2625   painter->restore();
2626 
2627   _calculatedTopLabelHeight = topLabelBound.height();
2628 
2629   if (!_topLabelDetails->isVisible()) {
2630     _calculatedTopLabelMargin = 0;
2631   } else {
2632     _calculatedTopLabelMargin = qMax(_calculatedAxisMarginTOverflow, topLabelBound.height());
2633 
2634     //No more than 1/4 the height of the plot
2635     if (height() < _calculatedTopLabelMargin * 4)
2636       _calculatedTopLabelMargin = height() / 4;
2637   }
2638 }
2639 
2640 
2641 void PlotItem::calculateMargins() {
2642   qreal m = qMax(_calculatedLeftLabelMargin, _calculatedRightLabelMargin);
2643 
2644   //No more than 1/4 the width of the plot
2645   if (width() < m * 4)
2646     m = width() / 4;
2647 
2648   _calculatedLabelMarginWidth = m;
2649 
2650   m = qMax(_calculatedTopLabelMargin, _calculatedBottomLabelMargin);
2651 
2652   //No more than 1/4 the height of the plot
2653   if (height() < m * 4)
2654     m = height() / 4;
2655 
2656   _calculatedLabelMarginHeight = m;
2657 }
2658 
2659 
2660 qreal PlotItem::axisMarginWidth() const {
2661   return _calculatedAxisMarginWidth;
2662 }
2663 
2664 
2665 qreal PlotItem::axisMarginHeight() const {
2666   return _calculatedAxisMarginHeight;
2667 }
2668 
2669 /** This function calculates and sets three things:
2670       _calculatedAxisMarginVLead: spacing between bottom of plotRect and top of axis labels
2671       _calculatedAxisMarginROverflow: rightmost axis number extension beyond plotRect 
2672       _calculatedAxisMarginHeight: the height of the axis numbers
2673 */
2674 void PlotItem::calculateBottomTickLabelBound(QPainter *painter) {
2675   QRectF xLabelRect;
2676 
2677   painter->save();
2678 
2679   painter->setFont(numberLabelDetails()->calculatedFont(*painter->device()));
2680 
2681 
2682   int flags = Qt::TextSingleLine | Qt::AlignCenter;
2683 
2684   _calculatedAxisMarginVLead = painter->fontMetrics().boundingRect('0').height()/2;
2685 
2686   if (_xAxis->isAxisVisible()) {
2687     // future potential optimization: only get bounds of the rightmost label 
2688     // but remember: the axis may be reversed.
2689     QMapIterator<double, QString> xLabelIt(_xAxis->axisLabels());
2690     while (xLabelIt.hasNext()) {
2691       xLabelIt.next();
2692 
2693       QRectF bound = painter->boundingRect(QRectF(), flags, xLabelIt.value());
2694       QPointF p(mapXToPlot(xLabelIt.key()), plotRect().bottom() + bound.height() / 2.0 + _calculatedAxisMarginVLead);
2695       bound.moveCenter(p);
2696 
2697       int rotation = _xAxis->axisLabelRotation();
2698       QTransform t;
2699       t.rotate(rotation);
2700 
2701       if (rotation != 0) {
2702         bound.setHeight(t.mapRect(bound).height());
2703       }
2704 
2705       if (xLabelRect.isValid()) {
2706         xLabelRect = xLabelRect.united(bound);
2707       } else {
2708         xLabelRect = bound;
2709       }
2710     }
2711   }
2712 
2713   xLabelRect.setHeight(xLabelRect.height() + _calculatedAxisMarginVLead);
2714 
2715   if (!_xAxis->baseLabel().isEmpty()) {
2716     qreal height = painter->boundingRect(QRectF(), flags, _xAxis->baseLabel()).height();
2717     if (painter->boundingRect(QRectF(), flags, _xAxis->baseLabel()).width() + _calculatedBottomLabelWidth/2 + xLabelRect.height()/2 > plotRect().width()/2) {
2718       height += bottomLabelMargin();
2719     }
2720     if (bottomLabelMargin() < height) {
2721       xLabelRect.setHeight(xLabelRect.height() + (height - bottomLabelMargin()));
2722     }
2723   }
2724 
2725   _calculatedAxisMarginHeight = xLabelRect.height();
2726   _calculatedAxisMarginROverflow = 2*ViewItem::sizeOfGrip().width();
2727 
2728   painter->restore();
2729 }
2730 
2731 /** This function calculates and sets three things:
2732       _calculatedAxisMarginHLead: spacing between left of plotRect and right of axis labels
2733       _calculatedAxisMarginVOverflow: topmost axis number extension beyond plotRect 
2734       _calculatedAxisMarginWidth: the width of the widest axis number
2735 */
2736 void PlotItem::calculateLeftTickLabelBound(QPainter *painter) {
2737   QRectF yLabelRect;
2738   int flags = Qt::TextSingleLine | Qt::AlignCenter;
2739 
2740   painter->save();
2741 
2742   painter->setFont(numberLabelDetails()->calculatedFont(*painter->device()));
2743 
2744   _calculatedAxisMarginHLead = painter->fontMetrics().boundingRect('[').height()/2;
2745 
2746   if (_yAxis->isAxisVisible()) {
2747 
2748     QMapIterator<double, QString> yLabelIt(_yAxis->axisLabels());
2749     while (yLabelIt.hasNext()) {
2750       yLabelIt.next();
2751 
2752       // a hacky heuristic to guess the right width of the widest number for very small scientific notation numbers.
2753       // 'label' is only used to find its width.  This is not exact but seems to work.
2754       QString label = yLabelIt.value();
2755       if (label.contains("e-")) {
2756         label.append('+');
2757       }
2758 
2759       QRectF bound = painter->boundingRect(QRectF(), flags, label);
2760       QPointF p(plotRect().left() - bound.width() / 2.0 - _calculatedAxisMarginHLead, mapYToPlot(yLabelIt.key()));
2761       bound.moveCenter(p);
2762 
2763       int rotation = _yAxis->axisLabelRotation();
2764       QTransform t;
2765       t.rotate(rotation);
2766 
2767       if (rotation != 0) {
2768         bound.setWidth(t.mapRect(bound).width());
2769         bound.setHeight(t.mapRect(bound).height());
2770       }
2771 
2772       if (yLabelRect.isValid()) {
2773         yLabelRect = yLabelRect.united(bound);
2774       } else {
2775         yLabelRect = bound;
2776       }
2777     }
2778   }
2779 
2780   yLabelRect.setWidth(yLabelRect.width() + _calculatedAxisMarginHLead);
2781   _calculatedLeftBaseOffset = 0.0;
2782   if (!_yAxis->baseLabel().isEmpty()) {
2783     qreal height = painter->boundingRect(QRectF(), flags, _yAxis->baseLabel()).height();
2784     if (painter->boundingRect(QRectF(), flags, _yAxis->baseLabel()).width() + _calculatedLeftLabelWidth/2 + yLabelRect.width()/2 > plotRect().height()/2) {
2785       height += leftLabelMargin();
2786       _calculatedLeftBaseOffset = leftLabelMargin();
2787     }
2788     if (leftLabelMargin() < height) {
2789       yLabelRect.setWidth(yLabelRect.width() + (height - leftLabelMargin()));
2790     }
2791   }
2792   _calculatedAxisMarginWidth = yLabelRect.width();
2793   if (yLabelRect.top() < plotRect().top()) {
2794     _calculatedAxisMarginTOverflow = qMax(ViewItem::sizeOfGrip().width(), -yLabelRect.top() + plotRect().top());
2795   } else {
2796     _calculatedAxisMarginTOverflow = ViewItem::sizeOfGrip().width();
2797   }
2798   painter->restore();
2799 }
2800 
2801 
2802 bool PlotItem::showLegend() const {
2803   return _showLegend;
2804 }
2805 
2806 
2807 LegendItem* PlotItem::legend() {
2808   if (!_legend) {
2809     _legend = new LegendItem(this);
2810     _legend->setVisible(false);
2811     double margin = 0.025*(plotRect().width() + plotRect().height());
2812     _legend->setPos(plotRect().x() + margin, plotRect().y() + margin);
2813     _legend->updateRelativeSize();
2814   }
2815   return _legend;
2816 }
2817 
2818 
2819 void PlotItem::setShowLegend(const bool show, const bool resetFonts) {
2820   if (show != _showLegend) {
2821     legend()->setVisible(show);
2822     _showLegend = show;
2823     if (show && resetFonts) {
2824       legend()->setFontScale(qMax(globalFontScale()*qreal(0.6), ApplicationSettings::self()->minimumFontSize()));
2825     }
2826   }
2827 }
2828 
2829 
2830 bool PlotItem::tryShortcut(const QString &keySequence) {
2831   return ViewItem::tryShortcut(keySequence);
2832 }
2833 
2834 
2835 void PlotItem::setProjectionRect(const QRectF &rect, bool forceAxisUpdate) {
2836   if (!(rect.isEmpty() || !rect.isValid())) {
2837     _projectionRect = rect;
2838     setPlotBordersDirty(true);
2839     emit updateAxes();
2840     update(); //slow, but need to update everything...
2841   } else if (forceAxisUpdate) {
2842     setPlotBordersDirty(true);
2843     emit updateAxes();
2844     update(); //slow, but need to update everything...
2845   }
2846   // Need to update data relative rect for all children.
2847   foreach (PlotRenderItem *render_item, renderItems()) {
2848     QList<QGraphicsItem*> children = render_item->childItems();
2849     foreach(QGraphicsItem* child, children) {
2850       ViewItem* item = dynamic_cast<ViewItem*>(child);
2851       if (item && !item->lockPosToData()) {
2852         item->updateDataRelativeRect();
2853       } else {
2854         item->applyDataLockedDimensions();
2855       }
2856     }
2857   }
2858 }
2859 
2860 
2861 QRectF PlotItem::computedProjectionRect() {
2862   QRectF rect;
2863   foreach (PlotRenderItem *renderer, renderItems()) {
2864     if (!renderer->computedProjectionRect().isEmpty()) {
2865       if (rect.isValid()) {
2866         rect = rect.united(renderer->computedProjectionRect());
2867       } else {
2868         rect = renderer->computedProjectionRect();
2869       }
2870     }
2871   }
2872 
2873   if (!rect.isValid())
2874     rect = QRectF(QPointF(-0.1, -0.1), QPointF(0.1, 0.1)); //default
2875 
2876   return rect;
2877 }
2878 
2879 
2880 void PlotItem::computedRelationalMax(double &minimum, double &maximum) {
2881   //QRectF rect;
2882   foreach (PlotRenderItem *renderer, renderItems()) {
2883     foreach (RelationPtr relation, renderer->relationList()) {
2884       if (relation->ignoreAutoScale())
2885         continue;
2886 
2887       double min, max;
2888       relation->yRange(projectionRect().left(),
2889           projectionRect().right(),
2890           &min, &max);
2891 
2892       //If the axis is in log mode, the lower extent will be the
2893       //minimum value larger than zero.
2894       if (yAxis()->axisLog())
2895         minimum = minimum <= 0.0 ? min : qMin(min, minimum);
2896       else
2897         minimum = qMin(min, minimum);
2898 
2899       maximum = qMax(max, maximum);
2900     }
2901   }
2902 }
2903 
2904 
2905 void PlotItem::computeBorder(Qt::Orientation orientation, double &minimum, double &maximum) const {
2906   //QRectF rect;
2907   foreach (PlotRenderItem *renderer, renderItems()) {
2908     double min = maximum;
2909     double max = minimum;
2910     renderer->computeBorder(orientation, &min, &max);
2911     minimum = qMin(min, minimum);
2912     maximum = qMax(max, maximum);
2913   }
2914 }
2915 
2916 
2917 void PlotItem::resetSelectionRect() {
2918   foreach (PlotRenderItem *renderer, renderItems()) {
2919     renderer->resetSelectionRect();
2920   }
2921 }
2922 
2923 
2924 void PlotItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
2925   if (event->button() == Qt::LeftButton) {
2926     if (checkBox().contains(event->pos())) {
2927       setTiedZoom(!isTiedZoom(), !isTiedZoom());
2928       ViewItem::mousePressEvent(event);
2929     } else {
2930       ViewItem::mousePressEvent(event);
2931     }
2932   } 
2933 }
2934 
2935 
2936 void PlotItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
2937   if (event->button() == Qt::LeftButton && view()->viewMode() == View::Data) {
2938     PlotClickEditRegion region = CONTENT;
2939     if (event->pos().x() - rect().left() < leftLabelMargin()) {
2940       region = LABEL;
2941     } else if (event->pos().y() - rect().top()< topLabelMargin()) {
2942       region = LABEL;
2943     } else if (rect().right()-event->pos().x() < rightLabelMargin()) {
2944       region = LABEL;
2945     } else if (rect().bottom()-event->pos().y() < bottomLabelMargin()) {
2946       region = LABEL;
2947     } else if (rect().bottom()-event->pos().y() < bottomMarginSize()) {
2948       region = XAXIS;
2949     } else if (event->pos().x() - rect().left() < leftMarginSize()) {
2950       region = YAXIS;
2951     }
2952     edit(region);
2953   } else {
2954     ViewItem::mouseDoubleClickEvent(event);
2955   }
2956 }
2957 
2958 
2959 QPainterPath PlotItem::checkBox() const {
2960   if (!isInSharedAxisBox() || (sharedAxisBox() && sharedAxisBox()->isXAxisShared() && sharedAxisBox()->isYAxisShared())) {
2961     return ViewItem::checkBox();
2962   } else {
2963     QRectF grip;
2964     if (sharedAxisBox()->isXAxisShared()) {
2965       grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() + sizeOfGrip().width() * .25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * -.25), sizeOfGrip());
2966     } else if (sharedAxisBox()->isYAxisShared()) {
2967       grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() - sizeOfGrip().width() * 1.25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * 1.25), sizeOfGrip());
2968     }
2969     QPainterPath path;
2970     path.addEllipse(grip);
2971     return path;
2972   }
2973 }
2974 
2975 
2976 QPainterPath PlotItem::tiedZoomCheck() const {
2977   if (!isInSharedAxisBox() || (sharedAxisBox() && sharedAxisBox()->isXAxisShared() && sharedAxisBox()->isYAxisShared())) {
2978     return ViewItem::tiedZoomCheck();
2979   } else {
2980     QRectF grip;
2981     if (sharedAxisBox()->isXAxisShared()) {
2982       grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() + sizeOfGrip().width() * .25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * -.25), sizeOfGrip());
2983     } else if (sharedAxisBox()->isYAxisShared()) {
2984       grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() - sizeOfGrip().width() * 1.25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * 1.25), sizeOfGrip());
2985     } else {
2986       qDebug() << "warning: no grip set in PlotItem::tiedZoomCheck  (bug?)";
2987     }
2988     QPainterPath path;
2989     if (isXTiedZoom() && isYTiedZoom()) {
2990       path.addEllipse(grip);
2991     } else if (isXTiedZoom()) {
2992       path.moveTo(grip.center());
2993       path.arcTo(grip, 225, 180);
2994     } else if (isYTiedZoom()) {
2995       path.moveTo(grip.center());
2996       path.arcTo(grip, 45, 180);
2997     }
2998     return path;
2999   }
3000 }
3001 
3002 
3003 bool PlotItem::supportsTiedZoom() const {
3004   if (isInSharedAxisBox()) {
3005     if (sharedAxisBox() && sharedAxisBox()->isXAxisShared() && sharedAxisBox()->isYAxisShared() &&
3006         sharedAxisBox()->keyPlot() == this) {
3007       return true;
3008     }
3009   }
3010   return ViewItem::supportsTiedZoom();
3011 }
3012 
3013 
3014 void PlotItem::setAllowUpdates(bool allowed) {
3015   _allowUpdates = allowed;
3016   UpdateManager::self()->doUpdates(true);
3017 }
3018 
3019 
3020 void PlotItem::plotMaximize() {
3021   if (!_plotMaximized && view()->viewMode() != View::Data) {
3022     return;
3023   }
3024 
3025   if (_plotMaximized) {
3026     double x_rescale;
3027     double y_rescale;
3028 
3029     x_rescale = view()->sceneRect().width()/_plotMaximizedSourceParentRect.width();
3030     y_rescale = view()->sceneRect().height()/_plotMaximizedSourceParentRect.height();
3031     _plotMaximizedSourceRect.setWidth(_plotMaximizedSourceRect.width()*x_rescale);
3032     _plotMaximizedSourceRect.setHeight(_plotMaximizedSourceRect.height()*y_rescale);
3033     _plotMaximizedSourcePosition.setX(_plotMaximizedSourcePosition.x()*x_rescale);
3034     _plotMaximizedSourcePosition.setY(_plotMaximizedSourcePosition.y()*y_rescale);
3035     xAxis()->setAxisVisible(_plotMaximizedBottomVisible);
3036     yAxis()->setAxisVisible(_plotMaximizedLeftVisible);
3037     _leftLabelDetails->setVisible(_plotMaximizedLeftVisible);
3038     _bottomLabelDetails->setVisible(_plotMaximizedBottomVisible);
3039     _rightLabelDetails->setVisible(_plotMaximizedRightVisible);
3040     _topLabelDetails->setVisible(_plotMaximizedTopVisible);
3041     _plotMaximized = false;
3042     PlotItemManager::self()->removeFocusPlot(this);
3043     setParentViewItem(_plotMaximizedSourceParent);
3044     setPos(_plotMaximizedSourcePosition);
3045     setViewRect(_plotMaximizedSourceRect);
3046     setZValue(_plotMaximizedSourceZValue);
3047     view()->setChildMaximized(false);
3048     view()->setFontRescale(1.0);
3049   } else {
3050     _plotMaximizedBottomVisible = _bottomLabelDetails->isVisible();
3051     xAxis()->setAxisVisible(true);
3052     _bottomLabelDetails->setVisible(true);
3053     _plotMaximizedLeftVisible = _leftLabelDetails->isVisible();
3054     yAxis()->setAxisVisible(true);
3055     _leftLabelDetails->setVisible(true);
3056     _plotMaximizedRightVisible = _rightLabelDetails->isVisible();
3057     _rightLabelDetails->setVisible(true);
3058     _plotMaximizedTopVisible = _topLabelDetails->isVisible();
3059     _topLabelDetails->setVisible(true);
3060     _plotMaximized = true;
3061     _plotMaximizedSourcePosition = pos();
3062     _plotMaximizedSourceRect = viewRect();
3063     _plotMaximizedSourceZValue = zValue();
3064     _plotMaximizedSourceParent = parentViewItem();
3065     _plotMaximizedSourceParentRect = view()->sceneRect();
3066 
3067     setParentViewItem(0);
3068     setPos(0, 0);
3069     setViewRect(view()->sceneRect());
3070     setZValue(PLOT_MAXIMIZED_ZORDER);
3071     PlotItemManager::self()->setFocusPlot(this);
3072 
3073     double rescale = double(view()->sceneRect().width() +
3074                             view()->sceneRect().height())/
3075                      double(_plotMaximizedSourceRect.width() + _plotMaximizedSourceRect.height());
3076     view()->setChildMaximized(true);
3077     view()->setFontRescale(rescale);
3078   }
3079   if (isInSharedAxisBox()) {
3080     view()->setPlotBordersDirty(true);
3081   }
3082   setPlotBordersDirty();
3083 }
3084 
3085 
3086 void PlotItem::zoomFixedExpression(const QRectF &projection, bool force) {
3087   if (projection.isValid()) {
3088     if (isInSharedAxisBox()) {
3089       ZoomCommand *cmd = new ZoomFixedExpressionCommand(this, projection, force);
3090       _undoStack->push(cmd);
3091       // cmd->redo();
3092       if (!force) {
3093         sharedAxisBox()->zoomFixedExpression(projection, this);
3094       } else {
3095         yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3096         xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3097         setProjectionRect(QRectF(projection.x(), projection.y(), projection.width(), projection.height()));
3098       }
3099     } else {
3100       ZoomCommand *cmd = new ZoomFixedExpressionCommand(this, projection, force);
3101       _undoStack->push(cmd);
3102       // cmd->redo();
3103     }
3104   }
3105 }
3106 
3107 
3108 void PlotItem::zoomXRange(const QRectF &projection, bool force) {
3109   if (projection.isValid()) {
3110     if (isInSharedAxisBox()) {
3111       if (!force) {
3112         sharedAxisBox()->zoomXRange(projection, this);
3113       } else {
3114         xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3115         setProjectionRect(QRectF(projection.x(), projectionRect().y(), projection.width(), projectionRect().height()));
3116       }
3117     } else {
3118       ZoomCommand *cmd = new ZoomXRangeCommand(this, projection, force);
3119       _undoStack->push(cmd);
3120       // cmd->redo();
3121     }
3122   }
3123 }
3124 
3125 
3126 void PlotItem::zoomYRange(const QRectF &projection, bool force) {
3127   if (projection.isValid()) {
3128     if (isInSharedAxisBox()) {
3129       if (!force) {
3130         sharedAxisBox()->zoomYRange(projection, this);
3131       } else {
3132         yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3133         setProjectionRect(QRectF(projectionRect().x(), projection.y(), projectionRect().width(), projection.height()));
3134       }
3135     } else {
3136       ZoomCommand *cmd = new ZoomYRangeCommand(this, projection, force);
3137       _undoStack->push(cmd);
3138       // cmd->redo();
3139     }
3140   }
3141 }
3142 
3143 
3144 void PlotItem::zoomMaximum(bool force) {
3145   if (isInSharedAxisBox() && (!force)) {
3146     sharedAxisBox()->zoomMaximum(this);
3147   } else {
3148     ZoomCommand *cmd = new ZoomMaximumCommand(this, force);
3149     _undoStack->push(cmd);
3150     //cmd->redo();
3151   }
3152 }
3153 
3154 void PlotItem::adjustImageColorScale() {
3155   const double per[] = {0.0, 0.0001, 0.001, 0.005, 0.02, 0.1};
3156   const int length = sizeof(per) / sizeof(double);
3157 
3158   if (++_i_per >= length) {
3159     _i_per = 0;
3160   }
3161   foreach (PlotRenderItem *renderer, renderItems()) {
3162     foreach (RelationPtr relation, renderer->relationList()) {
3163       if (ImagePtr image = kst_cast<Image>(relation)) {
3164         image->writeLock();
3165         image->setThresholdToSpikeInsensitive(per[_i_per]);
3166         image->registerChange();
3167         image->unlock();
3168       }
3169     }
3170   }
3171   UpdateManager::self()->doUpdates(true);
3172 }
3173 
3174 void PlotItem::zoomMaxSpikeInsensitive(bool force) {
3175   if (isInSharedAxisBox() && !force) {
3176     sharedAxisBox()->zoomMaxSpikeInsensitive(this);
3177   } else {
3178     ZoomCommand *cmd = new ZoomMaxSpikeInsensitiveCommand(this, force);
3179     _undoStack->push(cmd);
3180     //cmd->redo();
3181   }
3182 }
3183 
3184 
3185 void PlotItem::zoomPrevious() {
3186   if (!isInSharedAxisBox()) {
3187     if (_undoStack->canUndo()) {
3188       QAction *undoAction = _undoStack->createUndoAction(this);
3189       if (undoAction) {
3190         undoAction->activate(QAction::Trigger);
3191       }
3192     }
3193   }
3194 }
3195 
3196 
3197 void PlotItem::zoomTied() {
3198   setTiedZoom(!isTiedZoom(), !isTiedZoom());
3199 }
3200 
3201 
3202 void PlotItem::zoomXTied() {
3203   setTiedZoom(!isXTiedZoom(), isYTiedZoom());
3204 }
3205 
3206 
3207 void PlotItem::zoomYTied() {
3208   setTiedZoom(isXTiedZoom(), !isYTiedZoom());
3209 }
3210 
3211 
3212 void PlotItem::zoomMeanCentered(bool force) {
3213   if (isInSharedAxisBox() && !force) {
3214     sharedAxisBox()->zoomMeanCentered(this);
3215   } else {
3216     ZoomCommand *cmd = new ZoomMeanCenteredCommand(this, force);
3217     _undoStack->push(cmd);
3218     // cmd->redo();
3219   }
3220 }
3221 
3222 
3223 void PlotItem::zoomYMeanCentered(qreal dY, bool force) {
3224   if (isInSharedAxisBox() && !force) {
3225     sharedAxisBox()->zoomYMeanCentered(dY, this);
3226   } else {
3227     ZoomCommand *cmd = new ZoomYMeanCenteredCommand(this, dY, force);
3228     _undoStack->push(cmd);
3229     // cmd->redo();
3230   }
3231 }
3232 
3233 
3234 void PlotItem::zoomXMeanCentered(qreal dX, bool force) {
3235   if (isInSharedAxisBox() && !force) {
3236     sharedAxisBox()->zoomXMeanCentered(this);
3237   } else {
3238     ZoomCommand *cmd = new ZoomXMeanCenteredCommand(this, dX, force);
3239     _undoStack->push(cmd);
3240     // cmd->redo();
3241   }
3242 }
3243 
3244 
3245 void PlotItem::zoomXMaximum(bool force) {
3246   if (isInSharedAxisBox() && !force) {
3247     sharedAxisBox()->zoomXMaximum(this);
3248   } else {
3249     ZoomCommand *cmd = new ZoomXMaximumCommand(this, force);
3250     _undoStack->push(cmd);
3251     // cmd->redo();
3252   }
3253 }
3254 
3255 
3256 void PlotItem::zoomXNoSpike(bool force) {
3257   if (isInSharedAxisBox() && !force) {
3258     sharedAxisBox()->zoomXNoSpike(this);
3259   } else {
3260     ZoomCommand *cmd = new ZoomXNoSpikeCommand(this, force);
3261     _undoStack->push(cmd);
3262     // cmd->redo();
3263   }
3264 }
3265 
3266 
3267 void PlotItem::zoomXAutoBorder(bool force) {
3268   if (isInSharedAxisBox() && !force) {
3269     sharedAxisBox()->zoomXAutoBorder(this);
3270   } else {
3271     ZoomCommand *cmd = new ZoomXAutoBorderCommand(this, force);
3272     _undoStack->push(cmd);
3273     // cmd->redo();
3274   }
3275 }
3276 
3277 
3278 void PlotItem::zoomXRight(bool force, bool scroll_far) {
3279   if (isInSharedAxisBox() && !force) {
3280     sharedAxisBox()->zoomXRight(this, scroll_far);
3281   } else {
3282     ZoomCommand *cmd;
3283     if (scroll_far) {
3284       cmd = new ZoomXFarRightCommand(this, force);
3285     } else {
3286       cmd = new ZoomXRightCommand(this, force);
3287     }
3288     _undoStack->push(cmd);
3289     //cmd->redo();
3290   }
3291 }
3292 
3293 
3294 void PlotItem::zoomXLeft(bool force, bool scroll_far) {
3295   if (isInSharedAxisBox() && !force) {
3296     sharedAxisBox()->zoomXLeft(this, scroll_far);
3297   } else {
3298     ZoomCommand *cmd;
3299     if (scroll_far) {
3300       cmd = new ZoomXFarLeftCommand(this, force);
3301     } else {
3302       cmd = new ZoomXLeftCommand(this, force);
3303     }
3304     _undoStack->push(cmd);
3305     //cmd->redo();
3306   }
3307 }
3308 
3309 
3310 void PlotItem::zoomXFarRight(bool force) {
3311   zoomXRight(force, true);
3312 }
3313 
3314 void PlotItem::zoomXFarLeft(bool force) {
3315   zoomXLeft(force, true);
3316 }
3317 
3318 void PlotItem::zoomXOut(bool force) {
3319   resetSelectionRect();
3320   if (isInSharedAxisBox() && !force) {
3321     sharedAxisBox()->zoomXOut(this);
3322   } else {
3323     ZoomCommand *cmd = new ZoomXOutCommand(this, force);
3324     _undoStack->push(cmd);
3325     // cmd->redo();
3326   }
3327 }
3328 
3329 
3330 void PlotItem::zoomXIn(bool force) {
3331   resetSelectionRect();
3332   if (isInSharedAxisBox() && !force) {
3333     sharedAxisBox()->zoomXIn(this);
3334   } else {
3335     ZoomCommand *cmd = new ZoomXInCommand(this, force);
3336     _undoStack->push(cmd);
3337     // cmd->redo();
3338   }
3339 }
3340 
3341 
3342 void PlotItem::zoomNormalizeXtoY(bool force) {
3343   if (xAxis()->axisLog() || yAxis()->axisLog())
3344     return; //FIXME: if both are log, this could be supported
3345 
3346   if (isInSharedAxisBox() && !force) {
3347     sharedAxisBox()->zoomNormalizeXtoY(this);
3348   } else {
3349     ZoomCommand *cmd = new ZoomNormalizeXToYCommand(this, force);
3350     _undoStack->push(cmd);
3351     // cmd->redo();
3352   }
3353 }
3354 
3355 
3356 void PlotItem::zoomLogX(bool force, bool autoLog, bool enableLog) {
3357   if (isInSharedAxisBox() && !force) {
3358     sharedAxisBox()->zoomLogX(this);
3359   } else {
3360     bool log = enableLog;
3361     if (autoLog) {
3362       log = !xAxis()->axisLog();
3363     }
3364     ZoomCommand *cmd = new ZoomXLogCommand(this, log, force);
3365     _undoStack->push(cmd);
3366     // cmd->redo();
3367   }
3368 }
3369 
3370 
3371 void PlotItem::zoomYLocalMaximum(bool force) {
3372   if (isInSharedAxisBox() && !force) {
3373     sharedAxisBox()->zoomYLocalMaximum(this);
3374   } else {
3375     ZoomCommand *cmd = new ZoomYLocalMaximumCommand(this, force);
3376     _undoStack->push(cmd);
3377     // cmd->redo();
3378   }
3379 }
3380 
3381 
3382 void PlotItem::zoomYMaximum(bool force) {
3383   if (isInSharedAxisBox() && !force) {
3384     sharedAxisBox()->zoomYMaximum(this);
3385   } else {
3386     ZoomCommand *cmd = new ZoomYMaximumCommand(this, force);
3387     _undoStack->push(cmd);
3388     // cmd->redo();
3389   }
3390 }
3391 
3392 
3393 void PlotItem::zoomYNoSpike(bool force) {
3394   if (isInSharedAxisBox() && !force) {
3395     sharedAxisBox()->zoomYNoSpike(this);
3396   } else {
3397     ZoomCommand *cmd = new ZoomYNoSpikeCommand(this, force);
3398     _undoStack->push(cmd);
3399     // cmd->redo();
3400   }
3401 }
3402 
3403 
3404 void PlotItem::zoomYAutoBorder(bool force) {
3405   if (isInSharedAxisBox() && !force) {
3406     sharedAxisBox()->zoomYAutoBorder(this);
3407   } else {
3408     ZoomCommand *cmd = new ZoomYAutoBorderCommand(this, force);
3409     _undoStack->push(cmd);
3410     // cmd->redo();
3411   }
3412 }
3413 
3414 
3415 void PlotItem::zoomYUp(bool force) {
3416   if (isInSharedAxisBox() && !force) {
3417     sharedAxisBox()->zoomYUp(this);
3418   } else {
3419     ZoomCommand *cmd = new ZoomYUpCommand(this, force);
3420     _undoStack->push(cmd);
3421     // cmd->redo();
3422   }
3423 }
3424 
3425 
3426 void PlotItem::zoomYDown(bool force) {
3427   if (isInSharedAxisBox() && !force) {
3428     sharedAxisBox()->zoomYDown(this);
3429   } else {
3430     ZoomCommand *cmd = new ZoomYDownCommand(this, force);
3431     _undoStack->push(cmd);
3432     //cmd->redo();
3433   }
3434 }
3435 
3436 
3437 void PlotItem::zoomYOut(bool force) {
3438   resetSelectionRect();
3439   if (isInSharedAxisBox() && !force) {
3440     sharedAxisBox()->zoomYOut(this);
3441   } else {
3442     ZoomCommand *cmd = new ZoomYOutCommand(this, force);
3443     _undoStack->push(cmd);
3444     // cmd->redo();
3445   }
3446 }
3447 
3448 
3449 void PlotItem::zoomYIn(bool force) {
3450   resetSelectionRect();
3451   if (isInSharedAxisBox() && !force) {
3452     sharedAxisBox()->zoomYIn(this);
3453   } else {
3454     ZoomCommand *cmd = new ZoomYInCommand(this, force);
3455     _undoStack->push(cmd);
3456     // cmd->redo();
3457   }
3458 }
3459 
3460 
3461 void PlotItem::zoomNormalizeYtoX(bool force) {
3462   if (xAxis()->axisLog() || yAxis()->axisLog())
3463     return; //apparently we don't want to do anything here according to kst2dplot...
3464 
3465   if (isInSharedAxisBox() && !force) {
3466     sharedAxisBox()->zoomNormalizeYtoX(this);
3467   } else {
3468     ZoomCommand *cmd = new ZoomNormalizeYToXCommand(this, force);
3469     _undoStack->push(cmd);
3470     // cmd->redo();
3471   }
3472 }
3473 
3474 
3475 void PlotItem::zoomLogY(bool force, bool autoLog, bool enableLog) {
3476   if (isInSharedAxisBox() && !force) {
3477     sharedAxisBox()->zoomLogY(this);
3478   } else {
3479     bool log = enableLog;
3480     if (autoLog) {
3481       log = !yAxis()->axisLog();
3482     }
3483     ZoomCommand *cmd = new ZoomYLogCommand(this, log, force);
3484     _undoStack->push(cmd);
3485     // cmd->redo();
3486   }
3487 }
3488 
3489 void PlotItem::zoomOut(bool force) {
3490   zoomYOut(force);
3491   zoomXOut(force);
3492 }
3493 
3494 void PlotItem::zoomIn(bool force) {
3495   zoomYIn(force);
3496   zoomXIn(force);
3497 }
3498 
3499 void PlotItem::copyStatus() {
3500   kstApp->clipboard()->setText(kstApp->mainWindow()->statusMessage());
3501   kstApp->mainWindow()->setStatusMessage(tr("Info copied to clipboard: ") + kstApp->mainWindow()->statusMessage());
3502 }
3503 
3504 void PlotItem::copyXCoord() {
3505   QString valueString = QString::number(renderItem()->statusMessagePoint.x(), 'g', 12);
3506   kstApp->clipboard()->setText(valueString);
3507   kstApp->mainWindow()->setStatusMessage(tr("X coordinate copied to clipboard: ") + valueString);
3508 }
3509 
3510 void PlotItem::copyYCoord() {
3511   QString valueString = QString::number(renderItem()->statusMessagePoint.y(), 'g', 12);
3512   kstApp->clipboard()->setText(valueString);
3513   kstApp->mainWindow()->setStatusMessage(tr("Y coordinate copied to clipboard: ") + valueString);
3514 }
3515 
3516 QString PlotItem::descriptionTip() const {
3517   QString contents;
3518   foreach (PlotRenderItem *renderer, renderItems()) {
3519     foreach (RelationPtr relation, renderer->relationList()) {
3520       contents += QString("  %1\n").arg(relation->Name());
3521     }
3522   }
3523 
3524   return tr("Plot: %1 \nContents:\n %2").arg(Name()).arg(contents);
3525 }
3526 
3527 
3528 QString PlotItem::_automaticDescriptiveName() const {
3529   QString name = tr("Empty Plot");
3530   int n=0;
3531   foreach (PlotRenderItem *renderer, renderItems()) {
3532     foreach (RelationPtr relation, renderer->relationList()) {
3533       if (n==0) {
3534         name = relation->descriptiveName();
3535       }
3536       n++;
3537     }
3538   }
3539   if (n>1) {
3540     name += ", ...";
3541   }
3542   return name;
3543 }
3544 
3545 
3546 ZoomState PlotItem::currentZoomState() {
3547   ZoomState zoomState;
3548   zoomState.item = this; //the origin of this ZoomState
3549   zoomState.projectionRect = projectionRect();
3550   zoomState.xAxisZoomMode = xAxis()->axisZoomMode();
3551   zoomState.yAxisZoomMode = yAxis()->axisZoomMode();
3552   zoomState.isXAxisLog = xAxis()->axisLog();
3553   zoomState.isYAxisLog = yAxis()->axisLog();
3554   return zoomState;
3555 }
3556 
3557 
3558 void PlotItem::setCurrentZoomState(ZoomState zoomState) {
3559   _xAxis->setAxisZoomMode(PlotAxis::ZoomMode(zoomState.xAxisZoomMode));
3560   _yAxis->setAxisZoomMode(PlotAxis::ZoomMode(zoomState.yAxisZoomMode));
3561   _xAxis->setAxisLog(zoomState.isXAxisLog);
3562   _yAxis->setAxisLog(zoomState.isYAxisLog);
3563   setProjectionRect(zoomState.projectionRect);
3564 }
3565 
3566 
3567 void PlotItem::updateChildGeometry(const QRectF &oldParentRect, const QRectF &newParentRect) {
3568   ViewItem::updateChildGeometry(oldParentRect, newParentRect);
3569   setPlotBordersDirty(true);
3570   setLabelsDirty();
3571   setAxisLabelsDirty();
3572   setPlotPixmapDirty();
3573 }
3574 
3575 void PlotItem::saveAsDialogDefaults() const {
3576   dialogDefaults().setValue(defaultsGroupName()+"/globalFontFamily", QVariant(globalFont()).toString());
3577   dialogDefaults().setValue(defaultsGroupName()+"/globalFontScale",globalFontScale());
3578   dialogDefaults().setValue(defaultsGroupName()+"/globalFontColor", QVariant(globalFontColor()).toString());
3579 
3580   leftLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/leftFont"));
3581   rightLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/rightFont"));
3582   topLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/topFont"));
3583   bottomLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/bottomFont"));
3584   numberLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/numberFont"));
3585 
3586   _xAxis->saveAsDialogDefaults(defaultsGroupName()+"/xAxis");
3587   _yAxis->saveAsDialogDefaults(defaultsGroupName()+"/yAxis");
3588 }
3589 
3590 void PlotItem::saveDialogDefaultsFont(QFont F, QColor C) {
3591   dialogDefaults().setValue(staticDefaultsGroupName()+"/globalFontFamily", QVariant(F).toString());
3592   dialogDefaults().setValue(staticDefaultsGroupName()+"/globalFontScale",F.pointSize());
3593   dialogDefaults().setValue(staticDefaultsGroupName()+"/globalFontColor", QVariant(C).toString());
3594 
3595   PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/leftFont", F, C, true);
3596   PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/rightFont", F, C, true);
3597   PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/topFont", F, C, true);
3598   PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/bottomFont", F, C, true);
3599   PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/numberFont", F, C, true);
3600 }
3601 
3602 void PlotItem::setFont(const QFont &f, const QColor &c) {
3603   leftLabelDetails()->setFontUseGlobal(true);
3604   rightLabelDetails()->setFontUseGlobal(true);
3605   topLabelDetails()->setFontUseGlobal(true);
3606   bottomLabelDetails()->setFontUseGlobal(true);
3607   numberLabelDetails()->setFontUseGlobal(true);
3608   setGlobalFontColor(c);
3609   setGlobalFont(f);
3610   setGlobalFontScale(f.pointSize());
3611   leftLabelDetails()->setFontColor(c);
3612   rightLabelDetails()->setFontColor(c);
3613   topLabelDetails()->setFontColor(c);
3614   bottomLabelDetails()->setFontColor(c);
3615   numberLabelDetails()->setFontColor(c);
3616 }
3617 
3618 
3619 PlotLabel::PlotLabel(PlotItem *plotItem) : QObject(),
3620   _plotItem(plotItem),
3621   _visible(true),
3622   _fontScale(12),
3623   _fontUseGlobal(true),
3624   _isAuto(true) {
3625 
3626 }
3627 
3628 
3629 void PlotLabel::setDetails(const QString &label, bool is_auto,
3630                            const bool use_global, const QFont &font, 
3631                            const qreal scale, const QColor &color) {
3632   if ((label != _text) || (_isAuto != is_auto) ||
3633       (use_global != _fontUseGlobal) ||
3634       (font != _font) ||
3635       (scale != _fontScale) ||
3636       (color != _fontColor)) {
3637     _text = label;
3638     _isAuto = is_auto;
3639     _fontUseGlobal = use_global;
3640     _font = font;
3641     _fontScale = scale;
3642     _fontColor = color;
3643     emit labelChanged();
3644   }
3645 }
3646 
3647 
3648 QFont PlotLabel::calculatedFont(const QPaintDevice &p) {
3649   QFont tempFont;
3650   if (fontUseGlobal()) {
3651     tempFont = _plotItem->globalFont();
3652     tempFont.setPointSizeF(_plotItem->view()->scaledFontSize(_plotItem->globalFontScale(),p));
3653   } else {
3654     tempFont = font();
3655     tempFont.setPointSizeF(_plotItem->view()->scaledFontSize(fontScale(),p));
3656   }
3657   return tempFont;
3658 }
3659 
3660 
3661 bool PlotLabel::isVisible() const {
3662   return _visible;
3663 }
3664 
3665 
3666 void PlotLabel::setVisible(bool visible) {
3667   if (_visible == visible)
3668     return;
3669 
3670   _visible = visible;
3671   emit labelChanged();
3672 }
3673 
3674 
3675 bool PlotLabel::fontUseGlobal() const {
3676   return _fontUseGlobal; 
3677 }
3678 
3679 
3680 void PlotLabel::setFontUseGlobal(const bool use_global) {
3681   if (_fontUseGlobal == use_global)
3682     return;
3683 
3684   _fontUseGlobal = use_global;
3685   emit labelChanged();
3686 }
3687 
3688 
3689 QString PlotLabel::text() const {
3690   return _text;
3691 }
3692 
3693 
3694 void PlotLabel::setText(const QString &label) {
3695   if (label == _text) {
3696     return;
3697   }
3698   _text = label;
3699   emit labelChanged();
3700 }
3701 
3702 qreal PlotLabel::fontScale() const {
3703   return _fontScale;
3704 }
3705 
3706 
3707 void PlotLabel::setFontScale(const qreal scale) {
3708   if (scale != _fontScale) {
3709     _fontScale = scale;
3710     emit labelChanged();
3711   }
3712 }
3713 
3714 
3715 QFont PlotLabel::font() const {
3716   return _font;
3717 }
3718 
3719 
3720 void PlotLabel::setFont(const QFont &font) {
3721   if (font != _font) {
3722     _font = font;
3723     emit labelChanged();
3724   }
3725 }
3726 
3727 
3728 QColor PlotLabel::fontColor() const {
3729   return _fontColor;
3730 }
3731 
3732 
3733 void PlotLabel::setFontColor(const QColor &color) {
3734   if (color != _fontColor) {
3735     _fontColor = color;
3736     emit labelChanged();
3737   }
3738 }
3739 
3740 
3741 void PlotLabel::saveInPlot(QXmlStreamWriter &xml, QString labelId) {
3742   xml.writeStartElement("plotlabel");
3743   xml.writeAttribute("id", labelId);
3744   xml.writeAttribute("visible", QVariant(_visible).toString());
3745   xml.writeAttribute("overridetext", _text);
3746   xml.writeAttribute("autolabel", QVariant(_isAuto).toString());
3747   xml.writeAttribute("font", QVariant(_font).toString());
3748   xml.writeAttribute("fontscale", QVariant(_fontScale).toString());
3749   xml.writeAttribute("fontcolor", QVariant(_fontColor).toString());
3750   xml.writeAttribute("fontuseglobal", QVariant(_fontUseGlobal).toString());
3751   xml.writeEndElement();
3752 }
3753 
3754 
3755 bool PlotLabel::configureFromXml(QXmlStreamReader &xml, ObjectStore *store) {
3756   Q_UNUSED(store);
3757   bool validTag = true;
3758 
3759   QString primaryTag = xml.name().toString();
3760   QXmlStreamAttributes attrs = xml.attributes();
3761   QStringRef av = attrs.value("visible");
3762   if (!av.isNull()) {
3763     setVisible(QVariant(av.toString()).toBool());
3764   }
3765   av = attrs.value("overridetext");
3766   if (!av.isNull()) {
3767     setText(av.toString());
3768   }
3769   av = attrs.value("autolabel");
3770   if (!av.isNull()) {
3771     setIsAuto(QVariant(av.toString()).toBool());
3772   }
3773   av = attrs.value("fontuseglobal");
3774   if (!av.isNull()) {
3775     setFontUseGlobal(QVariant(av.toString()).toBool());
3776   }
3777   av = attrs.value("font");
3778   if (!av.isNull()) {
3779     QFont font;
3780     font.fromString(av.toString());
3781     setFont(font);
3782   }
3783   av = attrs.value("fontcolor");
3784   if (!av.isNull()) {
3785     setFontColor(QColor(av.toString()));
3786   }
3787   av = attrs.value("fontscale");
3788   if (!av.isNull()) {
3789     setFontScale(QVariant(av.toString()).toDouble());
3790   }
3791 
3792   QString expectedEnd;
3793   while (!(xml.isEndElement() && (xml.name().toString() == primaryTag))) {
3794     if (xml.isEndElement()) {
3795       if (xml.name().toString() != expectedEnd) {
3796         validTag = false;
3797         break;
3798       }
3799     }
3800     xml.readNext();
3801   }
3802 
3803   return validTag;
3804 }
3805 
3806 void PlotLabel::saveAsDialogDefaults(const QString &group) const {
3807   QFont F = font();
3808   F.setPointSize(fontScale());
3809   PlotLabel::saveDialogDefaults(group, F, fontColor(), fontUseGlobal());
3810 }
3811 
3812 void PlotLabel::saveDialogDefaults(const QString &group, const QFont &F, const QColor &C, bool U) {
3813   dialogDefaults().setValue(group+QString("Global"), U);
3814   dialogDefaults().setValue(group+QString("Family"), QVariant(F).toString());
3815   dialogDefaults().setValue(group+QString("Scale"), F.pointSize());
3816   dialogDefaults().setValue(group+QString("Color"), QVariant(C).toString());
3817 }
3818 
3819 void CreatePlotCommand::createItem() {
3820   _item = new PlotItem(_view);
3821   _view->setCursor(Qt::CrossCursor);
3822 
3823   CreateCommand::createItem();
3824 }
3825 
3826 
3827 void CreatePlotForCurve::createItem() {
3828   _item = new PlotItem(_view);
3829   creationComplete(); //add to undo stack
3830 }
3831 
3832 
3833 PlotItemFactory::PlotItemFactory()
3834 : GraphicsFactory() {
3835   registerFactory("plot", this);
3836 }
3837 
3838 
3839 PlotItemFactory::~PlotItemFactory() {
3840 }
3841 
3842 ViewItem* PlotItemFactory::generateGraphics(QXmlStreamReader& xml, ObjectStore *store, View *view, ViewItem *parent) {
3843   PlotItem *rc = 0;
3844   double x = 0, y = 0, w = 10, h = 10;
3845   bool xTiedZoom = false, yTiedZoom = false;
3846   while (!xml.atEnd()) {
3847     bool validTag = true;
3848     if (xml.isStartElement()) {
3849       if (!rc && xml.name().toString() == "plot") {
3850         Q_ASSERT(!rc);
3851 
3852         QXmlStreamAttributes attrs = xml.attributes();
3853         QStringRef av;
3854 
3855         Object::processShortNameIndexAttributes(attrs);
3856 
3857         rc = new PlotItem(view);
3858         if (parent) {
3859           rc->setParentViewItem(parent);
3860         }
3861 
3862         av = attrs.value("tiedxzoom");
3863         if (!av.isNull()) {
3864           xTiedZoom = QVariant(av.toString()).toBool();
3865         }
3866         av = attrs.value("tiedyzoom");
3867         if (!av.isNull()) {
3868           yTiedZoom = QVariant(av.toString()).toBool();
3869         }
3870         av = attrs.value("leftlabelvisible");
3871         if (!av.isNull()) {
3872           rc->leftLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3873         }
3874         av = attrs.value("bottomlabelvisible");
3875         if (!av.isNull()) {
3876           rc->bottomLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3877         }
3878         av = attrs.value("rightlabelvisible");
3879         if (!av.isNull()) {
3880           rc->rightLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3881         }
3882         av = attrs.value("toplabelvisible");
3883         if (!av.isNull()) {
3884           rc->topLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3885         }
3886         av = attrs.value("globalfont");
3887         if (!av.isNull()) {
3888           QFont font;
3889           font.fromString(av.toString());
3890           rc->setGlobalFont(font);
3891         }
3892         double fontscale = 0.0;
3893         av = attrs.value("globalfontscale");
3894         if (!av.isNull()) {
3895           fontscale = QVariant(av.toString()).toDouble();
3896         }
3897         if (fontscale < 0.1) {
3898           fontscale = 14.0;
3899         }
3900         rc->setGlobalFontScale(fontscale);
3901         av = attrs.value("globalfontcolor");
3902         if (!av.isNull()) {
3903           rc->setGlobalFontColor(QColor(av.toString()));
3904         }
3905         av = attrs.value("showlegend");
3906         if (!av.isNull()) {
3907           rc->setShowLegend(QVariant(av.toString()).toBool());
3908         }
3909 
3910         av = attrs.value("hidebottomaxislabel");
3911         if (!av.isNull()) {
3912           rc->setManuallyHideBottomAxisLabel(QVariant(av.toString()).toBool());
3913         }
3914 
3915         av = attrs.value("hidetopaxislabel");
3916         if (!av.isNull()) {
3917           rc->setManuallyHideTopAxisLabel(QVariant(av.toString()).toBool());
3918         }
3919 
3920         av = attrs.value("hideleftaxislabel");
3921         if (!av.isNull()) {
3922           rc->setManuallyHideLeftAxisLabel(QVariant(av.toString()).toBool());
3923         }
3924 
3925         av = attrs.value("hiderightaxislabel");
3926         if (!av.isNull()) {
3927           rc->setManuallyHideRightAxisLabel(QVariant(av.toString()).toBool());
3928         }
3929 
3930         av = attrs.value("numberaxislabelscale");
3931         if (!av.isNull()) {
3932           rc->setUseAxisScale(QVariant(av.toString()).toBool());
3933         }
3934 
3935         if (attrs.value("descriptiveNameIsManual").toString() == "true") {
3936           rc->setDescriptiveName(attrs.value("descriptiveName").toString());
3937         }
3938 
3939         // Add any new specialized PlotItem Properties here.
3940       } else if (xml.name().toString() == "projectionrect") {
3941         QXmlStreamAttributes attrs = xml.attributes();
3942         QStringRef av;
3943         av = attrs.value("width");
3944         if (!av.isNull()) {
3945           w = av.toString().toDouble();
3946         }
3947         av = attrs.value("height");
3948         if (!av.isNull()) {
3949           h = av.toString().toDouble();
3950         }
3951         av = attrs.value("x");
3952         if (!av.isNull()) {
3953           x = av.toString().toDouble();
3954         }
3955         av = attrs.value("y");
3956         if (!av.isNull()) {
3957           y = av.toString().toDouble();
3958         }
3959         xml.readNext();
3960       } else if (xml.name().toString() == "plotaxis") {
3961         Q_ASSERT(rc);
3962         QXmlStreamAttributes subattrs = xml.attributes();
3963         QStringRef av = subattrs.value("id");
3964         if (!av.isNull()) {
3965           if (av == "xaxis") {
3966             rc->xAxis()->configureFromXml(xml, store);
3967           } else if (av == "yaxis") {
3968             rc->yAxis()->configureFromXml(xml, store);
3969           }
3970         }
3971         xml.readNext();
3972       } else if (xml.name().toString() == "plotlabel") {
3973         Q_ASSERT(rc);
3974         QXmlStreamAttributes subattrs = xml.attributes();
3975         QStringRef av = subattrs.value("id");
3976         if (!av.isNull()) {
3977           if (av == "leftlabel") {
3978             rc->leftLabelDetails()->configureFromXml(xml, store);
3979           } else if (av == "rightlabel") {
3980             rc->rightLabelDetails()->configureFromXml(xml, store);
3981           } else if (av == "toplabel") {
3982             rc->topLabelDetails()->configureFromXml(xml, store);
3983           } else if (av == "bottomlabel") {
3984             rc->bottomLabelDetails()->configureFromXml(xml, store);
3985           } else if (av == "numberlabel") {
3986             rc->numberLabelDetails()->configureFromXml(xml, store);         }
3987         }
3988         xml.readNext();
3989       } else if (xml.name().toString() == "cartesianrender") {
3990         Q_ASSERT(rc);
3991         PlotRenderItem * renderItem = rc->renderItem(PlotRenderItem::Cartesian);
3992         if (renderItem) {
3993           validTag = renderItem->configureFromXml(xml, store);
3994         }
3995       } else if (xml.name().toString() == "legend") {
3996         Q_ASSERT(rc);
3997         validTag = rc->legend()->configureFromXml(xml, store);
3998       } else {
3999         Q_ASSERT(rc);
4000         if (!rc->parse(xml, validTag) && validTag) {
4001           ViewItem *i = GraphicsFactory::parse(xml, store, view, rc);
4002           if (!i) {
4003           }
4004         }
4005       }
4006     } else if (xml.isEndElement()) {
4007       if (xml.name().toString() == "plot") {
4008         break;
4009       } else {
4010         validTag = false;
4011       }
4012     }
4013     if (!validTag) {
4014       Debug::self()->log(QObject::tr("Error creating plot object from Kst file."), Debug::Warning);
4015       delete rc;
4016       return 0;
4017     }
4018     xml.readNext();
4019   }
4020   rc->setProjectionRect(QRectF(QPointF(x, y), QSizeF(w, h)));
4021   rc->setTiedZoom(xTiedZoom, yTiedZoom);
4022   return rc;
4023 }
4024 
4025 
4026 ZoomCommand::ZoomCommand(PlotItem *item, const QString &text, bool forced)
4027     : ViewItemCommand(item, text, false), _plotItem(item) {
4028 
4029   if (!item->isTiedZoom() || forced) {
4030     _originalStates << item->currentZoomState();
4031   } else {
4032     _viewItems = PlotItemManager::tiedZoomViewItems(item);
4033 
4034     QList<PlotItem*> plots = PlotItemManager::tiedZoomPlots(item);
4035     foreach (PlotItem *plotItem, plots) {
4036       if (plotItem->isInSharedAxisBox()) {
4037         if (!_viewItems.contains(plotItem->sharedAxisBox())) {
4038           _viewItems << plotItem->sharedAxisBox();
4039         }
4040       } else { // plots already in a shared box are going to get zoomed anyway, so don't re-add them.
4041         _originalStates << plotItem->currentZoomState();
4042       }
4043     }
4044   }
4045 }
4046 
4047 
4048 ZoomCommand::~ZoomCommand() {
4049 }
4050 
4051 
4052 void ZoomCommand::undo() {
4053   foreach (const ZoomState &state, _originalStates) {
4054     state.item->setCurrentZoomState(state);
4055   }
4056   kstApp->mainWindow()->document()->setChanged(true);
4057 }
4058 
4059 
4060 void ZoomCommand::redo() {
4061   bool tiedX = _plotItem->isXTiedZoom();
4062   bool tiedY = _plotItem->isYTiedZoom();
4063 
4064   foreach (const ZoomState &state, _originalStates) {
4065     if (state.item == _plotItem) {
4066       applyZoomTo(state.item, true, true);
4067     } else {
4068       applyZoomTo(state.item, state.item->isXTiedZoom() && tiedX, state.item->isYTiedZoom() && tiedY);
4069     }
4070   }
4071   foreach (ViewItem* item, _viewItems) { // _viewItems is the list of shared axis boxes tied in somehow.
4072     applyZoomTo(item, tiedX, tiedY);
4073   }
4074 
4075   kstApp->mainWindow()->document()->setChanged(true);
4076 }
4077 
4078 
4079 /*
4080  * X axis zoom to FixedExpression, Y axis zoom to FixedExpression.
4081  */
4082 void ZoomFixedExpressionCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4083   if (applyX && applyY) {
4084     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4085     item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4086     item->setProjectionRect(_fixed);
4087   } else if (applyX) {
4088     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4089     item->setProjectionRect(QRectF(_fixed.x(), item->projectionRect().y(), _fixed.width(), item->projectionRect().height()));
4090   } else if (applyY) {
4091     item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4092     item->setProjectionRect(QRectF(item->projectionRect().x(), _fixed.y(), item->projectionRect().width(), _fixed.height()));
4093   }
4094 }
4095 
4096 
4097 void ZoomFixedExpressionCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4098   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4099   if (shareBox) {
4100     if (applyX && applyY) {
4101       shareBox->zoomFixedExpression(_fixed, 0);
4102     } else if (applyX) {
4103       shareBox->zoomXRange(_fixed, 0);
4104     } else if (applyY) {
4105       shareBox->zoomYRange(_fixed, 0);
4106     }
4107   }
4108 }
4109 
4110 
4111 /*
4112  * X axis zoom to Range.
4113  */
4114 void ZoomXRangeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4115   Q_UNUSED(applyY);
4116   if (applyX) {
4117     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4118     item->setProjectionRect(QRectF(_fixed.x(), item->projectionRect().y(), _fixed.width(), item->projectionRect().height()));
4119   }
4120 }
4121 
4122 
4123 void ZoomXRangeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4124   Q_UNUSED(applyY);
4125   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4126   if (shareBox) {
4127     if (applyX) {
4128       shareBox->zoomXRange(_fixed, 0);
4129     }
4130   }
4131 }
4132 
4133 
4134 /*
4135  * Y axis zoom to Range.
4136  */
4137 void ZoomYRangeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4138   Q_UNUSED(applyX);
4139   if (applyY) {
4140     item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4141     item->setProjectionRect(QRectF(item->projectionRect().x(), _fixed.y(), item->projectionRect().width(), _fixed.height()));
4142   }
4143 }
4144 
4145 
4146 void ZoomYRangeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4147   Q_UNUSED(applyX);
4148   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4149   if (shareBox) {
4150     if (applyY) {
4151       shareBox->zoomYRange(_fixed, 0);
4152     }
4153   }
4154 }
4155 
4156 
4157 /*
4158  * X axis zoom to Auto, Y axis zoom to AutoBorder.
4159  */
4160 void ZoomMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4161   if (applyX && applyY) {
4162     item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4163     item->yAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4164     QRectF compute = item->computedProjectionRect();
4165     item->setProjectionRect(compute);
4166   } else if (applyX) {
4167     item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4168     QRectF compute = item->computedProjectionRect();
4169     item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), compute.width(), item->projectionRect().height()));
4170   } else if (applyY) {
4171     item->yAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4172     QRectF compute = item->computedProjectionRect();
4173     item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), compute.height()));
4174   }
4175 }
4176 
4177 
4178 void ZoomMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4179   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4180   if (shareBox) {
4181     if (applyX && applyY) {
4182       shareBox->zoomMaximum(0);
4183     } else if (applyX) {
4184       shareBox->zoomXMaximum(0);
4185     } else if (applyY) {
4186       shareBox->zoomYMaximum(0);
4187     }
4188   }
4189 }
4190 
4191 /*
4192  * X axis zoom to Auto, Y axis zoom to SpikeInsensitive.
4193  */
4194 void ZoomMaxSpikeInsensitiveCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4195   if (applyX && applyY) {
4196     item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4197     item->yAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4198     QRectF compute = item->computedProjectionRect();
4199     item->setProjectionRect(compute);
4200   } else if (applyX) {
4201     item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4202     QRectF compute = item->computedProjectionRect();
4203     item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), compute.width(), item->projectionRect().height()));
4204   } else if (applyY) {
4205     item->yAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4206     QRectF compute = item->computedProjectionRect();
4207     item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), compute.height()));
4208   }
4209 }
4210 
4211 
4212 void ZoomMaxSpikeInsensitiveCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4213   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4214   if (shareBox) {
4215     if (applyX && applyY) {
4216       shareBox->zoomMaxSpikeInsensitive(0);
4217     } else if (applyX) {
4218       shareBox->zoomXMaximum(0);
4219     } else if (applyY) {
4220       shareBox->zoomYNoSpike(0);
4221     }
4222   }
4223 }
4224 
4225 
4226 /*
4227  * X axis zoom to Auto, Y axis zoom to Mean Centered.
4228  */
4229 void ZoomMeanCenteredCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4230   if (applyX && applyY) {
4231     item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4232     item->yAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4233     QRectF compute = item->computedProjectionRect();
4234     item->setProjectionRect(compute);
4235   } else if (applyX) {
4236     item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4237     QRectF compute = item->computedProjectionRect();
4238     item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), compute.width(), item->projectionRect().height()));
4239   } else if (applyY) {
4240     item->yAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4241     QRectF compute = item->computedProjectionRect();
4242     item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), compute.height()));
4243   }
4244 }
4245 
4246 
4247 void ZoomMeanCenteredCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4248   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4249   if (shareBox) {
4250     if (applyX && applyY) {
4251       shareBox->zoomMeanCentered(0);
4252     } else if (applyX) {
4253       shareBox->zoomXMaximum(0);
4254     } else if (applyY) {
4255       shareBox->zoomMeanCentered(0);
4256     }
4257   }
4258 }
4259 
4260 /*
4261  * X axis zoom unchanged, Y axis zoom to Mean Centered.
4262  */
4263 void ZoomYMeanCenteredCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4264   Q_UNUSED(applyX);
4265 
4266   if (applyY) {
4267     item->yAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4268     QRectF compute = item->computedProjectionRect();
4269     item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), _dY));
4270   }
4271 }
4272 
4273 
4274 void ZoomYMeanCenteredCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4275   Q_UNUSED(applyX);
4276   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4277   if (shareBox) {
4278     if (applyY) {
4279       shareBox->zoomYMeanCentered(_dY, 0);
4280     }
4281   }
4282 }
4283 
4284 /*
4285  * X axis zoom to Mean Centered, Y axis unchanged.
4286  */
4287 void ZoomXMeanCenteredCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4288   Q_UNUSED(applyY);
4289 
4290   if (applyX) {
4291     item->xAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4292     QRectF compute = item->computedProjectionRect();
4293     item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), _dX, item->projectionRect().height()));
4294   }
4295 }
4296 
4297 
4298 void ZoomXMeanCenteredCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4299   Q_UNUSED(applyY);
4300   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4301   if (shareBox) {
4302     if (applyX) {
4303       shareBox->zoomXMeanCentered(0);
4304     }
4305   }
4306 }
4307 
4308 /*
4309  * X axis zoom to auto, Y zoom not changed.
4310  */
4311 void ZoomXMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4312   Q_UNUSED(applyY);
4313   if (applyX) {
4314     item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4315     QRectF compute = item->computedProjectionRect();
4316     item->setProjectionRect(QRectF(compute.x(),
4317           item->projectionRect().y(),
4318           compute.width(),
4319           item->projectionRect().height()));
4320   }
4321 }
4322 
4323 
4324 void ZoomXMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4325   Q_UNUSED(applyY);
4326   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4327   if (shareBox) {
4328     if (applyX) {
4329       shareBox->zoomXMaximum(0);
4330     }
4331   }
4332 }
4333 
4334 
4335 /*
4336  * X axis zoom to auto border, Y zoom not changed.
4337  */
4338 void ZoomXAutoBorderCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4339   Q_UNUSED(applyY);
4340   if (applyX) {
4341     item->xAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4342     QRectF compute = item->computedProjectionRect();
4343     item->setProjectionRect(QRectF(compute.x(),
4344           item->projectionRect().y(),
4345           compute.width(),
4346           item->projectionRect().height()));
4347   }
4348 }
4349 
4350 
4351 void ZoomXAutoBorderCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4352   Q_UNUSED(applyY);
4353   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4354   if (shareBox) {
4355     if (applyX) {
4356       shareBox->zoomXAutoBorder(0);
4357     }
4358   }
4359 }
4360 
4361 
4362 /*
4363  * X axis zoom to no spike, Y zoom not changed.
4364  */
4365 void ZoomXNoSpikeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4366   Q_UNUSED(applyY);
4367   if (applyX) {
4368     item->xAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4369     QRectF compute = item->computedProjectionRect();
4370     item->setProjectionRect(QRectF(compute.x(),
4371           item->projectionRect().y(),
4372           compute.width(),
4373           item->projectionRect().height()));
4374   }
4375 }
4376 
4377 
4378 void ZoomXNoSpikeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4379   Q_UNUSED(applyY);
4380   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4381   if (shareBox) {
4382     if (applyX) {
4383       shareBox->zoomXNoSpike(0);
4384     }
4385   }
4386 }
4387 
4388 
4389 /*
4390  * X axis zoom changed to fixed and shifted to right:
4391  *       new_xmin = xmin + (xmax - xmin)*0.10;
4392  *       new_xmax = xmax + (xmax – xmin)*0.10;
4393  */
4394 void ZoomXRightCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4395   Q_UNUSED(applyY);
4396   if (applyX) {
4397     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4398 
4399     QRectF compute = item->projectionRect();
4400 
4401     qreal dx = (item->xMax() - item->xMin())*0.10;
4402     if (item->xAxis()->axisReversed()) {
4403       dx *=-1;
4404     }
4405     if (item->xAxis()->axisLog()) {
4406       compute.setLeft(pow(10, item->xMin() + dx));
4407       compute.setRight(pow(10, item->xMax() + dx));
4408     } else {
4409       compute.setLeft(compute.left() + dx);
4410       compute.setRight(compute.right() + dx);
4411     }
4412 
4413     item->setProjectionRect(compute);
4414   }
4415 }
4416 
4417 
4418 void ZoomXRightCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4419   Q_UNUSED(applyY);
4420   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4421   if (shareBox) {
4422     if (applyX) {
4423       shareBox->zoomXRight(0);
4424     }
4425   }
4426 }
4427 
4428 /*
4429  * X axis zoom changed to fixed and shifted to right:
4430  *       new_xmin = xmin + (xmax - xmin);
4431  *       new_xmax = xmax + (xmax – xmin);
4432  */
4433 void ZoomXFarRightCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4434   Q_UNUSED(applyY);
4435   if (applyX) {
4436     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4437 
4438     QRectF compute = item->projectionRect();
4439 
4440     qreal dx = (item->xMax() - item->xMin());
4441     if (item->xAxis()->axisReversed()) {
4442       dx *=-1;
4443     }
4444     if (item->xAxis()->axisLog()) {
4445       compute.setLeft(pow(10, item->xMin() + dx));
4446       compute.setRight(pow(10, item->xMax() + dx));
4447     } else {
4448       compute.setLeft(compute.left() + dx);
4449       compute.setRight(compute.right() + dx);
4450     }
4451 
4452     item->setProjectionRect(compute);
4453   }
4454 }
4455 
4456 
4457 void ZoomXFarRightCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4458   Q_UNUSED(applyY);
4459   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4460   if (shareBox) {
4461     if (applyX) {
4462       shareBox->zoomXRight(0, true);
4463     }
4464   }
4465 }
4466 
4467 /*
4468  * X axis zoom changed to fixed and shifted to :
4469  *       new_xmin = xmin - (xmax - xmin)*0.10;
4470  *       new_xmax = xmax - (xmax – xmin)*0.10;
4471  */
4472 void ZoomXLeftCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4473   Q_UNUSED(applyY);
4474   if (applyX) {
4475     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4476 
4477     QRectF compute = item->projectionRect();
4478 
4479     qreal dx = (item->xMax() - item->xMin())*0.10;
4480     if (item->xAxis()->axisReversed()) {
4481       dx *=-1;
4482     }
4483     if (item->xAxis()->axisLog()) {
4484       compute.setLeft(pow(10, item->xMin() - dx));
4485       compute.setRight(pow(10, item->xMax() - dx));
4486     } else {
4487       compute.setLeft(compute.left() - dx);
4488       compute.setRight(compute.right() - dx);
4489     }
4490 
4491     item->setProjectionRect(compute);
4492   }
4493 }
4494 
4495 
4496 void ZoomXLeftCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4497   Q_UNUSED(applyY);
4498   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4499   if (shareBox) {
4500     if (applyX) {
4501       shareBox->zoomXLeft(0);
4502     }
4503   }
4504 }
4505 
4506 /*
4507  * X axis zoom changed to fixed and shifted to :
4508  *       new_xmin = xmin - (xmax - xmin);
4509  *       new_xmax = xmax - (xmax – xmin);
4510  */
4511 void ZoomXFarLeftCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4512   Q_UNUSED(applyY);
4513   if (applyX) {
4514     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4515 
4516     QRectF compute = item->projectionRect();
4517 
4518     qreal dx = (item->xMax() - item->xMin());
4519     if (item->xAxis()->axisReversed()) {
4520       dx *=-1;
4521     }
4522     if (item->xAxis()->axisLog()) {
4523       compute.setLeft(pow(10, item->xMin() - dx));
4524       compute.setRight(pow(10, item->xMax() - dx));
4525     } else {
4526       compute.setLeft(compute.left() - dx);
4527       compute.setRight(compute.right() - dx);
4528     }
4529 
4530     item->setProjectionRect(compute);
4531   }
4532 }
4533 
4534 
4535 void ZoomXFarLeftCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4536   Q_UNUSED(applyY);
4537   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4538   if (shareBox) {
4539     if (applyX) {
4540       shareBox->zoomXLeft(0, true);
4541     }
4542   }
4543 }
4544 
4545 
4546 /*
4547  * X axis zoom changed to fixed and increased:
4548  *       new_xmin = xmin - (xmax - xmin)*0.25;
4549  *       new_xmax = xmax + (xmax – xmin)*0.25;
4550  */
4551 void ZoomXOutCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4552   Q_UNUSED(applyY);
4553   if (applyX) {
4554     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4555 
4556     QRectF compute = item->projectionRect();
4557 
4558     qreal dx = (item->xMax() - item->xMin())*0.25;
4559     if (item->xAxis()->axisLog()) {
4560       compute.setLeft(pow(10, item->xMin() - dx));
4561       compute.setRight(pow(10, item->xMax() + dx));
4562     } else {
4563       compute.setLeft(compute.left() - dx);
4564       compute.setRight(compute.right() + dx);
4565     }
4566 
4567     item->setProjectionRect(compute);
4568     //   item->update();
4569   }
4570 }
4571 
4572 
4573 void ZoomXOutCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4574   Q_UNUSED(applyY);
4575   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4576   if (shareBox) {
4577     if (applyX) {
4578       shareBox->zoomXOut(0);
4579     }
4580   }
4581 }
4582 
4583 
4584 /*
4585  * X axis zoom changed to fixed and decreased:
4586  *       new_xmin = xmin + (xmax - xmin)*0.1666666;
4587  *       new_xmax = xmax - (xmax – xmin)*0.1666666;
4588  */
4589 void ZoomXInCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4590   Q_UNUSED(applyY);
4591   if (applyX) {
4592     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4593 
4594     QRectF compute = item->projectionRect();
4595 
4596     qreal dx = (item->xMax() - item->xMin())*0.1666666;
4597     if (item->xAxis()->axisLog()) {
4598       compute.setLeft(pow(10, item->xMin() + dx));
4599       compute.setRight(pow(10, item->xMax() - dx));
4600     } else {
4601       compute.setLeft(compute.left() + dx);
4602       compute.setRight(compute.right() - dx);
4603     }
4604 
4605     item->setProjectionRect(compute);
4606   }
4607 }
4608 
4609 
4610 void ZoomXInCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4611   Q_UNUSED(applyY);
4612   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4613   if (shareBox) {
4614     if (applyX) {
4615       shareBox->zoomXIn(0);
4616     }
4617   }
4618 }
4619 
4620 
4621 /*
4622  * Normalize X axis to Y axis: Given the current plot aspect ratio, change
4623  * the X axis range to have the same units per mm as the Y axis range. Particularly
4624  * useful for images.
4625  */
4626 void ZoomNormalizeXToYCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4627   Q_UNUSED(applyY);
4628   if (applyX) {
4629     QRectF compute = item->projectionRect();
4630     qreal mean = compute.center().x();
4631     qreal range = item->plotRect().width() * compute.height() / item->plotRect().height();
4632 
4633     compute.setLeft(mean - (range / 2.0));
4634     compute.setRight(mean + (range / 2.0));
4635 
4636     item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4637     item->setProjectionRect(compute);
4638   }
4639 }
4640 
4641 
4642 void ZoomNormalizeXToYCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4643   Q_UNUSED(applyY);
4644   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4645   if (shareBox) {
4646     if (applyX) {
4647       shareBox->zoomNormalizeXtoY(0);
4648     }
4649   }
4650 }
4651 
4652 
4653 /*
4654  * When zoomed in in X, auto zoom Y, only
4655  * counting points within the current X range. (eg, curve goes from x=0 to 100, but
4656  * we are zoomed in to x = 30 to 40. Adjust Y zoom to include all points with x
4657  * values between 30 and 40.
4658  */
4659 void ZoomYLocalMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4660   Q_UNUSED(applyX);
4661   if (applyY) {
4662     double minimum = item->yMax();
4663     double maximum = item->yMin();
4664     item->computedRelationalMax(minimum, maximum);
4665 
4666     item->computeBorder(Qt::Vertical, minimum, maximum);
4667 
4668     item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4669 
4670     QRectF compute = item->projectionRect();
4671     compute.setTop(minimum);
4672     compute.setBottom(maximum);
4673 
4674     item->setProjectionRect(compute);
4675   }
4676 }
4677 
4678 
4679 void ZoomYLocalMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4680   Q_UNUSED(applyX);
4681   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4682   if (shareBox) {
4683     if (applyY) {
4684       shareBox->zoomYLocalMaximum(0);
4685     }
4686   }
4687 }
4688 
4689 
4690 /*
4691  * Y axis zoom to auto, X zoom not changed.
4692  */
4693 void ZoomYMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4694   Q_UNUSED(applyX);
4695   if (applyY) {
4696     item->yAxis()->setAxisZoomMode(PlotAxis::Auto);
4697     QRectF compute = item->computedProjectionRect();
4698     item->setProjectionRect(QRectF(item->projectionRect().x(),
4699           compute.y(),
4700           item->projectionRect().width(),
4701           compute.height()));
4702   }
4703 }
4704 
4705 
4706 void ZoomYMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4707   Q_UNUSED(applyX);
4708   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4709   if (shareBox) {
4710     if (applyY) {
4711       shareBox->zoomYMaximum(0);
4712     }
4713   }
4714 }
4715 
4716 
4717 /*
4718  * Y axis zoom to auto border, X zoom not changed.
4719  */
4720 void ZoomYAutoBorderCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4721   Q_UNUSED(applyX);
4722   if (applyY) {
4723     item->yAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4724     QRectF compute = item->computedProjectionRect();
4725     item->setProjectionRect(QRectF(item->projectionRect().x(),
4726           compute.y(),
4727           item->projectionRect().width(),
4728           compute.height()));
4729   }
4730 }
4731 
4732 
4733 void ZoomYAutoBorderCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4734   Q_UNUSED(applyX);
4735   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4736   if (shareBox) {
4737     if (applyY) {
4738       shareBox->zoomYAutoBorder(0);
4739     }
4740   }
4741 }
4742 
4743 
4744 /*
4745  * Y axis zoom to no spike, X zoom not changed.
4746  */
4747 void ZoomYNoSpikeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4748   Q_UNUSED(applyX);
4749   if (applyY) {
4750     item->yAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4751     QRectF compute = item->computedProjectionRect();
4752     item->setProjectionRect(QRectF(item->projectionRect().x(),
4753           compute.y(),
4754           item->projectionRect().width(),
4755           compute.height()));
4756   }
4757 }
4758 
4759 
4760 void ZoomYNoSpikeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4761   Q_UNUSED(applyX);
4762   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4763   if (shareBox) {
4764     if (applyY) {
4765       shareBox->zoomYNoSpike(0);
4766     }
4767   }
4768 }
4769 
4770 
4771 /*
4772  * Y axis zoom up. If the Y zoom mode is not
4773  * Mean Centered, change to Fixed (expression).
4774  *             new_ymin = ymin + (ymax - ymin)*0.1;
4775  *             new_ymax = ymax + (ymax - ymin)*0.1;
4776  */
4777 void ZoomYUpCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4778   Q_UNUSED(applyX);
4779   if (applyY) {
4780     if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4781       item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4782 
4783     QRectF compute = item->projectionRect();
4784 
4785     qreal dy = (item->yMax() - item->yMin())*0.1;
4786     if (item->yAxis()->axisLog()) {
4787       compute.setTop(pow(10, item->yMin() + dy));
4788       compute.setBottom(pow(10, item->yMax() + dy));
4789     } else {
4790       compute.setTop(compute.top() + dy);
4791       compute.setBottom(compute.bottom() + dy);
4792     }
4793 
4794     item->setProjectionRect(compute);
4795   }
4796 }
4797 
4798 
4799 void ZoomYUpCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4800   Q_UNUSED(applyX);
4801   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4802   if (shareBox) {
4803     if (applyY) {
4804       shareBox->zoomYUp(0);
4805     }
4806   }
4807 }
4808 
4809 
4810 /*
4811  * Y axis zoom down. If the Y zoom mode is not
4812  * Mean Centered, change to Fixed (expression).
4813  *             new_ymin = ymin - (ymax - ymin)*0.10;
4814  *             new_ymax = ymax - (ymax - ymin)*0.10;
4815  */
4816 void ZoomYDownCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4817   Q_UNUSED(applyX);
4818   if (applyY) {
4819     if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4820       item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4821 
4822     QRectF compute = item->projectionRect();
4823 
4824     qreal dy = (item->yMax() - item->yMin())*0.1;
4825     if (item->yAxis()->axisLog()) {
4826       compute.setTop(pow(10, item->yMin() - dy));
4827       compute.setBottom(pow(10, item->yMax() - dy));
4828     } else {
4829       compute.setTop(compute.top() - dy);
4830       compute.setBottom(compute.bottom() - dy);
4831     }
4832 
4833     item->setProjectionRect(compute);
4834   }
4835 }
4836 
4837 
4838 void ZoomYDownCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4839   Q_UNUSED(applyX);
4840   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4841   if (shareBox) {
4842     if (applyY) {
4843       shareBox->zoomYDown(0);
4844     }
4845   }
4846 }
4847 
4848 
4849 /*
4850  * Y axis zoom increased. If the Y zoom mode is not
4851  * Mean Centered, change to Fixed (expression).
4852  *             new_ymin = ymin - (ymax - ymin)*0.25;
4853  *             new_ymax = ymax + (ymax - ymin)*0.25;
4854  */
4855 void ZoomYOutCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4856   Q_UNUSED(applyX);
4857   if (applyY) {
4858     if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4859       item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4860 
4861     QRectF compute = item->projectionRect();
4862 
4863     qreal dy = (item->yMax() - item->yMin())*0.25;
4864     if (item->yAxis()->axisLog()) {
4865       compute.setTop(pow(10, item->yMin() - dy));
4866       compute.setBottom(pow(10, item->yMax() + dy));
4867     } else {
4868       compute.setTop(compute.top() - dy);
4869       compute.setBottom(compute.bottom() + dy);
4870     }
4871 
4872     item->setProjectionRect(compute);
4873     //   item->update();
4874   }
4875 }
4876 
4877 
4878 void ZoomYOutCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4879   Q_UNUSED(applyX);
4880   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4881   if (shareBox) {
4882     if (applyY) {
4883       shareBox->zoomYOut(0);
4884     }
4885   }
4886 }
4887 
4888 
4889 /*
4890  * Y axis zoom decreased. If the Y zoom mode is not
4891  * Mean Centered, change to Fixed (expression).
4892  *             new_ymin = ymin + (ymax - ymin)*0.1666666;
4893  *             new_ymax = ymax - (ymax – ymin)*0.1666666;
4894  */
4895 void ZoomYInCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4896   Q_UNUSED(applyX);
4897   if (applyY) {
4898     if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4899       item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4900 
4901     QRectF compute = item->projectionRect();
4902 
4903     qreal dy = (item->yMax() - item->yMin())*0.1666666;
4904     if (item->yAxis()->axisLog()) {
4905       compute.setTop(pow(10, item->yMin() + dy));
4906       compute.setBottom(pow(10, item->yMax() - dy));
4907     } else {
4908       compute.setTop(compute.top() + dy);
4909       compute.setBottom(compute.bottom() - dy);
4910     }
4911 
4912     item->setProjectionRect(compute);
4913     //   item->update();
4914   }
4915 }
4916 
4917 
4918 void ZoomYInCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4919   Q_UNUSED(applyX);
4920   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4921   if (shareBox) {
4922     if (applyY) {
4923       shareBox->zoomYIn(0);
4924     }
4925   }
4926 }
4927 
4928 
4929 /*
4930  * Normalize Y axis to X axis: Given the current plot aspect ratio,
4931  * change the Y axis range to have the same units per mm as the X axis range.
4932  * Particularly useful for images.
4933  */
4934 void ZoomNormalizeYToXCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4935   Q_UNUSED(applyX);
4936   if (applyY) {
4937     QRectF compute = item->projectionRect();
4938     qreal mean = compute.center().y();
4939     qreal range = item->plotRect().height() * compute.width() / item->plotRect().width();
4940 
4941     compute.setTop(mean - (range / 2.0));
4942     compute.setBottom(mean + (range / 2.0));
4943 
4944     item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4945     item->setProjectionRect(compute);
4946   }
4947 }
4948 
4949 
4950 void ZoomNormalizeYToXCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4951   Q_UNUSED(applyX);
4952   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4953   if (shareBox) {
4954     if (applyY) {
4955       shareBox->zoomNormalizeYtoX(0);
4956     }
4957   }
4958 }
4959 
4960 
4961 /*
4962  * Switch the X Axis to a Log Scale.
4963  */
4964 void ZoomXLogCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4965   Q_UNUSED(applyY);
4966   if (applyX) {
4967     item->xAxis()->setAxisLog(_enableLog);
4968     item->setProjectionRect(item->computedProjectionRect(), true); //need to recompute
4969   }
4970 }
4971 
4972 
4973 void ZoomXLogCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4974   Q_UNUSED(applyY);
4975   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4976   if (shareBox) {
4977     if (applyX) {
4978       shareBox->zoomLogX(0, false, _enableLog);
4979     }
4980   }
4981 }
4982 
4983 
4984 /*
4985  * Switch the Y Axis to a Log Scale.
4986  */
4987 void ZoomYLogCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4988   Q_UNUSED(applyX);
4989   if (applyY) {
4990     item->yAxis()->setAxisLog(_enableLog);
4991     item->setProjectionRect(item->computedProjectionRect(), true); //need to recompute
4992   }
4993 }
4994 
4995 
4996 void ZoomYLogCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4997   Q_UNUSED(applyX);
4998   SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4999   if (shareBox) {
5000     if (applyY) {
5001       shareBox->zoomLogY(0, false, _enableLog);
5002     }
5003   }
5004 }
5005 
5006 }
5007 
5008 // vim: ts=2 sw=2 et