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

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 "plotaxis.h"
0014 
0015 #include "math_kst.h"
0016 #include "dialogdefaults.h"
0017 
0018 #include <QDate>
0019 #include <limits>
0020 
0021 #define MAJOR_TICK_DEBUG 0
0022 
0023 using namespace std;
0024 
0025 static int FULL_PRECISION = 15;
0026 static qreal JD1900 = 2415020.5;
0027 static qreal JD1899_12_30 = 2415018.5;
0028 static qreal JD1970 = 2440587.5;
0029 static qreal JD_RJD = 2400000.0;
0030 static qreal JD_MJD = 2400000.5;
0031 
0032 namespace Kst {
0033 
0034 PlotAxis::PlotAxis(PlotItem *plotItem, Qt::Orientation orientation) :
0035   _plotItem(plotItem),
0036   _orientation(orientation),
0037   _dirty(true),
0038   _axisZoomMode(Auto),
0039   _isAxisVisible(true),
0040   _ns_zoom_level(0),
0041   _ticksUpdated(true),
0042   _axisLog(false),
0043   _axisReversed(false),
0044   _axisAutoBaseOffset(true),
0045   _axisBaseOffset(false),
0046   _axisBaseOffsetOverride(false),
0047   _axisForceOffsetMin(false),
0048   _axisInterpret(false),
0049   _axisDisplay(AXIS_DISPLAY_QTLOCALDATEHHMMSS_SS),
0050   _axisDisplayFormatString("hh:mm:ss.zzz"),
0051   _axisInterpretation(AXIS_INTERP_CTIME),
0052   _axisMajorTickMode(TicksNormal),
0053   _axisOverrideMajorTicks(TicksNormal),
0054   _axisMinorTickCount(4),
0055   _automaticMinorTicks(true),
0056   _automaticMinorTickCount(5),
0057   _axisSignificantDigits(9),
0058   _drawAxisMajorTicks(true),
0059   _drawAxisMinorTicks(true),
0060   _drawAxisMajorGridLines(true),
0061   _drawAxisMinorGridLines(false),
0062   _axisMajorGridLineColor(Qt::gray),
0063   _axisMinorGridLineColor(Qt::gray),
0064   _axisMajorGridLineStyle(Qt::DashLine),
0065   _axisMinorGridLineStyle(Qt::DashLine),
0066   _axisMajorGridLineWidth(1.0),
0067   _axisMinorGridLineWidth(1.0),
0068   _axisPlotMarkers(orientation == Qt::Horizontal),
0069   _labelRotation(0)
0070  {
0071   connect(_plotItem, SIGNAL(updateAxes()), this, SLOT(updateTicks()));
0072 }
0073 
0074 
0075 PlotAxis::~PlotAxis() {
0076 }
0077 
0078 double PlotAxis::convertJDtoDisplayTime(double T) {
0079   switch (_axisDisplay) {
0080     case AXIS_DISPLAY_YEAR:
0081       T -= JD1900 + 0.5;
0082       T *= 1.0/365.25; // FIXME: make sure this is right
0083       T += 1900.0;
0084       break;
0085     case AXIS_DISPLAY_JD:
0086       break;
0087     case AXIS_DISPLAY_MJD:
0088       T -= JD_MJD;
0089       break;
0090     case AXIS_DISPLAY_RJD:
0091       T -= JD_RJD;
0092       break;
0093     default:
0094       break;
0095   }
0096 
0097   return T;
0098 }
0099 
0100 
0101 double PlotAxis::convertJDtoCTime(double jdIn) {
0102   jdIn -= (JD1970);
0103   jdIn *= 24.0*3600.0;
0104 
0105   if (jdIn > double(std::numeric_limits<time_t>::max())-1.0) {
0106     jdIn = std::numeric_limits<time_t>::max()-1;
0107   }
0108   if (jdIn<0) {
0109     jdIn = 0.0;
0110   }
0111   return (jdIn);
0112 }
0113 
0114 
0115 double PlotAxis::convertTimeValueToJD(double valueIn) {
0116   double value = valueIn;
0117 
0118   switch (_axisInterpretation) {
0119     case AXIS_INTERP_YEAR:
0120       value -= 1900.0;
0121       value *= 365.25;  // FIXME: seems wrong
0122       value += JD1900 + 0.5;
0123       break;
0124     case AXIS_INTERP_CTIME:
0125       value /= 24.0 * 60.0 * 60.0;
0126       value += JD1970;
0127       break;
0128     case AXIS_INTERP_JD:
0129       break;
0130     case AXIS_INTERP_MJD:
0131       value += JD_MJD;
0132       break;
0133     case AXIS_INTERP_RJD:
0134       value += JD_RJD;
0135       break;
0136     case AXIS_INTERP_EXCEL:
0137       value += JD1899_12_30;
0138       break;
0139     case AXIS_INTERP_AIT:
0140       value -= 86400.0 * (365.0 * 12.0 + 3.0);
0141       // current difference (seconds) between UTC and AIT
0142       // refer to the following for more information:
0143       // http://hpiers.obspm.fr/eop-pc/earthor/utc/TAI-UTC_tab.html
0144       value -= 32.0;
0145       value /= 24.0 * 60.0 * 60.0;
0146       value += JD1970;
0147     default:
0148       break;
0149   }
0150 
0151   return value;
0152 }
0153 
0154 
0155 QString PlotAxis::convertJDToDateString(double jd, double range_jd) {
0156   QString label;
0157   QDate date;
0158 
0159   int accuracy;
0160   range_jd *= 24.0 * 60.0 * 60.0;
0161 
0162 
0163   if (range_jd == 0.0) {
0164     accuracy = FULL_PRECISION;
0165   } else {
0166     accuracy = 1 - int(log10(range_jd));
0167     if (accuracy < 0) {
0168       accuracy = 0;
0169     }
0170   }
0171 
0172   // gmtOffset() is returned in seconds... as it must be since
0173   //  some time zones are not an integer number of hours offset
0174   //  from UTC...
0175   jd += (_timeZone.gmtOffset(convertJDtoCTime(jd)))/(3600.0*24.0);
0176 
0177   // get the date from the Julian day number
0178   double jd_day = floor(jd);
0179   double jd_fraction = jd - jd_day;
0180 
0181   // gregorian calendar correction
0182   if (jd >= 2299160.5) {
0183     double tmp = int( ( (jd_day - 1867216.0) - 0.25 ) / 36524.25 );
0184     jd_day += 1.0 + tmp - floor(0.25*tmp);
0185   }
0186 
0187   // correction for half day offset
0188   double dDayFraction = jd_fraction + 0.5;
0189   if (dDayFraction >= 1.0) {
0190     dDayFraction -= 1.0;
0191     jd_day += 1.0;
0192   }
0193 
0194   // get time of day from day fraction
0195   int hour   = int(dDayFraction*24.0);
0196   int minute = int((dDayFraction*24.0 - double(hour))*60.0);
0197   double second = ((dDayFraction*24.0 - double(hour))*60.0 - double(minute))*60.0;
0198   double fullseconds;
0199   double millisec = modf(second + 0.0005, &fullseconds) * 1000;
0200 
0201   if (accuracy >= 0) {
0202     second *= pow(10.0, accuracy);
0203     second  = floor(second+0.5);
0204     second /= pow(10.0,accuracy);
0205     if (second >= 60.0) {
0206       second -= 60.0;
0207       minute++;
0208       if (minute == 60) {
0209         minute = 0;
0210         hour++;
0211         if (hour == 24) {
0212           hour = 0;
0213         }
0214       }
0215     }
0216   }
0217 
0218   double j2 = jd_day + 1524.0;
0219   double j3 = floor(6680.0 + ( (j2 - 2439870.0) - 122.1 )/365.25);
0220   double j4 = floor(j3 * 365.25);
0221   double j5 = floor((j2 - j4)/30.6001);
0222 
0223   double day_d = floor(j2 - j4 - floor(j5*30.6001));
0224   int day = int(qBound(-double(std::numeric_limits<int>::max()-1), day_d, double(std::numeric_limits<int>::max())));
0225 
0226   double month_d = floor(j5-1.0);
0227   int month = int(qBound(-double(std::numeric_limits<int>::max()-1), month_d, double(std::numeric_limits<int>::max())));
0228   if (month > 12) {
0229     month -= 12;
0230   }
0231 
0232   double year_d = floor(j3 - 4715.0);
0233   int year = int(qBound(-double(std::numeric_limits<int>::max()-1), year_d, double(std::numeric_limits<int>::max())));
0234   if (month > 2) {
0235     --year;
0236   }
0237   if (year <= 0) {
0238     --year;
0239   }
0240   // check how many decimal places for the seconds we actually need to show
0241   if (accuracy > 0) {
0242     QString strSecond;
0243 
0244     strSecond.sprintf("%02.*f", accuracy, second);
0245     for (int i=strSecond.length()-1; i>0; i--) {
0246       if (strSecond.at(i) == '0') {
0247         accuracy--;
0248       } else if (!strSecond.at(i).isDigit()) {
0249         break;
0250       }
0251     }
0252   }
0253 
0254   if (accuracy < 0) {
0255     accuracy = 0;
0256   }
0257 
0258   QString seconds;
0259   QString hourminute;
0260   hourminute.sprintf(" %02d:%02d:", hour, minute);
0261   seconds.sprintf("%02.*f", accuracy, second);
0262   switch (_axisDisplay) {
0263     case AXIS_DISPLAY_YYMMDDHHMMSS_SS:
0264       label.sprintf("%d/%02d/%02d", year, month, day);
0265       label += hourminute + seconds;
0266       break;
0267     case AXIS_DISPLAY_DDMMYYHHMMSS_SS:
0268       label.sprintf("%02d/%02d/%d", day, month, year);
0269       label += hourminute + seconds;
0270       break;
0271     case AXIS_DISPLAY_QTTEXTDATEHHMMSS_SS:
0272       date.setDate(year, month, day);
0273       label = date.toString(Qt::TextDate).toLatin1();
0274       label += hourminute + seconds;
0275       break;
0276     case AXIS_DISPLAY_QTLOCALDATEHHMMSS_SS:
0277       date.setDate(year, month, day);
0278       label = date.toString(Qt::LocalDate).toLatin1();
0279       label += hourminute + seconds;
0280       break;
0281     case AXIS_DISPLAY_QTDATETIME_FORMAT:
0282       label += QDateTime(QDate(year, month, day), QTime(hour, minute, second, millisec))
0283                         .toString(_axisDisplayFormatString);
0284       break;
0285     default:
0286       label = QString::number(convertJDtoDisplayTime(jd), 'G', FULL_PRECISION-2);
0287       break;
0288   }
0289   return label;
0290 }
0291 
0292 
0293 PlotAxis::ZoomMode PlotAxis::axisZoomMode() const {
0294   return _axisZoomMode;
0295 }
0296 
0297 
0298 void PlotAxis::setAxisZoomMode(ZoomMode mode) {
0299   if (_axisZoomMode != mode) {
0300     _axisZoomMode = mode;
0301     _ns_zoom_level = 0;
0302     _dirty = true;
0303   } else if (mode == PlotAxis::SpikeInsensitive) {
0304     _ns_zoom_level = (_ns_zoom_level+1)%5;
0305   }
0306 }
0307 
0308 
0309 bool PlotAxis::axisLog() const {
0310   return _axisLog;
0311 }
0312 
0313 
0314 void PlotAxis::setAxisLog(bool log) {
0315   if (_axisLog != log) {
0316     _axisLog = log;
0317     _dirty = true;
0318   }
0319 }
0320 
0321 
0322 int PlotAxis::axisSignificantDigits() const {
0323   return _axisSignificantDigits;
0324 }
0325 
0326 
0327 void PlotAxis::setAxisSignificantDigits(const int digits) {
0328   if (_axisSignificantDigits != digits) {
0329     _axisSignificantDigits = digits;
0330     _dirty = true;
0331   }
0332 }
0333 
0334 
0335 MajorTickMode PlotAxis::axisMajorTickMode() const {
0336   return _axisMajorTickMode;
0337 }
0338 
0339 
0340 void PlotAxis::setAxisMajorTickMode(MajorTickMode mode) {
0341   if (_axisMajorTickMode != mode) {
0342     _axisMajorTickMode = mode;
0343     _dirty = true;
0344   }
0345 }
0346 
0347 
0348 int PlotAxis::axisMinorTickCount() const {
0349   return _axisMinorTickCount;
0350 }
0351 
0352 
0353 void PlotAxis::setAxisMinorTickCount(const int count) {
0354   if (_axisMinorTickCount != count) {
0355     _axisMinorTickCount = count;
0356     _dirty = true;
0357   }
0358 }
0359 
0360 
0361 
0362 bool PlotAxis::axisAutoMinorTicks() const {
0363   return _automaticMinorTicks;
0364 }
0365 
0366 
0367 void PlotAxis::setAxisAutoMinorTicks(const bool enabled) {
0368   if (_automaticMinorTicks != enabled) {
0369     _automaticMinorTicks = enabled;
0370     _dirty = true;
0371   }
0372 }
0373 
0374 
0375 bool PlotAxis::drawAxisMajorTicks() const {
0376   return _drawAxisMajorTicks;
0377 }
0378 
0379 
0380 void PlotAxis::setDrawAxisMajorTicks(bool draw) {
0381   if (_drawAxisMajorTicks != draw) {
0382     _drawAxisMajorTicks = draw;
0383     _dirty = true;
0384   }
0385 }
0386 
0387 
0388 bool PlotAxis::drawAxisMinorTicks() const {
0389   return _drawAxisMinorTicks;
0390 }
0391 
0392 
0393 void PlotAxis::setDrawAxisMinorTicks(bool draw) {
0394   if (_drawAxisMinorTicks != draw) {
0395     _drawAxisMinorTicks = draw;
0396     _dirty = true;
0397   }
0398 }
0399 
0400 
0401 bool PlotAxis::drawAxisMajorGridLines() const {
0402   return _drawAxisMajorGridLines;
0403 }
0404 
0405 
0406 void PlotAxis::setDrawAxisMajorGridLines(bool draw) {
0407   if (_drawAxisMajorGridLines != draw) {
0408     _drawAxisMajorGridLines = draw;
0409     _dirty = true;
0410   }
0411 }
0412 
0413 
0414 bool PlotAxis::drawAxisMinorGridLines() const {
0415   return _drawAxisMinorGridLines;
0416 }
0417 
0418 
0419 void PlotAxis::setDrawAxisMinorGridLines(bool draw) {
0420   if (_drawAxisMinorGridLines != draw) {
0421     _drawAxisMinorGridLines = draw;
0422     _dirty = true;
0423   }
0424 }
0425 
0426 
0427 QColor PlotAxis::axisMajorGridLineColor() const {
0428   return _axisMajorGridLineColor;
0429 }
0430 
0431 
0432 void PlotAxis::setAxisMajorGridLineColor(const QColor &color) {
0433   if (_axisMajorGridLineColor != color) {
0434     _axisMajorGridLineColor = color;
0435     _dirty = true;
0436   }
0437 }
0438 
0439 
0440 QColor PlotAxis::axisMinorGridLineColor() const {
0441   return _axisMinorGridLineColor;
0442 }
0443 
0444 
0445 void PlotAxis::setAxisMinorGridLineColor(const QColor &color) {
0446   if (_axisMinorGridLineColor != color) {
0447     _axisMinorGridLineColor = color;
0448     _dirty = true;
0449   }
0450 }
0451 
0452 
0453 Qt::PenStyle PlotAxis::axisMajorGridLineStyle() const {
0454   return _axisMajorGridLineStyle;
0455 }
0456 
0457 
0458 void PlotAxis::setAxisMajorGridLineStyle(const Qt::PenStyle style) {
0459   if (_axisMajorGridLineStyle != style) {
0460     _axisMajorGridLineStyle = style;
0461     _dirty = true;
0462   }
0463 }
0464 
0465 
0466 Qt::PenStyle PlotAxis::axisMinorGridLineStyle() const {
0467   return _axisMinorGridLineStyle;
0468 }
0469 
0470 
0471 void PlotAxis::setAxisMinorGridLineStyle(const Qt::PenStyle style) {
0472   if (_axisMinorGridLineStyle != style) {
0473     _axisMinorGridLineStyle = style;
0474     _dirty = true;
0475   }
0476 }
0477 
0478 qreal PlotAxis::axisMajorGridLineWidth() const {
0479   return _axisMajorGridLineWidth;
0480 }
0481 
0482 void PlotAxis::setAxisMajorGridLineWidth(qreal width) {
0483   if (_axisMajorGridLineWidth != width) {
0484     _axisMajorGridLineWidth = width;
0485     _dirty = true;
0486   }
0487 }
0488 
0489 qreal PlotAxis::axisMinorGridLineWidth() const {
0490   return _axisMinorGridLineWidth;
0491 }
0492 
0493 void PlotAxis::setAxisMinorGridLineWidth(qreal width) {
0494   if (_axisMinorGridLineWidth != width) {
0495     _axisMinorGridLineWidth = width;
0496     _dirty = true;
0497   }
0498 }
0499 
0500 bool PlotAxis::isAxisVisible() const {
0501   return _isAxisVisible;
0502 }
0503 
0504 
0505 void PlotAxis::setAxisVisible(bool visible) {
0506   if (_isAxisVisible == visible) {
0507     return;
0508   }
0509 
0510   _isAxisVisible = visible;
0511   _dirty = true;
0512 }
0513 
0514 
0515 bool PlotAxis::axisReversed() const {
0516   return _axisReversed;
0517 }
0518 
0519 
0520 void PlotAxis::setAxisReversed(const bool enabled) {
0521   if (_axisReversed != enabled) {
0522     _axisReversed = enabled;
0523     _dirty = true;
0524   }
0525 }
0526 
0527 
0528 bool PlotAxis::axisAutoBaseOffset() const {
0529   return _axisAutoBaseOffset;
0530 }
0531 
0532 
0533 void PlotAxis::setAxisAutoBaseOffset(const bool enabled) {
0534   if (_axisAutoBaseOffset != enabled) {
0535     _axisAutoBaseOffset = enabled;
0536     _dirty = true;
0537   }
0538 }
0539 
0540 
0541 bool PlotAxis::axisBaseOffset() const {
0542   return _axisBaseOffset;
0543 }
0544 
0545 
0546 void PlotAxis::setAxisBaseOffset(const bool enabled) {
0547   if (_axisBaseOffset != enabled) {
0548     _axisBaseOffset = enabled;
0549     _dirty = true;
0550   }
0551 }
0552 
0553 
0554 void PlotAxis::setAxisForceOffsetMin(bool enabled) {
0555   if (_axisForceOffsetMin != enabled) {
0556      _axisForceOffsetMin = enabled;
0557      _dirty = true;
0558   }
0559 }
0560 
0561 
0562 bool PlotAxis::axisInterpret() const {
0563   return _axisInterpret;
0564 }
0565 
0566 
0567 void PlotAxis::setAxisInterpret(const bool enabled) {
0568   if (_axisInterpret != enabled) {
0569     _axisInterpret = enabled;
0570     _dirty = true;
0571   }
0572 }
0573 
0574 
0575 QString PlotAxis::timezoneName() const {
0576   return _timeZone.tzName();
0577 }
0578 
0579 
0580 void PlotAxis::setTimezoneName(QString timezone) {
0581   if (_timeZone.tzName() != timezone) {
0582     _timeZone.setTZ(timezone);
0583     _dirty = true;
0584   }
0585 }
0586 
0587 
0588 AxisDisplayType PlotAxis::axisDisplay() const {
0589   return _axisDisplay;
0590 }
0591 
0592 QString PlotAxis::axisDisplayFormatString() const {
0593   return _axisDisplayFormatString;
0594 }
0595 
0596 
0597 void PlotAxis::setAxisDisplay(const AxisDisplayType display) {
0598   if (_axisDisplay != display) {
0599     _axisDisplay = display;
0600     _dirty = true;
0601   }
0602 }
0603 
0604 void PlotAxis::setAxisDisplayFormatString(const QString& formatString) {
0605   if (_axisDisplayFormatString != formatString) {
0606     _axisDisplayFormatString = formatString;
0607     _dirty = true;
0608   }
0609 }
0610 
0611 AxisInterpretationType PlotAxis::axisInterpretation() const {
0612   return _axisInterpretation;
0613 }
0614 
0615 
0616 void PlotAxis::setAxisInterpretation(const AxisInterpretationType display) {
0617   if (_axisInterpretation != display) {
0618     _axisInterpretation = display;
0619     _dirty = true;
0620   }
0621 }
0622 
0623 
0624 int PlotAxis::axisLabelRotation() const {
0625   return _labelRotation;
0626 }
0627 
0628 
0629 void PlotAxis::setAxisLabelRotation(const int rotation) {
0630   if (_labelRotation != rotation) {
0631     _labelRotation = rotation;
0632     _dirty = true;
0633   }
0634 }
0635 
0636 // Function validates that the labels will not overlap.  Only functions for X-axis.
0637 void PlotAxis::validateDrawingRegion(QPainter *painter) {
0638   // Always try to use the settings requested.
0639   if (_axisOverrideMajorTicks != _axisMajorTickMode) {
0640     _axisBaseOffsetOverride = false;
0641     updateTicks();
0642   }
0643 
0644   int flags = Qt::TextSingleLine | Qt::AlignCenter;
0645   int rotation = axisLabelRotation();
0646   QTransform t;
0647   t.rotate(rotation);
0648 
0649   QVector<QPolygonF> labels;
0650   QMapIterator<double, QString> iLabelCheck(_axisLabels);
0651   while (iLabelCheck.hasNext()) {
0652     iLabelCheck.next();
0653     QRectF bound = painter->boundingRect(QRectF(), flags, iLabelCheck.value());
0654     QPointF p;
0655     QPolygonF mappedPoly;
0656 
0657     if (rotation == 0) {
0658       if (_orientation == Qt::Horizontal) {
0659         p = QPointF(plotItem()->mapXToPlot(iLabelCheck.key()), 0);
0660       } else {
0661         p = QPointF(0, plotItem()->mapYToPlot(iLabelCheck.key()));
0662       }
0663 
0664       bound.moveCenter(p);
0665       mappedPoly = QPolygonF(bound);
0666     } else {
0667       if (_orientation == Qt::Horizontal) {
0668         p = QPointF(plotItem()->mapXToPlot(iLabelCheck.key()) - bound.height() * 0.5, 0);
0669       } else {
0670         p = QPointF(0, plotItem()->mapYToPlot(iLabelCheck.key()) - bound.height() * 0.5);
0671       }
0672 
0673       mappedPoly = t.map(QPolygonF(bound));
0674       mappedPoly.translate(p - bound.topLeft());
0675     }
0676 
0677     labels << mappedPoly;
0678   }
0679 
0680   for (int i = 0; i < (labels.count() - 1); i++) {
0681     if (!labels[i].intersected(labels[i+1]).isEmpty()) {
0682       qreal labelSize;
0683       qreal plotSize;
0684       MajorTickMode old_override_major_ticks = _axisOverrideMajorTicks;
0685 
0686       if (_orientation == Qt::Horizontal) {
0687         labelSize = qMax(labels[i].boundingRect().width(), labels[i+1].boundingRect().width());
0688         plotSize = plotItem()->plotRect().width();
0689       } else {
0690         labelSize = qMax(labels[i].boundingRect().height(), labels[i+1].boundingRect().height());
0691         plotSize = plotItem()->plotRect().height();
0692       }
0693 
0694       _axisOverrideMajorTicks = convertToMajorTickMode((plotSize / labelSize) - 1, old_override_major_ticks);
0695 
0696       if (_axisOverrideMajorTicks == TicksNone) {
0697         qreal scale = plotSize / (labelSize * (TicksNormal - 1));
0698         if (scale < 1) {
0699           plotItem()->scaleAxisLabels(scale);
0700         }
0701         _axisOverrideMajorTicks = TicksCoarse;
0702       }
0703 
0704       updateTicks(true);
0705       break;
0706     }
0707   }
0708   setTicksUpdated();
0709 
0710 }
0711 
0712 
0713 MajorTickMode PlotAxis::convertToMajorTickMode(int tickCount, MajorTickMode old_mode) {
0714   MajorTickMode mode = TicksNone;
0715   if ((tickCount >= TicksVeryFine) && (old_mode > TicksVeryFine)) {
0716     mode = TicksVeryFine;
0717   } else if ((tickCount >= TicksFine) && (old_mode > TicksFine)) {
0718     mode = TicksFine;
0719   } else if ((tickCount >= TicksNormal) && (old_mode > TicksNormal)) {
0720     mode = TicksNormal;
0721   } else if ((tickCount >= TicksCoarse) && (old_mode > TicksCoarse)) {
0722     mode = TicksCoarse;
0723   }
0724   return mode;
0725 }
0726 
0727 
0728 void PlotAxis::updateLogTicks(MajorTickMode tickMode) {
0729   QMap<double, QString> labels;
0730   QList<double> ticks;
0731   QList<double> minTicks;
0732   const int format_precision = 5;
0733 
0734   double min = _orientation == Qt::Horizontal ? plotItem()->xMin() : plotItem()->yMin();
0735   double max = _orientation == Qt::Horizontal ? plotItem()->xMax() : plotItem()->yMax();
0736 
0737   double tick;
0738   if (max - min <= (double)tickMode*1.5) {
0739     // show in logarithmic mode with major ticks nicely labelled and the
0740     // specified number of minor ticks between each major label
0741     tick = 1.0;
0742   } else {
0743     // show in logarithmic mode with major ticks nicely labelled and no minor ticks
0744     tick = floor((max - min) / (double)tickMode);
0745   }
0746 
0747   int Low = ceil(min);
0748   int High = floor(max)+1;
0749   bool minorLabels = ((High - Low) <= 1);
0750   for (int i = Low - 1; i <= High; i+=tick) {
0751     double majorPoint = pow(10.0, i);
0752     if (majorPoint == 0) majorPoint = -350;
0753     if (i >= min && i <= max) {
0754       ticks << majorPoint;
0755       // 'x' is a sign to the plot item to write 10^i rather than 1.0x10^i
0756       labels.insert(majorPoint, QString("xe%1").arg(i));
0757     }
0758 
0759     if (tick == 1.0) {
0760       // draw minor lines
0761       bool first = true;
0762       double powMin = pow(10, min), powMax = pow(10, max);
0763       for (int j = 2; j < 10; j++) {
0764         double minorPoint = majorPoint * j;
0765         if (minorPoint >= powMin && minorPoint <= powMax) {
0766           minTicks << minorPoint;
0767           if (minorLabels && first) {
0768             labels.insert(minorPoint, QString::number(minorPoint, 'g', format_precision));
0769             first = false;
0770           }
0771         }
0772       }
0773     }
0774   }
0775   if (minorLabels && !minTicks.isEmpty()) {
0776     double lastMinorTick = minTicks.last();
0777     if (ticks.isEmpty() || ticks.last() < lastMinorTick) {
0778       if (labels.contains(lastMinorTick)) {
0779         labels.insert(lastMinorTick, QString::number(lastMinorTick, 'g', format_precision));
0780       }
0781     }
0782   }
0783 
0784   if (_axisMajorTicks == ticks && _axisMinorTicks == minTicks && !_dirty) {
0785     return;
0786   }
0787 
0788   _dirty = false;
0789 
0790   _axisMajorTicks = ticks;
0791   _axisMinorTicks = minTicks;
0792   _ticksUpdated = true;
0793 
0794   _axisLabels = labels;
0795   _baseLabel.clear();
0796 }
0797 
0798 // returns true if axis is linear ticks
0799 // with no specially formatted time.
0800 bool PlotAxis::isLinearTickMode() {
0801   if (_axisLog) {
0802     return false;
0803   }
0804 
0805   if (_axisInterpret) {
0806     switch (_axisDisplay) {
0807     case AXIS_DISPLAY_YYMMDDHHMMSS_SS:
0808     case AXIS_DISPLAY_DDMMYYHHMMSS_SS:
0809     case AXIS_DISPLAY_QTTEXTDATEHHMMSS_SS:
0810     case AXIS_DISPLAY_QTLOCALDATEHHMMSS_SS:
0811     case AXIS_DISPLAY_QTDATETIME_FORMAT:
0812       return false;
0813     default:
0814       return true;
0815     }
0816   }
0817   return true;
0818 }
0819 
0820 void PlotAxis::updateInterpretTicks(MajorTickMode tickMode) {
0821   double min;
0822   double max;
0823 
0824   if (_orientation == Qt::Horizontal) {
0825     min = plotItem()->projectionRect().left();
0826     max = plotItem()->projectionRect().right();
0827   } else {
0828     min = plotItem()->projectionRect().top();
0829     max = plotItem()->projectionRect().bottom();
0830   }
0831 
0832   double range = max - min;
0833   double min_jd = convertTimeValueToJD(min);
0834   double max_jd = convertTimeValueToJD(max);
0835   double range_jd = fabs(max_jd - min_jd);
0836   double base_jd;
0837   double range_u;
0838   double tickspacing_u;
0839   double tickspacing;
0840   QString units;
0841 
0842   double minimum_units = tickMode;
0843 
0844   // find base_jd, range_u, units
0845   //double valid = true;
0846   if (range_jd > minimum_units*365.0*1.0e150) {
0847     _ticksUpdated = true;
0848     _axisLabels.clear();
0849     _axisMinorTicks.clear();
0850     _axisMajorTicks.clear();
0851     _baseLabel.clear();
0852     return;
0853 
0854   } else if (range_jd > minimum_units*365.0) {
0855     // use years
0856     range_u = range_jd/365.25;
0857     units = tr(" [Years]");
0858     computeMajorTickSpacing(&tickspacing_u, &_automaticMinorTickCount, tickMode, range_u);
0859     // round base to year;
0860     base_jd = floor((min_jd - (JD1900 + 0.5))/365.25) * 365.25 + (JD1900 + 0.5) + 1.0;
0861   } else if (range_jd > minimum_units) {
0862     // use days
0863     range_u = range_jd;
0864     units = tr(" [Days]");
0865     computeMajorTickSpacing(&tickspacing_u, &_automaticMinorTickCount, tickMode, range_u);
0866     // round base to day
0867     base_jd = floor(min_jd)+1.0;
0868   } else if (range_jd > minimum_units/24.0) {
0869     // use hours
0870     range_u = range_jd*24.0;
0871     units = tr(" [Hours]");
0872     computeMajorTickSpacing(&tickspacing_u, &_automaticMinorTickCount, tickMode, range_u, Hour);
0873     // round base to hour
0874     double d_jd = min_jd - floor(min_jd);
0875     base_jd = floor(min_jd) + (floor(d_jd*24.0/tickspacing_u)+1.0)/(24.0/tickspacing_u);
0876   } else if (range_jd > minimum_units/(24.0*60.0)) {
0877     // use minutes
0878     range_u = range_jd*24.0*60.0;
0879     units = tr(" [Minutes]");
0880     computeMajorTickSpacing(&tickspacing_u, &_automaticMinorTickCount, tickMode, range_u, Minute);
0881     double d_jd = min_jd - floor(min_jd);
0882     base_jd = floor(min_jd) + (floor(d_jd*24.0*60.0/tickspacing_u)+1.0)/(24.0*60.0/tickspacing_u);
0883   } else {
0884     // use seconds
0885     range_u = range_jd*24.0*3600.0;
0886     units = tr(" [Seconds]");
0887     double d_jd = min_jd - floor(min_jd);
0888     computeMajorTickSpacing(&tickspacing_u, &_automaticMinorTickCount, tickMode, range_u, Second);
0889     base_jd = floor(min_jd) + (floor(d_jd*24.0*3600.0/tickspacing_u)+1.0)/(24.0*3600.0/tickspacing_u);
0890     if (base_jd < min_jd) base_jd = min_jd;
0891     if (base_jd > max_jd) base_jd = min_jd;
0892   }
0893 
0894   //TODO Why could range_u be 0? Then it hangs in while(1)
0895   if (range_u != 0)
0896     tickspacing = tickspacing_u * range/range_u;
0897   else
0898     tickspacing = range;
0899 
0900 
0901 
0902   if (_axisForceOffsetMin) {
0903     base_jd = min_jd;
0904   }
0905   double base = (base_jd - min_jd) * range/range_jd + min;
0906 
0907   int i0 = -floor((base-min)/tickspacing);
0908 
0909   double tick;
0910   double first_tick;
0911   QMap<double, QString> labels;
0912   QList<double> ticks;
0913   QList<double> minTicks;
0914 
0915   QString tick_label;
0916   first_tick = base+i0*tickspacing;
0917   for (int i_tick = i0; base + i_tick*tickspacing<=max; i_tick++) {
0918     tick = base+i_tick*tickspacing;
0919     ticks << tick;
0920     tick_label = '[' + QString::number(i_tick*tickspacing_u, 'g', FULL_PRECISION-2) + ']';
0921     labels.insert(tick, tick_label);
0922   }
0923 
0924   double minorTickSpacing = 0.0;
0925   int desiredTicks;
0926   if (_automaticMinorTicks) {
0927     desiredTicks = _automaticMinorTickCount;
0928   } else {
0929     desiredTicks = _axisMinorTickCount;
0930   }
0931   if (desiredTicks > 0) {
0932     minorTickSpacing = tickspacing / double(desiredTicks);
0933   }
0934 
0935   if (minorTickSpacing != 0) {
0936     double firstMinorTick = (first_tick - tickspacing) + minorTickSpacing;
0937 
0938     int i_minor = 0;
0939     double nextMinorTick = firstMinorTick;
0940     while (1) {
0941       nextMinorTick = firstMinorTick + (i_minor++ * minorTickSpacing);
0942       if (nextMinorTick > max || isnan(nextMinorTick))
0943         break;
0944       if (!ticks.contains(nextMinorTick) && (nextMinorTick > min)) {
0945         minTicks << nextMinorTick;
0946       }
0947     }
0948   }
0949 
0950   if (_axisMajorTicks == ticks && _axisMinorTicks == minTicks && !_dirty) {
0951     _ticksUpdated = false;
0952     return;
0953   }
0954 
0955   _axisLabels = labels;
0956   _axisMinorTicks = minTicks;
0957   _axisMajorTicks = ticks;
0958   _baseLabel = convertJDToDateString(base_jd, range_jd) + units;
0959   _dirty = false;
0960   _ticksUpdated = true;
0961 
0962 }
0963 
0964 QString PlotAxis::statusBarString(double X) {
0965   if (_axisInterpret) {
0966     double X_jd = convertTimeValueToJD(X);
0967     double min;
0968     double max;
0969 
0970     if (_orientation == Qt::Horizontal) {
0971       min = plotItem()->projectionRect().left();
0972       max = plotItem()->projectionRect().right();
0973     } else {
0974       min = plotItem()->projectionRect().top();
0975       max = plotItem()->projectionRect().bottom();
0976     }
0977 
0978     double min_jd = convertTimeValueToJD(min);
0979     double max_jd = convertTimeValueToJD(max);
0980     double range_jd = fabs(max_jd - min_jd);
0981 
0982     return convertJDToDateString(X_jd, range_jd/100.0);
0983   } else {
0984     return QString::number(X, 'G', FULL_PRECISION-2);
0985   }
0986 }
0987 
0988 
0989 void PlotAxis::updateLinearTicks(MajorTickMode tickMode) {
0990   QMap<double, QString> labels;
0991   QList<double> ticks;
0992   QList<double> minTicks;
0993   double min;
0994   double max;
0995   double R;
0996   double uR; // range in interpreted units
0997   double uMin; // min and max in interpreted units
0998   double uMax;
0999   double drdu = 1.0; // interpreted units per raw units;
1000   double rOffset = 0.0; // r = drdu*u + rOffset;
1001   double uMajorTickSpacing; // major Tick spacing in iterpreted units
1002 
1003   if (_orientation == Qt::Horizontal) {
1004     min = plotItem()->projectionRect().left();
1005     max = plotItem()->projectionRect().right();
1006     R = plotItem()->projectionRect().width();
1007   } else {
1008     min = plotItem()->projectionRect().top();
1009     max = plotItem()->projectionRect().bottom();
1010     R = plotItem()->projectionRect().height();
1011   }
1012 
1013   if (_axisInterpret) {
1014     uMin = convertJDtoDisplayTime(convertTimeValueToJD(min));
1015     uMax = convertJDtoDisplayTime(convertTimeValueToJD(max));
1016     uR = fabs(uMax - uMin);
1017     drdu = (max - min)/(uMax - uMin);
1018     rOffset = min - drdu * uMin;
1019   } else {
1020     uR = R;
1021     uMin = min;
1022     uMax = max;
1023   }
1024 
1025   computeMajorTickSpacing(&uMajorTickSpacing, &_automaticMinorTickCount, tickMode, uR);
1026 
1027   double uFirstTick;
1028   bool offset_is_min = (_axisInterpret || _axisBaseOffset || _axisBaseOffsetOverride ) && (_axisForceOffsetMin);
1029   if (offset_is_min) {
1030     uFirstTick = uMin;
1031   } else {
1032     uFirstTick = ceil(uMin / uMajorTickSpacing) * uMajorTickSpacing;
1033   }
1034   double firstTick = uFirstTick*drdu + rOffset;
1035   double majorTickSpacing = uMajorTickSpacing * drdu;
1036 
1037   int i = 0;
1038   double lastTick = 12345678;
1039   while (1) {
1040     double uNextTick = uFirstTick + i++ * uMajorTickSpacing;
1041     if (fabs(uNextTick)<uMajorTickSpacing*0.5) { // fix roundoff...
1042       uNextTick = 0.0;
1043     }
1044     if (uNextTick > uMax)
1045       break;    
1046     double nextTick = uNextTick * drdu + rOffset;
1047     if (lastTick == uNextTick) // prevent endless loop
1048       break;
1049     lastTick = nextTick;
1050     ticks << nextTick;
1051     // FULL_PRECISION - 2 because round off errors mean you never actually quite get
1052     // full precision...
1053     labels.insert(nextTick, QString::number(uNextTick, 'g', FULL_PRECISION-2));
1054   }
1055 
1056   double minorTickSpacing = 0;
1057   int desiredTicks;
1058   if (_automaticMinorTicks) {
1059     desiredTicks = _automaticMinorTickCount;
1060   } else {
1061     desiredTicks = _axisMinorTickCount;
1062   }
1063   if (desiredTicks > 0) {
1064     minorTickSpacing = majorTickSpacing / desiredTicks;
1065   }
1066 
1067   if (minorTickSpacing != 0) {
1068     double firstMinorTick = (firstTick - majorTickSpacing) + minorTickSpacing;
1069 
1070     i = 0;
1071     double nextMinorTick = firstMinorTick;
1072     while (1) {
1073       nextMinorTick = firstMinorTick + (i++ * minorTickSpacing);
1074       if (nextMinorTick > max)
1075         break;
1076       if (!ticks.contains(nextMinorTick) && nextMinorTick > min) {
1077         minTicks << nextMinorTick;
1078       }
1079     }
1080   }
1081 
1082   if (_axisMajorTicks == ticks && _axisMinorTicks == minTicks && !_dirty) {
1083     return;
1084   }
1085 
1086   _dirty = false;
1087 
1088   _axisMajorTicks = ticks;
1089   _axisMinorTicks = minTicks;
1090   _ticksUpdated = true;
1091 
1092   _axisLabels.clear();
1093   _baseLabel.clear();
1094 
1095   int longest = 0, shortest = 1000;
1096   double base=10;
1097   QMapIterator<double, QString> iLabel(labels);
1098   while (iLabel.hasNext()) {
1099     iLabel.next();
1100     if (iLabel.value().length() < shortest) {
1101       shortest = iLabel.value().length();
1102       base = iLabel.key();
1103     }
1104     if (iLabel.value().length() > longest) {
1105       longest = iLabel.value().length();
1106     }
1107   }
1108   if (offset_is_min) {
1109     base = ticks[0];
1110   }
1111 
1112   // (shortest > 3) so that you don't use automatic base/offset mode when
1113   // it wouldn't actually take up less space.
1114   if (_axisBaseOffset || ((longest > _axisSignificantDigits)&&(shortest>3)) || _axisBaseOffsetOverride ) {
1115     _baseLabel = QString::number(base, 'g', FULL_PRECISION-2);
1116     QMapIterator<double, QString> i(labels);
1117     while (i.hasNext()) {
1118       i.next();
1119       double offset;
1120       offset = i.key() - base;
1121       QString label, num;
1122       if (offset < 0) {
1123         label += "-[";
1124         offset = offset * -1;
1125       } else if (offset > 0) {
1126         label += "+[";
1127       }
1128 
1129       if (offset==0.0) {
1130         num = "[0";
1131       } else if ((fabs(offset)>9.9E3)||(fabs(offset)<0.99E-3)) {
1132         num = QString::number(offset, 'e', 1);
1133       } else {
1134         num = QString::number(offset, 'g', 5);
1135       }
1136 
1137       label = label + num + ']';
1138       _axisLabels.insert(i.key(), label);
1139     }
1140   } else {
1141     _axisLabels = labels;
1142   }
1143 }
1144 
1145 void PlotAxis::updateTicks(bool useOverrideTicks) {
1146   MajorTickMode majorTickCount;
1147   if (useOverrideTicks) {
1148     majorTickCount = _axisOverrideMajorTicks;
1149   } else {
1150     _axisOverrideMajorTicks = _axisMajorTickMode;
1151     majorTickCount = _axisMajorTickMode;
1152     _axisBaseOffsetOverride = false;
1153   }
1154 
1155   plotItem()->updateScale();
1156 
1157   if (_axisLog) {
1158     updateLogTicks(majorTickCount);
1159     return;
1160   } else if (isLinearTickMode()) {
1161     updateLinearTicks(majorTickCount);
1162     return;
1163   } else {
1164     updateInterpretTicks(majorTickCount);
1165     return;
1166   }
1167 }
1168 
1169 
1170 void PlotAxis::copyProperties(PlotAxis *source) {
1171   if (source) {
1172     setAxisVisible(source->isAxisVisible());
1173     setAxisLog(source->axisLog());
1174     setAxisReversed(source->axisReversed());
1175     setAxisBaseOffset(source->axisBaseOffset());
1176     setAxisForceOffsetMin(source->axisForceOffsetMin());
1177     setAxisInterpret(source->axisInterpret());
1178     setAxisInterpretation(source->axisInterpretation());
1179     setAxisDisplay(source->axisDisplay());
1180     setAxisDisplayFormatString(source->axisDisplayFormatString());
1181     setAxisMajorTickMode(source->axisMajorTickMode());
1182     setAxisMinorTickCount(source->axisMinorTickCount());
1183     setAxisAutoMinorTicks(source->axisAutoMinorTicks());
1184     setDrawAxisMajorTicks(source->drawAxisMajorTicks());
1185     setDrawAxisMinorTicks(source->drawAxisMinorTicks());
1186     setDrawAxisMajorGridLines(source->drawAxisMajorGridLines());
1187     setDrawAxisMinorGridLines(source->drawAxisMinorGridLines());
1188     setAxisMajorGridLineColor(source->axisMajorGridLineColor());
1189     setAxisMinorGridLineColor(source->axisMinorGridLineColor());
1190     setAxisMajorGridLineStyle(source->axisMajorGridLineStyle());
1191     setAxisMinorGridLineStyle(source->axisMinorGridLineStyle());
1192     setAxisMajorGridLineWidth(source->axisMinorGridLineWidth());
1193     setAxisMinorGridLineWidth(source->axisMinorGridLineWidth());
1194     setAxisSignificantDigits(source->axisSignificantDigits());
1195     setAxisLabelRotation(source->axisLabelRotation());
1196     setAxisZoomMode(source->axisZoomMode());
1197   }
1198 }
1199 
1200 void PlotAxis::saveAsDialogDefaults(const QString &group) const {
1201   dialogDefaults().setValue(group+"Visible", QVariant(isAxisVisible()).toString());
1202   dialogDefaults().setValue(group+"Log", QVariant(axisLog()).toString());
1203   dialogDefaults().setValue(group+"Reversed", QVariant(axisReversed()).toString());
1204   dialogDefaults().setValue(group+"AutoBaseOffset", QVariant(axisAutoBaseOffset()).toString());
1205   dialogDefaults().setValue(group+"BaseOffset", QVariant(axisBaseOffset()).toString());
1206   dialogDefaults().setValue(group+"ForceOffsetMin", QVariant(axisForceOffsetMin()).toString());
1207   dialogDefaults().setValue(group+"Interpret", QVariant(axisInterpret()).toString());
1208   dialogDefaults().setValue(group+"Interpretation", QVariant(axisInterpretation()).toString());
1209   dialogDefaults().setValue(group+"Display", QVariant(axisDisplay()).toString());
1210   dialogDefaults().setValue(group+"DisplayFormatString", QVariant(axisDisplayFormatString()).toString());
1211   dialogDefaults().setValue(group+"Timezone", QVariant(timezoneName()));
1212   dialogDefaults().setValue(group+"MajorTickMode", QVariant(axisMajorTickMode()).toString());
1213   dialogDefaults().setValue(group+"MinorTickCount", QVariant(axisMinorTickCount()).toString());
1214   dialogDefaults().setValue(group+"AutoMinorTickCount", QVariant(axisAutoMinorTicks()).toString());
1215   dialogDefaults().setValue(group+"DrawMajorTicks", QVariant(drawAxisMajorTicks()).toString());
1216   dialogDefaults().setValue(group+"DrawMajorTicks", QVariant(drawAxisMajorTicks()).toString());
1217   dialogDefaults().setValue(group+"DrawMinorTicks", QVariant(drawAxisMinorTicks()).toString());
1218   dialogDefaults().setValue(group+"DrawMajorGridLines", QVariant(drawAxisMajorGridLines()).toString());
1219   dialogDefaults().setValue(group+"DrawMinorGridLines", QVariant(drawAxisMinorGridLines()).toString());
1220   dialogDefaults().setValue(group+"DrawMajorGridLinecolor", QVariant(axisMajorGridLineColor()).toString());
1221   dialogDefaults().setValue(group+"DrawMinorGridLinecolor", QVariant(axisMinorGridLineColor()).toString());
1222   dialogDefaults().setValue(group+"DrawMajorGridLinestyle", QVariant((int)axisMajorGridLineStyle()).toString());
1223   dialogDefaults().setValue(group+"DrawMinorGridLinestyle", QVariant((int)axisMinorGridLineStyle()).toString());
1224   dialogDefaults().setValue(group+"DrawMajorGridLinewidth", QVariant(axisMajorGridLineWidth()).toString());
1225   dialogDefaults().setValue(group+"DrawMinorGridLinewidth", QVariant(axisMinorGridLineWidth()).toString());
1226   dialogDefaults().setValue(group+"SignificantDigits", QVariant(axisSignificantDigits()).toString());
1227   dialogDefaults().setValue(group+"Rotation", QVariant(axisLabelRotation()).toString());
1228 }
1229 
1230 void PlotAxis::saveInPlot(QXmlStreamWriter &xml, QString axisId) {
1231   xml.writeStartElement("plotaxis");
1232   xml.writeAttribute("id", axisId);
1233   xml.writeAttribute("visible", QVariant(isAxisVisible()).toString());
1234   xml.writeAttribute("log", QVariant(axisLog()).toString());
1235   xml.writeAttribute("reversed", QVariant(axisReversed()).toString());
1236   xml.writeAttribute("autobaseoffset", QVariant(axisAutoBaseOffset()).toString());
1237   xml.writeAttribute("baseoffset", QVariant(axisBaseOffset()).toString());
1238   xml.writeAttribute("forceoffsetmin", QVariant(axisForceOffsetMin()).toString());
1239   xml.writeAttribute("interpret", QVariant(axisInterpret()).toString());
1240   xml.writeAttribute("interpretation", QVariant(axisInterpretation()).toString());
1241   xml.writeAttribute("display", QVariant(axisDisplay()).toString());
1242   xml.writeAttribute("displayformatstring", QVariant(axisDisplayFormatString()).toString());
1243   xml.writeAttribute("majortickmode", QVariant(axisMajorTickMode()).toString());
1244   xml.writeAttribute("minortickcount", QVariant(axisMinorTickCount()).toString());
1245   xml.writeAttribute("autominortickcount", QVariant(axisAutoMinorTicks()).toString());
1246   xml.writeAttribute("drawmajorticks", QVariant(drawAxisMajorTicks()).toString());
1247   xml.writeAttribute("drawminorticks", QVariant(drawAxisMinorTicks()).toString());
1248   xml.writeAttribute("drawmajorgridlines", QVariant(drawAxisMajorGridLines()).toString());
1249   xml.writeAttribute("drawminorgridlines", QVariant(drawAxisMinorGridLines()).toString());
1250   xml.writeAttribute("drawmajorgridlinecolor", QVariant(axisMajorGridLineColor()).toString());
1251   xml.writeAttribute("drawminorgridlinecolor", QVariant(axisMinorGridLineColor()).toString());
1252   xml.writeAttribute("drawmajorgridlinestyle", QVariant((int)axisMajorGridLineStyle()).toString());
1253   xml.writeAttribute("drawminorgridlinestyle", QVariant((int)axisMinorGridLineStyle()).toString());
1254   xml.writeAttribute("drawmajorgridlinewidth", QVariant(axisMajorGridLineWidth()).toString());
1255   xml.writeAttribute("drawminorgridlinewidth", QVariant(axisMinorGridLineWidth()).toString());
1256   xml.writeAttribute("significantdigits", QVariant(axisSignificantDigits()).toString());
1257   xml.writeAttribute("rotation", QVariant(axisLabelRotation()).toString());
1258   xml.writeAttribute("zoommode", QVariant(axisZoomMode()).toString());
1259   xml.writeAttribute("timezonename", _timeZone.tzName());
1260   xml.writeAttribute("timezoneoffset", QVariant(_timeZone.gmtOffset(0)).toString());
1261   _axisPlotMarkers.saveInPlot(xml);
1262   xml.writeEndElement();
1263 }
1264 
1265 
1266 bool PlotAxis::configureFromXml(QXmlStreamReader &xml, ObjectStore *store) {
1267   bool validTag = true;
1268 
1269   QString primaryTag = xml.name().toString();
1270   QXmlStreamAttributes attrs = xml.attributes();
1271   QStringRef av = attrs.value("visible");
1272   if (!av.isNull()) {
1273     setAxisVisible(QVariant(av.toString()).toBool());
1274   }
1275   av = attrs.value("log");
1276   if (!av.isNull()) {
1277     setAxisLog(QVariant(av.toString()).toBool());
1278   }
1279   av = attrs.value("reversed");
1280   if (!av.isNull()) {
1281     setAxisReversed(QVariant(av.toString()).toBool());
1282   }
1283   av = attrs.value("autobaseoffset");
1284   if (!av.isNull()) {
1285     setAxisAutoBaseOffset(QVariant(av.toString()).toBool());
1286   }
1287   av = attrs.value("baseoffset");
1288   if (!av.isNull()) {
1289     setAxisBaseOffset(QVariant(av.toString()).toBool());
1290   }
1291   av = attrs.value("forceoffsetmin");
1292   if (!av.isNull()) {
1293     setAxisForceOffsetMin(QVariant(av.toString()).toBool());
1294   }
1295   av = attrs.value("interpret");
1296   if (!av.isNull()) {
1297     setAxisInterpret(QVariant(av.toString()).toBool());
1298   }
1299   av = attrs.value("interpretation");
1300   if (!av.isNull()) {
1301     setAxisInterpretation((AxisInterpretationType)QVariant(av.toString()).toInt());
1302   }
1303   av = attrs.value("display");
1304   if (!av.isNull()) {
1305     setAxisDisplay((AxisDisplayType)QVariant(av.toString()).toInt());
1306   }
1307   av = attrs.value("displayformatstring");
1308   if (!av.isNull()) {
1309     setAxisDisplayFormatString(av.toString());
1310   }
1311   av = attrs.value("majortickmode");
1312   if (!av.isNull()) {
1313     setAxisMajorTickMode((MajorTickMode)QVariant(av.toString()).toInt());
1314   }
1315   av = attrs.value("minortickcount");
1316   if (!av.isNull()) {
1317     setAxisMinorTickCount(QVariant(av.toString()).toInt());
1318   }
1319   av = attrs.value("autominortickcount");
1320   if (!av.isNull()) {
1321     setAxisAutoMinorTicks(QVariant(av.toString()).toBool());
1322   }
1323   av = attrs.value("drawmajorticks");
1324   if (!av.isNull()) {
1325     setDrawAxisMajorTicks(QVariant(av.toString()).toBool());
1326   }
1327   av = attrs.value("drawminorticks");
1328   if (!av.isNull()) {
1329     setDrawAxisMinorTicks(QVariant(av.toString()).toBool());
1330   }
1331   av = attrs.value("drawmajorgridlines");
1332   if (!av.isNull()) {
1333     setDrawAxisMajorGridLines(QVariant(av.toString()).toBool());
1334   }
1335   av = attrs.value("drawminorgridlines");
1336   if (!av.isNull()) {
1337     setDrawAxisMinorGridLines(QVariant(av.toString()).toBool());
1338   }
1339   av = attrs.value("drawmajorgridlinecolor");
1340   if (!av.isNull()) {
1341     setAxisMajorGridLineColor(QColor(av.toString()));
1342   }
1343   av = attrs.value("drawminorgridlinecolor");
1344   if (!av.isNull()) {
1345     setAxisMinorGridLineColor(QColor(av.toString()));
1346   }
1347   av = attrs.value("drawmajorgridlinestyle");
1348   if (!av.isNull()) {
1349     setAxisMajorGridLineStyle((Qt::PenStyle)QVariant(av.toString()).toInt());
1350   }
1351   av = attrs.value("drawminorgridlinestyle");
1352   if (!av.isNull()) {
1353     setAxisMinorGridLineStyle((Qt::PenStyle)QVariant(av.toString()).toInt());
1354   }
1355   av = attrs.value("drawmajorgridlinewidth");
1356   if (!av.isNull()) {
1357     setAxisMajorGridLineWidth((qreal)QVariant(av.toString()).toDouble());
1358   }
1359   av = attrs.value("drawminorgridlinewidth");
1360   if (!av.isNull()) {
1361     setAxisMinorGridLineWidth((qreal)QVariant(av.toString()).toDouble());
1362   }
1363   av = attrs.value("significantdigits");
1364   if (!av.isNull()) {
1365     setAxisSignificantDigits(QVariant(av.toString()).toInt());
1366   }
1367   av = attrs.value("rotation");
1368   if (!av.isNull()) {
1369     setAxisLabelRotation(QVariant(av.toString()).toInt());
1370   }
1371   av = attrs.value("zoommode");
1372   if (!av.isNull()) {
1373     setAxisZoomMode((PlotAxis::ZoomMode)av.toString().toInt());
1374   }
1375   av = attrs.value("timezonename");
1376   if (!av.isNull()) {
1377     setTimezoneName(av.toString());
1378     // fixme: handle unrecognised timezone name by using timezoneoffset
1379   }
1380 
1381   QString expectedEnd;
1382   while (!(xml.isEndElement() && (xml.name().toString() == primaryTag))) {
1383    if (xml.isStartElement() && xml.name().toString() == "plotmarkers") {
1384       validTag = _axisPlotMarkers.configureFromXml(xml, store);
1385     } else if (xml.isEndElement()) {
1386       if (xml.name().toString() != expectedEnd) {
1387         validTag = false;
1388         break;
1389       }
1390     }
1391     xml.readNext();
1392   }
1393 
1394   return validTag;
1395 }
1396 
1397 
1398 }
1399 
1400 // vim: ts=2 sw=2 et