UPlot.cpp
Go to the documentation of this file.
00001 /*
00002 *  utilite is a cross-platform library with
00003 *  useful utilities for fast and small developing.
00004 *  Copyright (C) 2010  Mathieu Labbe
00005 *
00006 *  utilite is free library: you can redistribute it and/or modify
00007 *  it under the terms of the GNU Lesser General Public License as published by
00008 *  the Free Software Foundation, either version 3 of the License, or
00009 *  (at your option) any later version.
00010 *
00011 *  utilite is distributed in the hope that it will be useful,
00012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 *  GNU Lesser General Public License for more details.
00015 *
00016 *  You should have received a copy of the GNU Lesser General Public License
00017 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 */
00019 
00020 #include "rtabmap/utilite/UPlot.h"
00021 #include "rtabmap/utilite/ULogger.h"
00022 #include "rtabmap/utilite/UMath.h"
00023 
00024 #include <QGraphicsScene>
00025 #include <QGraphicsView>
00026 #include <QGraphicsItem>
00027 #include <QGraphicsRectItem>
00028 #include <QHBoxLayout>
00029 #include <QFormLayout>
00030 #include <QtGui/QResizeEvent>
00031 #include <QtGui/QMouseEvent>
00032 #include <QtCore/QTime>
00033 #include <QtCore/QTimer>
00034 #include <QtCore/QFileInfo>
00035 #include <QPushButton>
00036 #include <QToolButton>
00037 #include <QLabel>
00038 #include <QMenu>
00039 #include <QInputDialog>
00040 #include <QMessageBox>
00041 #include <QFileDialog>
00042 #include <QtGui/QClipboard>
00043 #include <QApplication>
00044 #include <QPrinter>
00045 #include <QColorDialog>
00046 #include <QToolTip>
00047 #ifdef QT_SVG_LIB
00048 #include <QtSvg/QSvgGenerator>
00049 #endif
00050 #include <cmath>
00051 
00052 #define PRINT_DEBUG 0
00053 
00054 UPlotItem::UPlotItem(qreal dataX, qreal dataY, qreal width) :
00055         QGraphicsEllipseItem(0, 0, width, width, 0),
00056         _previousItem(0),
00057         _nextItem(0),
00058         _text(0),
00059         _textBackground(0)
00060 {
00061         this->init(dataX, dataY);
00062 }
00063 
00064 UPlotItem::UPlotItem(const QPointF & data, qreal width) :
00065         QGraphicsEllipseItem(0, 0, width, width, 0),
00066         _previousItem(0),
00067         _nextItem(0),
00068         _text(0),
00069         _textBackground(0)
00070 {
00071         this->init(data.x(), data.y());
00072 }
00073 
00074 void UPlotItem::init(qreal dataX, qreal dataY)
00075 {
00076         _data.setX(dataX);
00077         _data.setY(dataY);
00078         this->setAcceptHoverEvents(true);
00079         this->setFlag(QGraphicsItem::ItemIsFocusable, true);
00080 }
00081 
00082 UPlotItem::~UPlotItem()
00083 {
00084         if(_previousItem && _nextItem)
00085         {
00086                 _previousItem->setNextItem(_nextItem);
00087                 _nextItem->setPreviousItem(_previousItem);
00088         }
00089         else if(_previousItem)
00090         {
00091                 _previousItem->setNextItem(0);
00092         }
00093         else if(_nextItem)
00094         {
00095                 _nextItem->setPreviousItem(0);
00096         }
00097 }
00098 
00099 void UPlotItem::setData(const QPointF & data)
00100 {
00101         _data = data;
00102 }
00103 
00104 void UPlotItem::setNextItem(UPlotItem * nextItem)
00105 {
00106         if(_nextItem != nextItem)
00107         {
00108                 _nextItem = nextItem;
00109                 if(nextItem)
00110                 {
00111                         nextItem->setPreviousItem(this);
00112                 }
00113         }
00114 }
00115 
00116 void UPlotItem::setPreviousItem(UPlotItem * previousItem)
00117 {
00118         if(_previousItem != previousItem)
00119         {
00120                 _previousItem = previousItem;
00121                 if(previousItem)
00122                 {
00123                         previousItem->setNextItem(this);
00124                 }
00125         }
00126 }
00127 
00128 void UPlotItem::showDescription(bool shown)
00129 {
00130         if(!_textBackground)
00131         {
00132                 _textBackground = new QGraphicsRectItem(this);
00133                 _textBackground->setBrush(QBrush(QColor(255, 255, 255, 200)));
00134                 _textBackground->setPen(Qt::NoPen);
00135                 _textBackground->setZValue(this->zValue()+1);
00136                 _textBackground->setVisible(false);
00137 
00138                 _text = new QGraphicsTextItem(_textBackground);
00139         }
00140 
00141         if(this->parentItem() && this->parentItem() != _textBackground->parentItem())
00142         {
00143                 _textBackground->setParentItem(this->parentItem());
00144                 _textBackground->setZValue(this->zValue()+1);
00145         }
00146 
00147         if(this->scene() && shown)
00148         {
00149                 _textBackground->setVisible(true);
00150                 _text->setPlainText(QString("(%1,%2)").arg(_data.x()).arg(_data.y()));
00151 
00152                 this->setPen(QPen(this->pen().color(), 2));
00153 
00154                 QRectF rect = this->scene()->sceneRect();
00155                 QPointF p = this->pos();
00156                 QRectF br = _text->boundingRect();
00157                 _textBackground->setRect(QRectF(0,0,br.width(), br.height()));
00158 
00159                 // Make sure the text is always in the scene
00160                 if(p.x() - br.width() < 0)
00161                 {
00162                         p.setX(0);
00163                 }
00164                 else if(p.x() > rect.width())
00165                 {
00166                         p.setX(rect.width() - br.width());
00167                 }
00168                 else
00169                 {
00170                         p.setX(p.x() - br.width());
00171                 }
00172 
00173                 if(p.y() - br.height() < 0)
00174                 {
00175                         p.setY(0);
00176                 }
00177                 else
00178                 {
00179                         p.setY(p.y() - br.height());
00180                 }
00181 
00182                 _textBackground->setPos(p);
00183         }
00184         else
00185         {
00186                 this->setPen(QPen(this->pen().color(), 1));
00187                 _textBackground->setVisible(false);
00188         }
00189 }
00190 
00191 void UPlotItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
00192 {
00193         this->showDescription(true);
00194         QGraphicsEllipseItem::hoverEnterEvent(event);
00195 }
00196 
00197 void UPlotItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
00198 {
00199         if(!this->hasFocus())
00200         {
00201                 this->showDescription(false);
00202         }
00203         QGraphicsEllipseItem::hoverLeaveEvent(event);
00204 }
00205 
00206 void UPlotItem::focusInEvent(QFocusEvent * event)
00207 {
00208         this->showDescription(true);
00209         QGraphicsEllipseItem::focusInEvent(event);
00210 }
00211 
00212 void UPlotItem::focusOutEvent(QFocusEvent * event)
00213 {
00214         this->showDescription(false);
00215         QGraphicsEllipseItem::focusOutEvent(event);
00216 }
00217 
00218 void UPlotItem::keyReleaseEvent(QKeyEvent * keyEvent)
00219 {
00220         //Get the next/previous visible item
00221         if(keyEvent->key() == Qt::Key_Right)
00222         {
00223                 UPlotItem * next = _nextItem;
00224                 while(next && !next->isVisible())
00225                 {
00226                         next = next->nextItem();
00227                 }
00228                 if(next && next->isVisible())
00229                 {
00230                         this->clearFocus();
00231                         next->setFocus();
00232                 }
00233         }
00234         else if(keyEvent->key() == Qt::Key_Left)
00235         {
00236                 UPlotItem * previous = _previousItem;
00237                 while(previous && !previous->isVisible())
00238                 {
00239                         previous = previous->previousItem();
00240                 }
00241                 if(previous && previous->isVisible())
00242                 {
00243                         this->clearFocus();
00244                         previous->setFocus();
00245                 }
00246         }
00247         QGraphicsEllipseItem::keyReleaseEvent(keyEvent);
00248 }
00249 
00250 
00251 
00252 
00253 
00254 UPlotCurve::UPlotCurve(const QString & name, QObject * parent) :
00255         QObject(parent),
00256         _plot(0),
00257         _name(name),
00258         _xIncrement(1),
00259         _xStart(0),
00260         _visible(true),
00261         _valuesShown(false),
00262         _itemsColor(0,0,0,150)
00263 {
00264         _rootItem = new QGraphicsRectItem();
00265 }
00266 
00267 UPlotCurve::UPlotCurve(const QString & name, QVector<UPlotItem *> data, QObject * parent) :
00268         QObject(parent),
00269         _plot(0),
00270         _name(name),
00271         _xIncrement(1),
00272         _xStart(0),
00273         _visible(true),
00274         _valuesShown(false),
00275         _itemsColor(0,0,0,150)
00276 {
00277         _rootItem = new QGraphicsRectItem();
00278         this->setData(data);
00279 }
00280 
00281 UPlotCurve::UPlotCurve(const QString & name, const QVector<float> & x, const QVector<float> & y, QObject * parent) :
00282         QObject(parent),
00283         _plot(0),
00284         _name(name),
00285         _xIncrement(1),
00286         _xStart(0),
00287         _visible(true),
00288         _valuesShown(false),
00289         _itemsColor(0,0,0,150)
00290 {
00291         _rootItem = new QGraphicsRectItem();
00292         this->setData(x, y);
00293 }
00294 
00295 UPlotCurve::~UPlotCurve()
00296 {
00297         if(_plot)
00298         {
00299                 _plot->removeCurve(this);
00300         }
00301 #if PRINT_DEBUG
00302         ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
00303 #endif
00304         this->clear();
00305         delete _rootItem;
00306 }
00307 
00308 void UPlotCurve::attach(UPlot * plot)
00309 {
00310         if(!plot || plot == _plot)
00311         {
00312                 return;
00313         }
00314         if(_plot)
00315         {
00316                 _plot->removeCurve(this);
00317         }
00318         _plot = plot;
00319         _plot->addItem(_rootItem);
00320 }
00321 
00322 void UPlotCurve::detach(UPlot * plot)
00323 {
00324 #if PRINT_DEBUG
00325         ULOGGER_DEBUG("curve=\"%s\" from plot=\"%s\"", this->objectName().toStdString().c_str(), plot?plot->objectName().toStdString().c_str():"");
00326 #endif
00327         if(plot && _plot == plot)
00328         {
00329                 _plot = 0;
00330                 if(_rootItem->scene())
00331                 {
00332                         _rootItem->scene()->removeItem(_rootItem);
00333                 }
00334         }
00335 }
00336 
00337 void UPlotCurve::updateMinMax()
00338 {
00339         float x,y;
00340         const UPlotItem * item;
00341         if(!_items.size())
00342         {
00343                 _minMax = QVector<float>();
00344         }
00345         else
00346         {
00347                 _minMax = QVector<float>(4);
00348         }
00349         for(int i=0; i<_items.size(); ++i)
00350         {
00351                 item = qgraphicsitem_cast<const UPlotItem *>(_items.at(i));
00352                 if(item)
00353                 {
00354                         x = item->data().x();
00355                         y = item->data().y();
00356                         if(i==0)
00357                         {
00358                                 _minMax[0] = x;
00359                                 _minMax[1] = x;
00360                                 _minMax[2] = y;
00361                                 _minMax[3] = y;
00362                         }
00363                         else
00364                         {
00365                                 if(x<_minMax[0]) _minMax[0] = x;
00366                                 if(x>_minMax[1]) _minMax[1] = x;
00367                                 if(y<_minMax[2]) _minMax[2] = y;
00368                                 if(y>_minMax[3]) _minMax[3] = y;
00369                         }
00370                 }
00371         }
00372 }
00373 
00374 void UPlotCurve::_addValue(UPlotItem * data)
00375 {
00376         // add item
00377         if(data)
00378         {
00379                 float x = data->data().x();
00380                 float y = data->data().y();
00381 
00382                 if(_minMax.size() != 4)
00383                 {
00384                         _minMax = QVector<float>(4);
00385                 }
00386                 if(_items.size())
00387                 {
00388                         data->setPreviousItem((UPlotItem *)_items.last());
00389                         QGraphicsLineItem * line = new QGraphicsLineItem(_rootItem);
00390                         line->setPen(_pen);
00391                         line->setVisible(false);
00392                         _items.append(line);
00393                         //Update min/max
00394                         if(x<_minMax[0]) _minMax[0] = x;
00395                         if(x>_minMax[1]) _minMax[1] = x;
00396                         if(y<_minMax[2]) _minMax[2] = y;
00397                         if(y>_minMax[3]) _minMax[3] = y;
00398                 }
00399                 else
00400                 {
00401                         _minMax[0] = x;
00402                         _minMax[1] = x;
00403                         _minMax[2] = y;
00404                         _minMax[3] = y;
00405                 }
00406                 data->setParentItem(_rootItem);
00407                 data->setZValue(1);
00408                 _items.append(data);
00409                 data->setVisible(false);
00410                 QPen pen = data->pen();
00411                 pen.setColor(_itemsColor);
00412                 data->setPen(pen);
00413         }
00414         else
00415         {
00416                 ULOGGER_ERROR("Data is null ?!?");
00417         }
00418 }
00419 
00420 void UPlotCurve::addValue(UPlotItem * data)
00421 {
00422         // add item
00423         if(data)
00424         {
00425                 this->_addValue(data);
00426                 Q_EMIT dataChanged(this);
00427         }
00428 }
00429 
00430 void UPlotCurve::addValue(float x, float y)
00431 {
00432         if(_items.size() &&
00433                 _minMax[0] != _minMax[1] &&
00434                 x < _minMax[1])
00435         {
00436                 UWARN("New value (%f) added to curve \"%s\" is smaller "
00437                           "than the last added (%f). Clearing the curve.",
00438                                 x, this->name().toStdString().c_str(), ((UPlotItem*)_items.back())->data().x());
00439                 this->clear();
00440         }
00441 
00442         float width = 2; // TODO warn : hard coded value!
00443         this->addValue(new UPlotItem(x,y,width));
00444 }
00445 
00446 void UPlotCurve::addValue(float y)
00447 {
00448         float x = 0;
00449         if(_items.size())
00450         {
00451                 UPlotItem * lastItem = (UPlotItem *)_items.last();
00452                 x = lastItem->data().x() + _xIncrement;
00453         }
00454         else
00455         {
00456                 x = _xStart;
00457         }
00458         this->addValue(x,y);
00459 }
00460 
00461 void UPlotCurve::addValue(const QString & value)
00462 {
00463         bool ok;
00464         float v = value.toFloat(&ok);
00465         if(ok)
00466         {
00467                 this->addValue(v);
00468         }
00469         else
00470         {
00471                 ULOGGER_ERROR("Value not valid, must be a number, received %s", value.toStdString().c_str());
00472         }
00473 }
00474 
00475 void UPlotCurve::addValues(QVector<UPlotItem *> & data)
00476 {
00477         for(int i=0; i<data.size(); ++i)
00478         {
00479                 this->_addValue(data.at(i));
00480         }
00481         Q_EMIT dataChanged(this);
00482 }
00483 
00484 void UPlotCurve::addValues(const QVector<float> & xs, const QVector<float> & ys)
00485 {
00486         float width = 2; // TODO warn : hard coded value!
00487         for(int i=0; i<xs.size() && i<ys.size(); ++i)
00488         {
00489                 this->_addValue(new UPlotItem(xs.at(i),ys.at(i),width));
00490         }
00491         Q_EMIT dataChanged(this);
00492 }
00493 
00494 void UPlotCurve::addValues(const QVector<float> & ys)
00495 {
00496         float x = 0;
00497         float width = 2; // TODO warn : hard coded value!
00498         for(int i=0; i<ys.size(); ++i)
00499         {
00500                 if(_items.size())
00501                 {
00502                         UPlotItem * lastItem = (UPlotItem *)_items.last();
00503                         x = lastItem->data().x() + _xIncrement;
00504                 }
00505                 else
00506                 {
00507                         x = _xStart;
00508                 }
00509                 this->_addValue(new UPlotItem(x,ys.at(i),width));
00510         }
00511         Q_EMIT dataChanged(this);
00512 }
00513 
00514 void UPlotCurve::addValues(const QVector<int> & ys)
00515 {
00516         float x = 0;
00517         float width = 2; // TODO warn : hard coded value!
00518         for(int i=0; i<ys.size(); ++i)
00519         {
00520                 if(_items.size())
00521                 {
00522                         UPlotItem * lastItem = (UPlotItem *)_items.last();
00523                         x = lastItem->data().x() + _xIncrement;
00524                 }
00525                 else
00526                 {
00527                         x = _xStart;
00528                 }
00529                 this->_addValue(new UPlotItem(x,ys.at(i),width));
00530         }
00531         Q_EMIT dataChanged(this);
00532 }
00533 
00534 void UPlotCurve::addValues(const std::vector<int> & ys)
00535 {
00536         float x = 0;
00537         float width = 2; // TODO warn : hard coded value!
00538         for(unsigned int i=0; i<ys.size(); ++i)
00539         {
00540                 if(_items.size())
00541                 {
00542                         UPlotItem * lastItem = (UPlotItem *)_items.last();
00543                         x = lastItem->data().x() + _xIncrement;
00544                 }
00545                 else
00546                 {
00547                         x = _xStart;
00548                 }
00549                 this->_addValue(new UPlotItem(x,ys.at(i),width));
00550         }
00551         Q_EMIT dataChanged(this);
00552 }
00553 
00554 void UPlotCurve::addValues(const std::vector<float> & ys)
00555 {
00556         float x = 0;
00557         float width = 2; // TODO warn : hard coded value!
00558         for(unsigned int i=0; i<ys.size(); ++i)
00559         {
00560                 if(_items.size())
00561                 {
00562                         UPlotItem * lastItem = (UPlotItem *)_items.last();
00563                         x = lastItem->data().x() + _xIncrement;
00564                 }
00565                 else
00566                 {
00567                         x = _xStart;
00568                 }
00569                 this->_addValue(new UPlotItem(x,ys.at(i),width));
00570         }
00571         Q_EMIT dataChanged(this);
00572 }
00573 
00574 int UPlotCurve::removeItem(int index)
00575 {
00576         if(index >= 0 && index < _items.size())
00577         {
00578                 if(index!=0)
00579                 {
00580                         index-=1;
00581                         delete _items.takeAt(index); // the line
00582                 }
00583                 else if(_items.size()>1)
00584                 {
00585                         delete _items.takeAt(index+1); // the line
00586                 }
00587                 UPlotItem * item = (UPlotItem *)_items.takeAt(index); // the plot item
00588                 //Update min/max
00589                 if(_minMax.size() == 4)
00590                 {
00591                         if(item->data().x() == _minMax[0] || item->data().x() == _minMax[1] ||
00592                            item->data().y() == _minMax[2] || item->data().y() == _minMax[3])
00593                         {
00594                                 if(_items.size())
00595                                 {
00596                                         UPlotItem * tmp = (UPlotItem *)_items.at(0);
00597                                         float x = tmp->data().x();
00598                                         float y = tmp->data().y();
00599                                         _minMax[0]=x;
00600                                         _minMax[1]=x;
00601                                         _minMax[2]=y;
00602                                         _minMax[3]=y;
00603                                         for(int i = 2; i<_items.size(); i+=2)
00604                                         {
00605                                                 tmp = (UPlotItem*)_items.at(i);
00606                                                 x = tmp->data().x();
00607                                                 y = tmp->data().y();
00608                                                 if(x<_minMax[0]) _minMax[0] = x;
00609                                                 if(x>_minMax[1]) _minMax[1] = x;
00610                                                 if(y<_minMax[2]) _minMax[2] = y;
00611                                                 if(y>_minMax[3]) _minMax[3] = y;
00612                                         }
00613                                 }
00614                                 else
00615                                 {
00616                                         _minMax = QVector<float>();
00617                                 }
00618                         }
00619                 }
00620                 delete item;
00621         }
00622 
00623         return index;
00624 }
00625 
00626 void UPlotCurve::removeItem(UPlotItem * item) // ownership is transfered to the caller
00627 {
00628         for(int i=0; i<_items.size(); ++i)
00629         {
00630                 if(_items.at(i) == item)
00631                 {
00632                         if(i!=0)
00633                         {
00634                                 i-=1;
00635                                 delete _items[i];
00636                                 _items.removeAt(i);
00637                         }
00638                         else if(_items.size()>1)
00639                         {
00640                                 delete _items[i+1];
00641                                 _items.removeAt(i+1);
00642                         }
00643                         item->scene()->removeItem(item);
00644                         _items.removeAt(i);
00645                         break;
00646                 }
00647         }
00648 }
00649 
00650 void UPlotCurve::clear()
00651 {
00652 #if PRINT_DEBUG
00653         ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
00654 #endif
00655         qDeleteAll(_rootItem->childItems());
00656         _items.clear();
00657 }
00658 
00659 void UPlotCurve::setPen(const QPen & pen)
00660 {
00661         _pen = pen;
00662         for(int i=1; i<_items.size(); i+=2)
00663         {
00664                 ((QGraphicsLineItem*) _items.at(i))->setPen(_pen);
00665         }
00666 }
00667 
00668 void UPlotCurve::setBrush(const QBrush & brush)
00669 {
00670         _brush = brush;
00671         ULOGGER_WARN("Not used...");
00672 }
00673 
00674 void UPlotCurve::setItemsColor(const QColor & color)
00675 {
00676         if(color.isValid())
00677         {
00678                 _itemsColor.setRgb(color.red(), color.green(), color.blue(), _itemsColor.alpha());
00679                 for(int i=0; i<_items.size(); i+=2)
00680                 {
00681                         QPen pen = ((UPlotItem*) _items.at(i))->pen();
00682                         pen.setColor(_itemsColor);
00683                         ((UPlotItem*) _items.at(i))->setPen(pen);
00684                 }
00685         }
00686 }
00687 
00688 void UPlotCurve::update(float scaleX, float scaleY, float offsetX, float offsetY, float xDir, float yDir, int maxItemsKept)
00689 {
00690         //ULOGGER_DEBUG("scaleX=%f, scaleY=%f, offsetX=%f, offsetY=%f, xDir=%d, yDir=%d, _plot->scene()->width()=%f, _plot->scene()->height=%f", scaleX, scaleY, offsetX, offsetY, xDir, yDir,_plot->scene()->width(),_plot->scene()->height());
00691         //make sure direction values are 1 or -1
00692         xDir<0?xDir=-1:xDir=1;
00693         yDir<0?yDir=-1:yDir=1;
00694 
00695         bool hide = false;
00696         int j=0;
00697         for(int i=_items.size()-1; i>=0; --i)
00698         {
00699                 if(i%2 == 0)
00700                 {
00701                         UPlotItem * item = (UPlotItem *)_items.at(i);
00702                         if(hide)
00703                         {
00704                                 if(maxItemsKept == 0 || j <= maxItemsKept)
00705                                 {
00706                                         // if not visible, stop looping... all other items are normally already hidden
00707                                         if(!item->isVisible())
00708                                         {
00709                                                 break;
00710                                         }
00711                                         item->setVisible(false);
00712                                 }
00713                                 else
00714                                 {
00715                                         //remove the item with his line
00716                                         i = this->removeItem(i);
00717                                 }
00718                         }
00719                         else
00720                         {
00721                                 QPointF newPos(((xDir*item->data().x()+offsetX)*scaleX-item->rect().width()/2.0f),
00722                                                            ((yDir*item->data().y()+offsetY)*scaleY-item->rect().width()/2.0f));
00723                                 if(!item->isVisible())
00724                                 {
00725                                         item->setVisible(true);
00726                                 }
00727                                 item->setPos(newPos);
00728                         }
00729                         ++j;
00730                 }
00731                 else
00732                 {
00733                         if(hide)
00734                         {
00735                                 _items.at(i)->setVisible(false);
00736                         }
00737                         else
00738                         {
00739                                 UPlotItem * from = (UPlotItem *)_items.at(i-1);
00740                                 UPlotItem * to = (UPlotItem *)_items.at(i+1);
00741                                 QGraphicsLineItem * lineItem = (QGraphicsLineItem *)_items.at(i);
00742                                 lineItem->setLine((xDir*from->data().x()+offsetX)*scaleX,
00743                                                                 (yDir*from->data().y()+offsetY)*scaleY,
00744                                                                 (xDir*to->data().x()+offsetX)*scaleX,
00745                                                                 (yDir*to->data().y()+offsetY)*scaleY);
00746                                 if(!lineItem->isVisible())
00747                                 {
00748                                         lineItem->setVisible(true);
00749                                 }
00750                                 //Don't update not visible items
00751                                 // (Detect also if the curve goes forward or backward)
00752                                 QLineF line = lineItem->line();
00753                                 if((line.x1() <= line.x2() && line.x2() < 0-((line.x2() - line.x1()))) ||
00754                                         (line.x1() > line.x2() && line.x2() > lineItem->scene()->sceneRect().width() + ((line.x1() - line.x2()))))
00755                                 {
00756                                         hide = true;
00757                                 }
00758 
00759                         }
00760                 }
00761         }
00762 
00763 }
00764 
00765 void UPlotCurve::draw(QPainter * painter, const QRect & limits)
00766 {
00767         if(painter)
00768         {
00769                 for(int i=_items.size()-1; i>=0 && _items.at(i)->isVisible(); i-=2)
00770                 {
00771                         //plotItem
00772                         const UPlotItem * item = (const UPlotItem *)_items.at(i);
00773                         int x = (int)item->x();
00774                         if(x<0)
00775                         {
00776                                 break;
00777                         }
00778 
00779                         // draw line in first
00780                         if(i-1>=0)
00781                         {
00782                                 //lineItem
00783                                 const QGraphicsLineItem * lineItem = (const QGraphicsLineItem *)_items.at(i-1);
00784                                 QLine line = lineItem->line().toLine();
00785                                 if(limits.contains(line.p1()) || limits.contains(line.p2()))
00786                                 {
00787                                         QPointF intersection;
00788                                         QLineF::IntersectType type;
00789                                         type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.bottomLeft()), &intersection);
00790                                         if(type == QLineF::BoundedIntersection)
00791                                         {
00792                                                 !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00793                                         }
00794                                         else
00795                                         {
00796                                                 type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.topRight()), &intersection);
00797                                                 if(type == QLineF::BoundedIntersection)
00798                                                 {
00799                                                         !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00800                                                 }
00801                                                 else
00802                                                 {
00803                                                         type = lineItem->line().intersect(QLineF(limits.bottomLeft(), limits.bottomRight()), &intersection);
00804                                                         if(type == QLineF::BoundedIntersection)
00805                                                         {
00806                                                                 !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00807                                                         }
00808                                                         else
00809                                                         {
00810                                                                 type = lineItem->line().intersect(QLineF(limits.topRight(), limits.bottomRight()), &intersection);
00811                                                                 if(type == QLineF::BoundedIntersection)
00812                                                                 {
00813                                                                         !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00814                                                                 }
00815                                                         }
00816                                                 }
00817                                         }
00818                                         painter->save();
00819                                         painter->setPen(this->pen());
00820                                         painter->setBrush(this->brush());
00821                                         painter->drawLine(line);
00822                                         painter->restore();
00823                                 }
00824                         }
00825 
00826                         /*if(limits.contains(item->pos().toPoint()) && limits.contains((item->pos() + QPointF(item->rect().width(), item->rect().height())).toPoint()))
00827                         {
00828                                 painter->save();
00829                                 painter->setPen(QPen(_itemsColor));
00830                                 painter->drawEllipse(item->pos()+QPointF(item->rect().width()/2, item->rect().height()/2), (int)item->rect().width()/2, (int)item->rect().height()/2);
00831                                 painter->restore();
00832                         }*/
00833                 }
00834         }
00835 }
00836 
00837 int UPlotCurve::itemsSize() const
00838 {
00839         return _items.size();
00840 }
00841 
00842 QPointF UPlotCurve::getItemData(int index)
00843 {
00844         QPointF data;
00845         //make sure the index point to a PlotItem {PlotItem, line, PlotItem, line...}
00846         if(index>=0 && index < _items.size() && index % 2 == 0 )
00847         {
00848                 data = ((UPlotItem*)_items.at(index))->data();
00849         }
00850         else
00851         {
00852                 ULOGGER_ERROR("Wrong index, not pointing on a PlotItem");
00853         }
00854         return data;
00855 }
00856 
00857 void UPlotCurve::setVisible(bool visible)
00858 {
00859         _visible = visible;
00860         for(int i=0; i<_items.size(); ++i)
00861         {
00862                 _items.at(i)->setVisible(visible);
00863         }
00864 }
00865 
00866 void UPlotCurve::setXIncrement(float increment)
00867 {
00868         _xIncrement = increment;
00869 }
00870 
00871 void UPlotCurve::setXStart(float val)
00872 {
00873         _xStart = val;
00874 }
00875 
00876 void UPlotCurve::setData(QVector<UPlotItem*> & data)
00877 {
00878         this->clear();
00879         for(int i = 0; i<data.size(); ++i)
00880         {
00881                 this->addValue(data[i]);
00882         }
00883 }
00884 
00885 void UPlotCurve::setData(const QVector<float> & x, const QVector<float> & y)
00886 {
00887         if(x.size() == y.size())
00888         {
00889                 //match the size of the current data
00890                 int margin = int((_items.size()+1)/2) - x.size();
00891                 while(margin < 0)
00892                 {
00893                         UPlotItem * newItem = new UPlotItem(0, 0, 2);
00894                         this->_addValue(newItem);
00895                         ++margin;
00896                 }
00897                 while(margin > 0)
00898                 {
00899                         this->removeItem(0);
00900                         --margin;
00901                 }
00902 
00903                 // update values
00904                 int index = 0;
00905                 QVector<float>::const_iterator i=x.begin();
00906                 QVector<float>::const_iterator j=y.begin();
00907                 for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
00908                 {
00909                         ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
00910                 }
00911 
00912                 //reset minMax, this will force the plot to update the axes
00913                 this->updateMinMax();
00914                 Q_EMIT dataChanged(this);
00915         }
00916         else if(y.size()>0 && x.size()==0)
00917         {
00918                 this->setData(y);
00919         }
00920         else
00921         {
00922                 ULOGGER_ERROR("Data vectors have not the same size.");
00923         }
00924 }
00925 
00926 void UPlotCurve::setData(const std::vector<float> & x, const std::vector<float> & y)
00927 {
00928         if(x.size() == y.size())
00929         {
00930                 //match the size of the current data
00931                 int margin = int((_items.size()+1)/2) - int(x.size());
00932                 while(margin < 0)
00933                 {
00934                         UPlotItem * newItem = new UPlotItem(0, 0, 2);
00935                         this->_addValue(newItem);
00936                         ++margin;
00937                 }
00938                 while(margin > 0)
00939                 {
00940                         this->removeItem(0);
00941                         --margin;
00942                 }
00943 
00944                 // update values
00945                 int index = 0;
00946                 std::vector<float>::const_iterator i=x.begin();
00947                 std::vector<float>::const_iterator j=y.begin();
00948                 for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
00949                 {
00950                         ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
00951                 }
00952 
00953                 //reset minMax, this will force the plot to update the axes
00954                 this->updateMinMax();
00955                 Q_EMIT dataChanged(this);
00956         }
00957         else if(y.size()>0 && x.size()==0)
00958         {
00959                 this->setData(y);
00960         }
00961         else
00962         {
00963                 ULOGGER_ERROR("Data vectors have not the same size.");
00964         }
00965 }
00966 
00967 void UPlotCurve::setData(const QVector<float> & y)
00968 {
00969         this->setData(y.toStdVector());
00970 }
00971 
00972 void UPlotCurve::setData(const std::vector<float> & y)
00973 {
00974         //match the size of the current data
00975         int margin = int((_items.size()+1)/2) - int(y.size());
00976         while(margin < 0)
00977         {
00978                 UPlotItem * newItem = new UPlotItem(0, 0, 2);
00979                 this->_addValue(newItem);
00980                 ++margin;
00981         }
00982         while(margin > 0)
00983         {
00984                 this->removeItem(0);
00985                 --margin;
00986         }
00987 
00988         // update values
00989         int index = 0;
00990         float x = 0;
00991         std::vector<float>::const_iterator j=y.begin();
00992         for(; j!=y.end(); ++j, index+=2)
00993         {
00994                 ((UPlotItem*)_items[index])->setData(QPointF(x++, *j));
00995         }
00996 
00997         //reset minMax, this will force the plot to update the axes
00998         this->updateMinMax();
00999         Q_EMIT dataChanged(this);
01000 }
01001 
01002 void UPlotCurve::getData(QVector<float> & x, QVector<float> & y) const
01003 {
01004         x.clear();
01005         y.clear();
01006         if(_items.size())
01007         {
01008                 x.resize((_items.size()-1)/2+1);
01009                 y.resize(x.size());
01010                 int j=0;
01011                 for(int i=0; i<_items.size(); i+=2)
01012                 {
01013                         x[j] = ((UPlotItem*)_items.at(i))->data().x();
01014                         y[j++] = ((UPlotItem*)_items.at(i))->data().y();
01015                 }
01016         }
01017 }
01018 
01019 void UPlotCurve::getData(QMap<float,float> & data) const
01020 {
01021         data.clear();
01022         if(_items.size())
01023         {
01024                 for(int i=0; i<_items.size(); i+=2)
01025                 {
01026                         data.insert(((UPlotItem*)_items.at(i))->data().x(), ((UPlotItem*)_items.at(i))->data().y());
01027                 }
01028         }
01029 }
01030 
01031 
01032 
01033 
01034 
01035 UPlotCurveThreshold::UPlotCurveThreshold(const QString & name, float thesholdValue, Qt::Orientation orientation, QObject * parent) :
01036         UPlotCurve(name, parent),
01037         _orientation(orientation)
01038 {
01039         if(_orientation == Qt::Horizontal)
01040         {
01041                 this->addValue(0, thesholdValue);
01042                 this->addValue(1, thesholdValue);
01043         }
01044         else
01045         {
01046                 this->addValue(thesholdValue, 0);
01047                 this->addValue(thesholdValue, 1);
01048         }
01049 }
01050 
01051 UPlotCurveThreshold::~UPlotCurveThreshold()
01052 {
01053 
01054 }
01055 
01056 void UPlotCurveThreshold::setThreshold(float threshold)
01057 {
01058 #if PRINT_DEBUG
01059         ULOGGER_DEBUG("%f", threshold);
01060 #endif
01061         if(_items.size() == 3)
01062         {
01063                 UPlotItem * item = 0;
01064                 if(_orientation == Qt::Horizontal)
01065                 {
01066                         item = (UPlotItem*)_items.at(0);
01067                         item->setData(QPointF(item->data().x(), threshold));
01068                         item = (UPlotItem*)_items.at(2);
01069                         item->setData(QPointF(item->data().x(), threshold));
01070                 }
01071                 else
01072                 {
01073                         item = (UPlotItem*)_items.at(0);
01074                         item->setData(QPointF(threshold, item->data().y()));
01075                         item = (UPlotItem*)_items.at(2);
01076                         item->setData(QPointF(threshold, item->data().y()));
01077                 }
01078         }
01079         else
01080         {
01081                 ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
01082         }
01083 }
01084 
01085 void UPlotCurveThreshold::setOrientation(Qt::Orientation orientation)
01086 {
01087         if(_orientation != orientation)
01088         {
01089                 _orientation = orientation;
01090                 if(_items.size() == 3)
01091                 {
01092                         UPlotItem * item = 0;
01093                         item = (UPlotItem*)_items.at(0);
01094                         item->setData(QPointF(item->data().y(), item->data().x()));
01095                         item = (UPlotItem*)_items.at(2);
01096                         item->setData(QPointF(item->data().y(), item->data().x()));
01097                 }
01098                 else
01099                 {
01100                         ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
01101                 }
01102         }
01103 }
01104 
01105 void UPlotCurveThreshold::update(float scaleX, float scaleY, float offsetX, float offsetY, float xDir, float yDir, int maxItemsKept)
01106 {
01107         if(_items.size() == 3)
01108         {
01109                 if(_plot)
01110                 {
01111                         UPlotItem * item = 0;
01112                         if(_orientation == Qt::Horizontal)
01113                         {
01114                                 //(xDir*item->data().x()+offsetX)*scaleX
01115                                 item = (UPlotItem*)_items.at(0);
01116                                 item->setData(QPointF(-(offsetX-item->rect().width()/scaleX)/xDir, item->data().y()));
01117                                 item = (UPlotItem*)_items.at(2);
01118                                 item->setData(QPointF( (_plot->sceneRect().width()/scaleX-(offsetX+item->rect().width()/scaleX))/xDir, item->data().y()));
01119                         }
01120                         else
01121                         {
01122                                 item = (UPlotItem*)_items.at(0);
01123                                 item->setData(QPointF(item->data().x(), -(offsetY-item->rect().height()/scaleY)/yDir));
01124                                 item = (UPlotItem*)_items.at(2);
01125                                 item->setData(QPointF(item->data().x(), (_plot->sceneRect().height()/scaleY-(offsetY+item->rect().height()/scaleY))/yDir));
01126                         }
01127                         this->updateMinMax();
01128                 }
01129         }
01130         else
01131         {
01132                 ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
01133         }
01134         UPlotCurve::update(scaleX, scaleY, offsetX, offsetY, xDir, yDir, maxItemsKept);
01135 }
01136 
01137 
01138 
01139 
01140 
01141 
01142 
01143 UPlotAxis::UPlotAxis(Qt::Orientation orientation, float min, float max, QWidget * parent) :
01144         QWidget(parent),
01145         _orientation(orientation),
01146         _reversed(false),
01147         _gradMaxDigits(4),
01148         _border(0)
01149 {
01150         if(_orientation == Qt::Vertical)
01151         {
01152                 _reversed = true; // default bottom->up
01153         }
01154 #ifdef _WIN32
01155         this->setMinimumSize(15, 25);
01156 #else
01157         this->setMinimumSize(15, 25);
01158 #endif
01159         this->setAxis(min, max); // this initialize all attributes
01160 }
01161 
01162 UPlotAxis::~UPlotAxis()
01163 {
01164 #if PRINT_DEBUG
01165         ULOGGER_DEBUG("");
01166 #endif
01167 }
01168 
01169 // Vertical :bottom->up, horizontal :right->left
01170 void UPlotAxis::setReversed(bool reversed)
01171 {
01172         if(_reversed != reversed)
01173         {
01174                 float min = _min;
01175                 _min = _max;
01176                 _max = min;
01177         }
01178         _reversed = reversed;
01179 }
01180 
01181 void UPlotAxis::setAxis(float & min, float & max)
01182 {
01183         int borderMin = 0;
01184         int borderMax = 0;
01185         if(_orientation == Qt::Vertical)
01186         {
01187                 borderMin = borderMax = this->fontMetrics().height()/2;
01188         }
01189         else
01190         {
01191                 borderMin = this->fontMetrics().width(QString::number(_min,'g',_gradMaxDigits))/2;
01192                 borderMax = this->fontMetrics().width(QString::number(_max,'g',_gradMaxDigits))/2;
01193         }
01194         int border = borderMin>borderMax?borderMin:borderMax;
01195         int borderDelta;
01196         int length;
01197         if(_orientation == Qt::Vertical)
01198         {
01199                 length = (this->height()-border*2);
01200         }
01201         else
01202         {
01203                 length = (this->width()-border*2);
01204         }
01205 
01206         if(length <= 70)
01207         {
01208                 _count = 5;
01209         }
01210         else if(length <= 175)
01211         {
01212                 _count = 10;
01213         }
01214         else if(length <= 350)
01215         {
01216                 _count = 20;
01217         }
01218         else if(length <= 700)
01219         {
01220                 _count = 40;
01221         }
01222         else if(length <= 1000)
01223         {
01224                 _count = 60;
01225         }
01226         else if(length <= 1300)
01227         {
01228                 _count = 80;
01229         }
01230         else
01231         {
01232                 _count = 100;
01233         }
01234 
01235         // Rounding min and max
01236         if(min != max)
01237         {
01238                 float mul = 1;
01239                 float rangef = max - min;
01240                 int countStep = _count/5;
01241                 float val;
01242                 for(int i=0; i<6; ++i)
01243                 {
01244                         val = (rangef/float(countStep)) * mul;
01245                         if( val >= 1.0f && val < 10.0f)
01246                         {
01247                                 break;
01248                         }
01249                         else if(val<1)
01250                         {
01251                                 mul *= 10.0f;
01252                         }
01253                         else
01254                         {
01255                                 mul /= 10.0f;
01256                         }
01257                 }
01258                 //ULOGGER_DEBUG("min=%f, max=%f", min, max);
01259                 int minR = min*mul-0.9;
01260                 int maxR = max*mul+0.9;
01261                 min = float(minR)/mul;
01262                 max = float(maxR)/mul;
01263                 //ULOGGER_DEBUG("mul=%f, minR=%d, maxR=%d,countStep=%d", mul, minR, maxR, countStep);
01264         }
01265 
01266         _min = min;
01267         _max = max;
01268 
01269         if(_reversed)
01270         {
01271                 _min = _max;
01272                 _max = min;
01273         }
01274 
01275         if(_orientation == Qt::Vertical)
01276         {
01277                 _step = length/_count;
01278                 borderDelta = length - (_step*_count);
01279         }
01280         else
01281         {
01282                 _step = length/_count;
01283                 borderDelta = length - (_step*_count);
01284         }
01285 
01286         if(borderDelta%2 != 0)
01287         {
01288                 borderDelta+=1;
01289         }
01290 
01291         _border = border + borderDelta/2;
01292 
01293         //Resize estimation
01294         if(_orientation == Qt::Vertical)
01295         {
01296                 int minWidth = 0;
01297                 for (int i = 0; i <= _count; i+=5)
01298                 {
01299                         QString n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
01300                         if(this->fontMetrics().width(n) > minWidth)
01301                         {
01302                                 minWidth = this->fontMetrics().width(n);
01303                         }
01304                 }
01305                 this->setMinimumWidth(15+minWidth);
01306         }
01307 }
01308 
01309 void UPlotAxis::paintEvent(QPaintEvent * event)
01310 {
01311         QPainter painter(this);
01312         if(_orientation == Qt::Vertical)
01313         {
01314                 painter.translate(0, _border);
01315                 for (int i = 0; i <= _count; ++i)
01316                 {
01317                         if(i%5 == 0)
01318                         {
01319                                 painter.drawLine(this->width(), 0, this->width()-10, 0);
01320                                 QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
01321                                 painter.drawText(this->width()-(12+n.sizeHint().width()), n.sizeHint().height()/2-2, n.text());
01322                         }
01323                         else
01324                         {
01325                                 painter.drawLine(this->width(), 0, this->width()-5, 0);
01326                         }
01327                         painter.translate(0, _step);
01328                 }
01329         }
01330         else
01331         {
01332                 painter.translate(_border, 0);
01333                 for (int i = 0; i <= _count; ++i)
01334                 {
01335                         if(i%5 == 0)
01336                         {
01337                                 painter.drawLine(0, 0, 0, 10);
01338                                 QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
01339                                 painter.drawText(-(n.sizeHint().width()/2)+1, 22, n.text());
01340                         }
01341                         else
01342                         {
01343                                 painter.drawLine(0, 0, 0, 5);
01344                         }
01345                         painter.translate(_step, 0);
01346                 }
01347         }
01348 }
01349 
01350 
01351 
01352 
01353 UPlotLegendItem::UPlotLegendItem(UPlotCurve * curve, QWidget * parent) :
01354                 QPushButton(parent),
01355                 _curve(curve)
01356 {
01357         QString nameSpaced = curve->name();
01358         nameSpaced.replace('_', ' ');
01359         this->setText(nameSpaced);
01360 
01361         this->setIcon(QIcon(this->createSymbol(curve->pen(), curve->brush())));
01362         this->setIconSize(QSize(25,20));
01363 
01364         _aChangeText = new QAction(tr("Change text..."), this);
01365         _aResetText = new QAction(tr("Reset text..."), this);
01366         _aChangeColor = new QAction(tr("Change color..."), this);
01367         _aCopyToClipboard = new QAction(tr("Copy curve data to clipboard"), this);
01368         _aShowStdDev = new QAction(tr("Show std deviation"), this);
01369         _aShowStdDev->setCheckable(true);
01370         _aMoveUp = new QAction(tr("Move up"), this);
01371         _aMoveDown = new QAction(tr("Move down"), this);
01372         _aRemoveCurve = new QAction(tr("Remove this curve"), this);
01373         _menu = new QMenu(tr("Curve"), this);
01374         _menu->addAction(_aChangeText);
01375         _menu->addAction(_aResetText);
01376         _menu->addAction(_aChangeColor);
01377         _menu->addAction(_aCopyToClipboard);
01378         _menu->addAction(_aShowStdDev);
01379         _menu->addSeparator();
01380         _menu->addAction(_aMoveUp);
01381         _menu->addAction(_aMoveDown);
01382         _menu->addSeparator();
01383         _menu->addAction(_aRemoveCurve);
01384 }
01385 
01386 UPlotLegendItem::~UPlotLegendItem()
01387 {
01388 
01389 }
01390 void UPlotLegendItem::contextMenuEvent(QContextMenuEvent * event)
01391 {
01392         QAction * action = _menu->exec(event->globalPos());
01393         if(action == _aChangeText)
01394         {
01395                 bool ok;
01396                 QString text = QInputDialog::getText(this, _aChangeText->text(), tr("Name :"), QLineEdit::Normal, this->text(), &ok);
01397                 if(ok && !text.isEmpty())
01398                 {
01399                         this->setText(text);
01400                 }
01401         }
01402         else if(action == _aResetText)
01403         {
01404                 if(_curve)
01405                 {
01406                         this->setText(_curve->name());
01407                 }
01408         }
01409         else if(action == _aChangeColor)
01410         {
01411                 if(_curve)
01412                 {
01413                         QPen pen = _curve->pen();
01414                         QColor color = QColorDialog::getColor(pen.color(), this);
01415                         if(color.isValid())
01416                         {
01417                                 pen.setColor(color);
01418                                 _curve->setPen(pen);
01419                                 this->setIcon(QIcon(this->createSymbol(_curve->pen(), _curve->brush())));
01420                         }
01421                 }
01422         }
01423         else if (action == _aCopyToClipboard)
01424         {
01425                 if(_curve)
01426                 {
01427                         QVector<float> x;
01428                         QVector<float> y;
01429                         _curve->getData(x, y);
01430                         QString textX;
01431                         QString textY;
01432                         for(int i=0; i<x.size(); ++i)
01433                         {
01434                                 textX.append(QString::number(x[i]));
01435                                 textY.append(QString::number(y[i]));
01436                                 if(i+1<x.size())
01437                                 {
01438                                         textX.append(' ');
01439                                         textY.append(' ');
01440                                 }
01441                         }
01442                         QClipboard * clipboard = QApplication::clipboard();
01443                         clipboard->setText((textX+"\n")+textY);
01444                 }
01445         }
01446         else if(action == _aShowStdDev)
01447         {
01448                 if(_aShowStdDev->isChecked())
01449                 {
01450                         connect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDev()));
01451                 }
01452                 else
01453                 {
01454                         disconnect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDev()));
01455                         QString nameSpaced = _curve->name();
01456                         nameSpaced.replace('_', ' ');
01457                         this->setText(nameSpaced);
01458                 }
01459         }
01460         else if(action == _aRemoveCurve)
01461         {
01462                 Q_EMIT legendItemRemoved(_curve);
01463         }
01464         else if(action == _aMoveUp)
01465         {
01466                 Q_EMIT moveUpRequest(this);
01467         }
01468         else if(action == _aMoveDown)
01469         {
01470                 Q_EMIT moveDownRequest(this);
01471         }
01472 }
01473 
01474 QPixmap UPlotLegendItem::createSymbol(const QPen & pen, const QBrush & brush)
01475 {
01476         QPixmap pixmap(50, 50);
01477         pixmap.fill(Qt::transparent);
01478         QPainter painter(&pixmap);
01479         QPen p = pen;
01480         p.setWidthF(4.0);
01481         painter.setPen(p);
01482         painter.drawLine(0.0, 25.0, 50.0, 25.0);
01483         return pixmap;
01484 }
01485 
01486 void UPlotLegendItem::updateStdDev()
01487 {
01488         QVector<float> x, y;
01489         _curve->getData(x, y);
01490         float stdDev = std::sqrt(uVariance(y.data(), y.size()));
01491         QString nameSpaced = _curve->name();
01492         nameSpaced.replace('_', ' ');
01493         nameSpaced += QString(" (%1=%2)").arg(QChar(0xc3, 0x03)).arg(stdDev);
01494         this->setText(nameSpaced);
01495 }
01496 
01497 
01498 
01499 
01500 
01501 
01502 UPlotLegend::UPlotLegend(QWidget * parent) :
01503         QWidget(parent),
01504         _flat(true)
01505 {
01506         //menu
01507         _aUseFlatButtons = new QAction(tr("Use flat buttons"), this);
01508         _aUseFlatButtons->setCheckable(true);
01509         _aUseFlatButtons->setChecked(_flat);
01510         _aCopyAllCurveToClipboard = new QAction(tr("Copy all curve data to clipboard"), this);
01511         _menu = new QMenu(tr("Legend"), this);
01512         _menu->addAction(_aUseFlatButtons);
01513         _menu->addAction(_aCopyAllCurveToClipboard);
01514 
01515         QVBoxLayout * vLayout = new QVBoxLayout(this);
01516         vLayout->setContentsMargins(0,0,0,0);
01517         this->setLayout(vLayout);
01518         vLayout->addStretch(0);
01519         vLayout->setSpacing(0);
01520 }
01521 
01522 UPlotLegend::~UPlotLegend()
01523 {
01524 #if PRINT_DEBUG
01525         ULOGGER_DEBUG("");
01526 #endif
01527 }
01528 
01529 void UPlotLegend::setFlat(bool on)
01530 {
01531         if(_flat != on)
01532         {
01533                 _flat = on;
01534                 QList<UPlotLegendItem*> items = this->findChildren<UPlotLegendItem*>();
01535                 for(int i=0; i<items.size(); ++i)
01536                 {
01537                         items.at(i)->setFlat(_flat);
01538                         items.at(i)->setChecked(!items.at(i)->isChecked());
01539                 }
01540                 _aUseFlatButtons->setChecked(_flat);
01541         }
01542 }
01543 
01544 void UPlotLegend::addItem(UPlotCurve * curve)
01545 {
01546         if(curve)
01547         {
01548                 UPlotLegendItem * legendItem = new UPlotLegendItem(curve, this);
01549                 legendItem->setAutoDefault(false);
01550                 legendItem->setFlat(_flat);
01551                 legendItem->setCheckable(true);
01552                 legendItem->setChecked(false);
01553                 connect(legendItem, SIGNAL(toggled(bool)), this, SLOT(redirectToggled(bool)));
01554                 connect(legendItem, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeLegendItem(const UPlotCurve *)));
01555                 connect(legendItem, SIGNAL(moveUpRequest(UPlotLegendItem *)), this, SLOT(moveUp(UPlotLegendItem *)));
01556                 connect(legendItem, SIGNAL(moveDownRequest(UPlotLegendItem *)), this, SLOT(moveDown(UPlotLegendItem *)));
01557 
01558                 // layout
01559                 QHBoxLayout * hLayout = new QHBoxLayout();
01560                 hLayout->addWidget(legendItem);
01561                 hLayout->addStretch(0);
01562                 hLayout->setMargin(0);
01563 
01564                 // add to the legend
01565                 ((QVBoxLayout*)this->layout())->insertLayout(this->layout()->count()-1, hLayout);
01566         }
01567 }
01568 
01569 bool UPlotLegend::remove(const UPlotCurve * curve)
01570 {
01571         QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
01572         for(int i=0; i<items.size(); ++i)
01573         {
01574                 if(items.at(i)->curve() == curve)
01575                 {
01576                         delete items.at(i);
01577                         return true;
01578                 }
01579         }
01580         return false;
01581 }
01582 
01583 void UPlotLegend::removeLegendItem(const UPlotCurve * curve)
01584 {
01585         if(this->remove(curve))
01586         {
01587                 Q_EMIT legendItemRemoved(curve);
01588         }
01589 }
01590 
01591 void UPlotLegend::moveUp(UPlotLegendItem * item)
01592 {
01593         int index = -1;
01594         QLayoutItem * layoutItem = 0;
01595         for(int i=0; i<this->layout()->count(); ++i)
01596         {
01597                 if(this->layout()->itemAt(i)->layout() &&
01598                    this->layout()->itemAt(i)->layout()->indexOf(item) != -1)
01599                 {
01600                         layoutItem = this->layout()->itemAt(i);
01601                         index = i;
01602                         break;
01603                 }
01604         }
01605         if(index > 0 && layoutItem)
01606         {
01607                 this->layout()->removeItem(layoutItem);
01608                 QHBoxLayout * hLayout = new QHBoxLayout();
01609                 hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
01610                 hLayout->addStretch(0);
01611                 hLayout->setMargin(0);
01612                 ((QVBoxLayout*)this->layout())->insertLayout(index-1, hLayout);
01613                 delete layoutItem;
01614                 Q_EMIT legendItemMoved(item->curve(), index-1);
01615         }
01616 }
01617 
01618 void UPlotLegend::moveDown(UPlotLegendItem * item)
01619 {
01620         int index = -1;
01621         QLayoutItem * layoutItem = 0;
01622         for(int i=0; i<this->layout()->count(); ++i)
01623         {
01624                 if(this->layout()->itemAt(i)->layout() &&
01625                    this->layout()->itemAt(i)->layout()->indexOf(item) != -1)
01626                 {
01627                         layoutItem = this->layout()->itemAt(i);
01628                         index = i;
01629                         break;
01630                 }
01631         }
01632         if(index < this->layout()->count()-2 && layoutItem)
01633         {
01634                 this->layout()->removeItem(layoutItem);
01635                 QHBoxLayout * hLayout = new QHBoxLayout();
01636                 hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
01637                 hLayout->addStretch(0);
01638                 hLayout->setMargin(0);
01639                 ((QVBoxLayout*)this->layout())->insertLayout(index+1, hLayout);
01640                 delete layoutItem;
01641                 Q_EMIT legendItemMoved(item->curve(), index+1);
01642         }
01643 }
01644 
01645 void UPlotLegend::contextMenuEvent(QContextMenuEvent * event)
01646 {
01647         QAction * action = _menu->exec(event->globalPos());
01648         if(action == _aUseFlatButtons)
01649         {
01650                 this->setFlat(_aUseFlatButtons->isChecked());
01651         }
01652         else if(action == _aCopyAllCurveToClipboard)
01653         {
01654                 QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
01655                 if(items.size())
01656                 {
01657                         QMap<float,float> firstData;
01658                         QVector<QVector<float> > axes;
01659                         for(int i=0; i<items.size(); ++i)
01660                         {
01661                                 QMap<float, float> data;
01662                                 items.at(i)->curve()->getData(data);
01663 
01664                                 if(i==0)
01665                                 {
01666                                         firstData = data;
01667                                 }
01668                                 else
01669                                 {
01670                                         QVector<float> y(firstData.size(), 0.0f);
01671                                         // ust to make usre that we have the same number of data on each curve, set 0 for unknowns
01672                                         int j=0;
01673                                         for(QMap<float,float>::iterator iter=firstData.begin(); iter!=firstData.end(); ++iter)
01674                                         {
01675                                                 if(data.contains(iter.key()))
01676                                                 {
01677                                                         y[j] = data.value(iter.key());
01678                                                 }
01679                                                 ++j;
01680                                         }
01681                                         axes.push_back(y);
01682                                 }
01683                         }
01684                         if(firstData.size())
01685                         {
01686                                 axes.push_front(firstData.values().toVector());
01687                                 axes.push_front(firstData.keys().toVector());
01688                                 QString text;
01689                                 for(int i=0; i<axes.size(); ++i)
01690                                 {
01691                                         for(int j=0; j<axes[i].size(); ++j)
01692                                         {
01693                                                 text.append(QString::number(axes[i][j]));
01694                                                 if(j+1<axes[i].size())
01695                                                 {
01696                                                         text.append(' ');
01697                                                 }
01698                                         }
01699                                         if(i+1<axes.size())
01700                                         {
01701                                                 text.append("\n");
01702                                         }
01703                                 }
01704                                 QClipboard * clipboard = QApplication::clipboard();
01705                                 clipboard->setText(text);
01706                         }
01707                 }
01708         }
01709 }
01710 
01711 void UPlotLegend::redirectToggled(bool toggled)
01712 {
01713         if(sender())
01714         {
01715                 UPlotLegendItem * item = qobject_cast<UPlotLegendItem*>(sender());
01716                 if(item)
01717                 {
01718                         Q_EMIT legendItemToggled(item->curve(), _flat?!toggled:toggled);
01719                 }
01720         }
01721 }
01722 
01723 
01724 
01725 
01726 
01727 
01728 
01729 UOrientableLabel::UOrientableLabel(const QString & text, Qt::Orientation orientation, QWidget * parent) :
01730         QLabel(text, parent),
01731         _orientation(orientation)
01732 {
01733 }
01734 
01735 UOrientableLabel::~UOrientableLabel()
01736 {
01737 }
01738 
01739 QSize UOrientableLabel::sizeHint() const
01740 {
01741         QSize size = QLabel::sizeHint();
01742         if (_orientation == Qt::Vertical)
01743                 size.transpose();
01744         return size;
01745 
01746 }
01747 
01748 QSize UOrientableLabel::minimumSizeHint() const
01749 {
01750         QSize size = QLabel::minimumSizeHint();
01751         if (_orientation == Qt::Vertical)
01752                 size.transpose();
01753         return size;
01754 }
01755 
01756 void UOrientableLabel::setOrientation(Qt::Orientation orientation)
01757 {
01758         _orientation = orientation;
01759         switch(orientation)
01760         {
01761         case Qt::Horizontal:
01762                 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
01763                 break;
01764 
01765         case Qt::Vertical:
01766                 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
01767                 break;
01768         }
01769 }
01770 
01771 void UOrientableLabel::paintEvent(QPaintEvent* event)
01772 {
01773         QPainter p(this);
01774         QRect r = rect();
01775         switch (_orientation)
01776         {
01777         case Qt::Horizontal:
01778                 break;
01779         case Qt::Vertical:
01780                 p.rotate(-90);
01781                 p.translate(-height(), 0);
01782                 QSize size = r.size();
01783                 size.transpose();
01784                 r.setSize(size);
01785                 break;
01786         }
01787         p.drawText(r, this->alignment() | (this->wordWrap()?Qt::TextWordWrap:0), this->text());
01788 }
01789 
01790 
01791 
01792 
01793 
01794 
01795 
01796 
01797 
01798 
01799 
01800 
01801 
01802 UPlot::UPlot(QWidget *parent) :
01803         QWidget(parent),
01804         _maxVisibleItems(-1),
01805         _autoScreenCaptureFormat("png"),
01806         _bgColor(Qt::white)
01807 {
01808         this->setupUi();
01809         this->createActions();
01810         this->createMenus();
01811 
01812         // This will update actions
01813         this->showLegend(true);
01814         this->setGraphicsView(false);
01815         this->setMaxVisibleItems(0);
01816         this->showGrid(false);
01817         this->showRefreshRate(false);
01818         this->keepAllData(false);
01819 
01820         for(int i=0; i<4; ++i)
01821         {
01822                 _axisMaximums[i] = 0;
01823                 _axisMaximumsSet[i] = false;
01824                 if(i<2)
01825                 {
01826                         _fixedAxis[i] = false;
01827                 }
01828         }
01829 
01830         _mouseCurrentPos = _mousePressedPos; // for zooming
01831 
01832         _refreshIntervalTime.start();
01833         _lowestRefreshRate = 99;
01834         _refreshStartTime.start();
01835 
01836         _penStyleCount = 0;
01837         _workingDirectory = QDir::homePath();
01838 }
01839 
01840 UPlot::~UPlot()
01841 {
01842         _aAutoScreenCapture->setChecked(false);
01843 #if PRINT_DEBUG
01844         ULOGGER_DEBUG("%s", this->title().toStdString().c_str());
01845 #endif
01846         this->removeCurves();
01847 }
01848 
01849 void UPlot::setupUi()
01850 {
01851         _legend = new UPlotLegend(this);
01852         _view = new QGraphicsView(this);
01853         _view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01854         _view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01855         _view->setScene(new QGraphicsScene(0,0,0,0,this));
01856         _view->setStyleSheet( "QGraphicsView { border-style: none; }" );
01857         _sceneRoot = _view->scene()->addText("");
01858         _sceneRoot->setTransform(QTransform::fromTranslate(0, 0), true);
01859         _graphicsViewHolder = new QWidget(this);
01860         _graphicsViewHolder->setMinimumSize(100,100);
01861         _graphicsViewHolder->setMouseTracking(true);
01862         _verticalAxis = new UPlotAxis(Qt::Vertical, 0, 1, this);
01863         _horizontalAxis = new UPlotAxis(Qt::Horizontal, 0, 1, this);
01864         _title = new QLabel("");
01865         _xLabel = new QLabel("");
01866         _refreshRate = new QLabel("");
01867         _yLabel = new UOrientableLabel("");
01868         _yLabel->setOrientation(Qt::Vertical);
01869         _title->setAlignment(Qt::AlignCenter);
01870         _xLabel->setAlignment(Qt::AlignCenter);
01871         _yLabel->setAlignment(Qt::AlignCenter);
01872         _refreshRate->setAlignment(Qt::AlignCenter);
01873         _title->setWordWrap(true);
01874         _xLabel->setWordWrap(true);
01875         _yLabel->setWordWrap(true);
01876         _title->setVisible(false);
01877         _xLabel->setVisible(false);
01878         _yLabel->setVisible(false);
01879         _refreshRate->setVisible(false);
01880 
01881         //layouts
01882         QVBoxLayout * vLayout = new QVBoxLayout(_graphicsViewHolder);
01883         vLayout->setContentsMargins(0,0,0,0);
01884         vLayout->addWidget(_view);
01885 
01886         QGridLayout * grid = new QGridLayout(this);
01887         grid->setContentsMargins(0,0,0,0);
01888         grid->addWidget(_title, 0, 2);
01889         grid->addWidget(_yLabel, 1, 0);
01890         grid->addWidget(_verticalAxis, 1, 1);
01891         grid->addWidget(_refreshRate, 2, 1);
01892         grid->addWidget(_graphicsViewHolder, 1, 2);
01893         grid->setColumnStretch(2, 1);
01894         grid->setRowStretch(1, 1);
01895         grid->addWidget(_horizontalAxis, 2, 2);
01896         grid->addWidget(_xLabel, 3, 2);
01897         grid->addWidget(_legend, 1, 3);
01898 
01899         connect(_legend, SIGNAL(legendItemToggled(const UPlotCurve *, bool)), this, SLOT(showCurve(const UPlotCurve *, bool)));
01900         connect(_legend, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeCurve(const UPlotCurve *)));
01901         connect(_legend, SIGNAL(legendItemMoved(const UPlotCurve *, int)), this, SLOT(moveCurve(const UPlotCurve *, int)));
01902 }
01903 
01904 void UPlot::createActions()
01905 {
01906         _aShowLegend = new QAction(tr("Show legend"), this);
01907         _aShowLegend->setCheckable(true);
01908         _aShowGrid = new QAction(tr("Show grid"), this);
01909         _aShowGrid->setCheckable(true);
01910         _aShowRefreshRate = new QAction(tr("Show refresh rate"), this);
01911         _aShowRefreshRate->setCheckable(true);
01912         _aMouseTracking = new QAction(tr("Mouse tracking"), this);
01913         _aMouseTracking->setCheckable(true);
01914         _aGraphicsView = new QAction(tr("Graphics view"), this);
01915         _aGraphicsView->setCheckable(true);
01916         _aKeepAllData = new QAction(tr("Keep all data"), this);
01917         _aKeepAllData->setCheckable(true);
01918         _aLimit0 = new QAction(tr("No maximum items shown"), this);
01919         _aLimit10 = new QAction(tr("10"), this);
01920         _aLimit50 = new QAction(tr("50"), this);
01921         _aLimit100 = new QAction(tr("100"), this);
01922         _aLimit500 = new QAction(tr("500"), this);
01923         _aLimit1000 = new QAction(tr("1000"), this);
01924         _aLimitCustom = new QAction(tr(""), this);
01925         _aLimit0->setCheckable(true);
01926         _aLimit10->setCheckable(true);
01927         _aLimit50->setCheckable(true);
01928         _aLimit100->setCheckable(true);
01929         _aLimit500->setCheckable(true);
01930         _aLimit1000->setCheckable(true);
01931         _aLimitCustom->setCheckable(true);
01932         _aLimitCustom->setVisible(false);
01933         _aAddVerticalLine = new QAction(tr("Vertical line..."), this);
01934         _aAddHorizontalLine = new QAction(tr("Horizontal line..."), this);
01935         _aChangeTitle = new QAction(tr("Change title"), this);
01936         _aChangeXLabel = new QAction(tr("Change X label..."), this);
01937         _aChangeYLabel = new QAction(tr("Change Y label..."), this);
01938         _aChangeBackgroundColor = new QAction(tr("Change bg color..."), this);
01939         _aYLabelVertical = new QAction(tr("Vertical orientation"), this);
01940         _aYLabelVertical->setCheckable(true);
01941         _aYLabelVertical->setChecked(true);
01942         _aSaveFigure = new QAction(tr("Save figure..."), this);
01943         _aAutoScreenCapture = new QAction(tr("Auto screen capture..."), this);
01944         _aAutoScreenCapture->setCheckable(true);
01945         _aClearData = new QAction(tr("Clear data"), this);
01946 
01947         QActionGroup * grpLimit = new QActionGroup(this);
01948         grpLimit->addAction(_aLimit0);
01949         grpLimit->addAction(_aLimit10);
01950         grpLimit->addAction(_aLimit50);
01951         grpLimit->addAction(_aLimit100);
01952         grpLimit->addAction(_aLimit500);
01953         grpLimit->addAction(_aLimit1000);
01954         grpLimit->addAction(_aLimitCustom);
01955         _aLimit0->setChecked(true);
01956 }
01957 
01958 void UPlot::createMenus()
01959 {
01960         _menu = new QMenu(tr("Plot"), this);
01961         _menu->addAction(_aShowLegend);
01962         _menu->addAction(_aShowGrid);
01963         _menu->addAction(_aShowRefreshRate);
01964         _menu->addAction(_aMouseTracking);
01965         _menu->addAction(_aGraphicsView);
01966         _menu->addAction(_aKeepAllData);
01967         _menu->addSeparator()->setStatusTip(tr("Maximum items shown"));
01968         _menu->addAction(_aLimit0);
01969         _menu->addAction(_aLimit10);
01970         _menu->addAction(_aLimit50);
01971         _menu->addAction(_aLimit100);
01972         _menu->addAction(_aLimit500);
01973         _menu->addAction(_aLimit1000);
01974         _menu->addAction(_aLimitCustom);
01975         _menu->addSeparator();
01976         QMenu * addLineMenu = _menu->addMenu(tr("Add line"));
01977         addLineMenu->addAction(_aAddHorizontalLine);
01978         addLineMenu->addAction(_aAddVerticalLine);
01979         _menu->addSeparator();
01980         _menu->addAction(_aChangeTitle);
01981         _menu->addAction(_aChangeXLabel);
01982         QMenu * yLabelMenu = _menu->addMenu(tr("Y label"));
01983         yLabelMenu->addAction(_aChangeYLabel);
01984         yLabelMenu->addAction(_aYLabelVertical);
01985         _menu->addAction(_aChangeBackgroundColor);
01986         _menu->addAction(_aSaveFigure);
01987         _menu->addAction(_aAutoScreenCapture);
01988         _menu->addSeparator();
01989         _menu->addAction(_aClearData);
01990 
01991 }
01992 
01993 UPlotCurve * UPlot::addCurve(const QString & curveName, const QColor & color)
01994 {
01995         // add curve
01996         UPlotCurve * curve = new UPlotCurve(curveName, this);
01997         if(color.isValid())
01998         {
01999                 curve->setPen(color);
02000         }
02001         else
02002         {
02003                 curve->setPen(this->getRandomPenColored());
02004         }
02005         this->addCurve(curve);
02006         return curve;
02007 }
02008 
02009 bool UPlot::addCurve(UPlotCurve * curve, bool ownershipTransferred)
02010 {
02011         if(curve)
02012         {
02013 #if PRINT_DEBUG
02014                 ULOGGER_DEBUG("Adding curve \"%s\" to plot \"%s\"...", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
02015 #endif
02016                 // only last curve can trigger an update, so disable previous connections
02017                 if(!qobject_cast<UPlotCurveThreshold*>(curve))
02018                 {
02019                         for(int i=_curves.size()-1; i>=0; --i)
02020                         {
02021                                 if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
02022                                 {
02023                                         disconnect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
02024                                         break;
02025                                 }
02026                         }
02027                 }
02028 
02029                 // add curve
02030                 _curves.append(curve);
02031                 curve->attach(this);
02032                 curve->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.red(), _bgColor.alpha()));
02033                 if(ownershipTransferred)
02034                 {
02035                         curve->setParent(this);
02036                 }
02037                 this->updateAxis(curve);
02038                 curve->setXStart(_axisMaximums[1]);
02039 
02040                 connect(curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
02041 
02042                 _legend->addItem(curve);
02043 
02044 #if PRINT_DEBUG
02045                 ULOGGER_DEBUG("Curve \"%s\" added to plot \"%s\"", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
02046 #endif
02047 
02048                 return true;
02049         }
02050         else
02051         {
02052                 ULOGGER_ERROR("The curve is null!");
02053         }
02054         return false;
02055 }
02056 
02057 QStringList UPlot::curveNames()
02058 {
02059         QStringList names;
02060         for(QList<UPlotCurve*>::iterator iter = _curves.begin(); iter!=_curves.end(); ++iter)
02061         {
02062                 if(*iter)
02063                 {
02064                         names.append((*iter)->name());
02065                 }
02066         }
02067         return names;
02068 }
02069 
02070 bool UPlot::contains(const QString & curveName)
02071 {
02072         for(QList<UPlotCurve*>::iterator iter = _curves.begin(); iter!=_curves.end(); ++iter)
02073         {
02074                 if(*iter && (*iter)->name().compare(curveName) == 0)
02075                 {
02076                         return true;
02077                 }
02078         }
02079         return false;
02080 }
02081 
02082 QPen UPlot::getRandomPenColored()
02083 {
02084         int penStyle = 0;
02085         bool colorNotUsed = false;
02086         for(int i=0; i<12; ++i)
02087         {
02088                 QColor tmp((Qt::GlobalColor)((penStyle+i) % 12 + 7 ));
02089                 bool colorAlreadyUsed = false;
02090                 for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd() && !colorAlreadyUsed; ++iter)
02091                 {
02092                         colorAlreadyUsed = (*iter)->pen().color() == tmp;
02093                 }
02094                 if(!colorAlreadyUsed)
02095                 {
02096                         colorNotUsed = true;
02097                         penStyle+=i;
02098                         break;
02099                 }
02100         }
02101         if(colorNotUsed)
02102         {
02103                 _penStyleCount = penStyle;
02104         }
02105 
02106         return QPen((Qt::GlobalColor)(_penStyleCount++ % 12 + 7 ));
02107 }
02108 
02109 void UPlot::replot(QPainter * painter)
02110 {
02111         if(_maxVisibleItems>0)
02112         {
02113                 UPlotCurve * c = 0;
02114                 int maxItem = 0;
02115                 // find the curve with the most items
02116                 for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
02117                 {
02118                         if((*i)->isVisible() && ((UPlotCurve *)(*i))->itemsSize() > maxItem)
02119                         {
02120                                 c = *i;
02121                                 maxItem = c->itemsSize();
02122                         }
02123                 }
02124                 if(c && (maxItem-1)/2+1 > _maxVisibleItems && _axisMaximums[0] < c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x())
02125                 {
02126                         _axisMaximums[0] = c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x();
02127                 }
02128         }
02129 
02130         float axis[4] = {0};
02131         for(int i=0; i<4; ++i)
02132         {
02133                 axis[i] = _axisMaximums[i];
02134         }
02135 
02136         _verticalAxis->setAxis(axis[2], axis[3]);
02137         _horizontalAxis->setAxis(axis[0], axis[1]);
02138         if(_aGraphicsView->isChecked() && !painter)
02139         {
02140                 _verticalAxis->update();
02141                 _horizontalAxis->update();
02142         }
02143 
02144         //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
02145 
02146         QRectF newRect(0,0, _graphicsViewHolder->size().width(), _graphicsViewHolder->size().height());
02147         _view->scene()->setSceneRect(newRect);
02148         float borderHor = (float)_horizontalAxis->border();
02149         float borderVer = (float)_verticalAxis->border();
02150 
02151         //grid
02152         qDeleteAll(hGridLines);
02153         hGridLines.clear();
02154         qDeleteAll(vGridLines);
02155         vGridLines.clear();
02156         if(_aShowGrid->isChecked())
02157         {
02158                 // TODO make a PlotGrid class ?
02159                 float w = newRect.width()-(borderHor*2);
02160                 float h = newRect.height()-(borderVer*2);
02161                 float stepH = w / float(_horizontalAxis->count());
02162                 float stepV = h / float(_verticalAxis->count());
02163                 QPen dashPen(Qt::DashLine);
02164                 dashPen.setColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), 100));
02165                 QPen pen(dashPen.color());
02166                 for(float i=0.0f; i*stepV <= h+stepV; i+=5.0f)
02167                 {
02168                         //horizontal lines
02169                         if(!_aGraphicsView->isChecked())
02170                         {
02171                                 if(painter)
02172                                 {
02173                                         painter->save();
02174                                         painter->setPen(pen);
02175                                         painter->drawLine(0, stepV*i+borderVer+0.5f, borderHor, stepV*i+borderVer+0.5f);
02176 
02177                                         painter->setPen(dashPen);
02178                                         painter->drawLine(borderHor, stepV*i+borderVer+0.5f, w+borderHor, stepV*i+borderVer+0.5f);
02179 
02180                                         painter->setPen(pen);
02181                                         painter->drawLine(w+borderHor, stepV*i+borderVer+0.5f, w+borderHor*2, stepV*i+borderVer+0.5f);
02182                                         painter->restore();
02183                                 }
02184                         }
02185                         else
02186                         {
02187                                 hGridLines.append(new QGraphicsLineItem(0, stepV*i+borderVer, borderHor, stepV*i+borderVer, _sceneRoot));
02188                                 hGridLines.last()->setPen(pen);
02189                                 hGridLines.append(new QGraphicsLineItem(borderHor, stepV*i+borderVer, w+borderHor, stepV*i+borderVer, _sceneRoot));
02190                                 hGridLines.last()->setPen(dashPen);
02191                                 hGridLines.append(new QGraphicsLineItem(w+borderHor, stepV*i+borderVer, w+borderHor*2, stepV*i+borderVer, _sceneRoot));
02192                                 hGridLines.last()->setPen(pen);
02193                         }
02194                 }
02195                 for(float i=0; i*stepH < w+stepH; i+=5.0f)
02196                 {
02197                         //vertical lines
02198                         if(!_aGraphicsView->isChecked())
02199                         {
02200                                 if(painter)
02201                                 {
02202                                         painter->save();
02203                                         painter->setPen(pen);
02204                                         painter->drawLine(stepH*i+borderHor+0.5f, 0, stepH*i+borderHor+0.5f, borderVer);
02205 
02206                                         painter->setPen(dashPen);
02207                                         painter->drawLine(stepH*i+borderHor+0.5f, borderVer, stepH*i+borderHor+0.5f, h+borderVer);
02208 
02209                                         painter->setPen(pen);
02210                                         painter->drawLine(stepH*i+borderHor+0.5f, h+borderVer, stepH*i+borderHor+0.5f, h+borderVer*2);
02211                                         painter->restore();
02212                                 }
02213                         }
02214                         else
02215                         {
02216                                 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, 0, stepH*i+borderHor, borderVer, _sceneRoot));
02217                                 vGridLines.last()->setPen(pen);
02218                                 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, borderVer, stepH*i+borderHor, h+borderVer, _sceneRoot));
02219                                 vGridLines.last()->setPen(dashPen);
02220                                 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, h+borderVer, stepH*i+borderHor, h+borderVer*2, _sceneRoot));
02221                                 vGridLines.last()->setPen(pen);
02222                         }
02223                 }
02224         }
02225 
02226         // curves
02227         float scaleX = 1;
02228         float scaleY = 1;
02229         float den = 0;
02230         den = axis[1] - axis[0];
02231         if(den != 0)
02232         {
02233                 scaleX = (newRect.width()-(borderHor*2)) / den;
02234         }
02235         den = axis[3] - axis[2];
02236         if(den != 0)
02237         {
02238                 scaleY = (newRect.height()-(borderVer*2)) / den;
02239         }
02240         for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
02241         {
02242                 if((*i)->isVisible())
02243                 {
02244                         float xDir = 1.0f;
02245                         float yDir = -1.0f;
02246                         (*i)->update(scaleX,
02247                                                 scaleY,
02248                                                 xDir<0?axis[1]+borderHor/scaleX:-(axis[0]-borderHor/scaleX),
02249                                                 yDir<0?axis[3]+borderVer/scaleY:-(axis[2]-borderVer/scaleY),
02250                                                 xDir,
02251                                                 yDir,
02252                                                 _aKeepAllData->isChecked()?0:_maxVisibleItems);
02253                         if(painter)
02254                         {
02255                                 (*i)->draw(painter, QRect(0,0,_graphicsViewHolder->rect().width(), _graphicsViewHolder->rect().height()));
02256                         }
02257                 }
02258         }
02259 
02260         // Update refresh rate
02261         if(_aShowRefreshRate->isChecked())
02262         {
02263                 int refreshRate = qRound(1000.0f/float(_refreshIntervalTime.restart()));
02264                 if(refreshRate > 0 && refreshRate < _lowestRefreshRate)
02265                 {
02266                         _lowestRefreshRate = refreshRate;
02267                 }
02268                 // Refresh the label only after each 1000 ms
02269                 if(_refreshStartTime.elapsed() > 1000)
02270                 {
02271                         _refreshRate->setText(QString::number(_lowestRefreshRate));
02272                         _lowestRefreshRate = 99;
02273                         _refreshStartTime.start();
02274                 }
02275         }
02276 }
02277 
02278 void UPlot::setFixedXAxis(float x1, float x2)
02279 {
02280         _fixedAxis[0] = true;
02281         _axisMaximums[0] = x1;
02282         _axisMaximums[1] = x2;
02283 }
02284 
02285 void UPlot::setFixedYAxis(float y1, float y2)
02286 {
02287         _fixedAxis[1] = true;
02288         _axisMaximums[2] = y1;
02289         _axisMaximums[3] = y2;
02290 }
02291 
02292 void UPlot::updateAxis(const UPlotCurve * curve)
02293 {
02294         if(curve && curve->isVisible() && curve->itemsSize() && curve->isMinMaxValid())
02295         {
02296                 const QVector<float> & minMax = curve->getMinMax();
02297                 //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", minMax[0], minMax[1], minMax[2], minMax[3]);
02298                 if(minMax.size() != 4)
02299                 {
02300                         ULOGGER_ERROR("minMax size != 4 ?!?");
02301                         return;
02302                 }
02303                 this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
02304                 _aGraphicsView->isChecked()?this->replot(0):this->update();
02305         }
02306 }
02307 
02308 bool UPlot::updateAxis(float x1, float x2, float y1, float y2)
02309 {
02310         bool modified = false;
02311         modified = updateAxis(x1,y1);
02312         if(!modified)
02313         {
02314                 modified = updateAxis(x2,y2);
02315         }
02316         else
02317         {
02318                 updateAxis(x2,y2);
02319         }
02320         return modified;
02321 }
02322 
02323 bool UPlot::updateAxis(float x, float y)
02324 {
02325         //ULOGGER_DEBUG("x=%f, y=%f", x,y);
02326         bool modified = false;
02327         if(!_fixedAxis[0] && (!_axisMaximumsSet[0] || x < _axisMaximums[0]))
02328         {
02329                 _axisMaximums[0] = x;
02330                 _axisMaximumsSet[0] = true;
02331                 modified = true;
02332         }
02333 
02334         if(!_fixedAxis[0] && (!_axisMaximumsSet[1] || x > _axisMaximums[1]))
02335         {
02336                 _axisMaximums[1] = x;
02337                 _axisMaximumsSet[1] = true;
02338                 modified = true;
02339         }
02340 
02341         if(!_fixedAxis[1] && (!_axisMaximumsSet[2] || y < _axisMaximums[2]))
02342         {
02343                 _axisMaximums[2] = y;
02344                 _axisMaximumsSet[2] = true;
02345                 modified = true;
02346         }
02347 
02348         if(!_fixedAxis[1] && (!_axisMaximumsSet[3] || y > _axisMaximums[3]))
02349         {
02350                 _axisMaximums[3] = y;
02351                 _axisMaximumsSet[3] = true;
02352                 modified = true;
02353         }
02354 
02355         return modified;
02356 }
02357 
02358 void UPlot::updateAxis()
02359 {
02360         //Reset the axis
02361         for(int i=0; i<4; ++i)
02362         {
02363                 if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
02364                 {
02365                         _axisMaximums[i] = 0;
02366                         _axisMaximumsSet[i] = false;
02367                 }
02368         }
02369 
02370         for(int i=0; i<_curves.size(); ++i)
02371         {
02372                 if(_curves.at(i)->isVisible() && _curves.at(i)->isMinMaxValid())
02373                 {
02374                         const QVector<float> & minMax = _curves.at(i)->getMinMax();
02375                         this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
02376                 }
02377         }
02378 
02379         _aGraphicsView->isChecked()?this->replot(0):this->update();
02380 
02381         this->captureScreen();
02382 }
02383 
02384 void UPlot::paintEvent(QPaintEvent * event)
02385 {
02386 #if PRINT_DEBUG
02387         UDEBUG("");
02388 #endif
02389         if(!_aGraphicsView->isChecked())
02390         {
02391                 QPainter painter(this);
02392                 painter.translate(_graphicsViewHolder->pos());
02393                 painter.save();
02394                 painter.setBrush(_bgColor);
02395                 painter.setPen(QPen(Qt::NoPen));
02396                 painter.drawRect(_graphicsViewHolder->rect());
02397                 painter.restore();
02398 
02399                 this->replot(&painter);
02400 
02401                 if(_mouseCurrentPos != _mousePressedPos)
02402                 {
02403                         painter.save();
02404                         int left, top, right, bottom;
02405                         left = _mousePressedPos.x() < _mouseCurrentPos.x() ? _mousePressedPos.x()-_graphicsViewHolder->x():_mouseCurrentPos.x()-_graphicsViewHolder->x();
02406                         top = _mousePressedPos.y() < _mouseCurrentPos.y() ? _mousePressedPos.y()-1-_graphicsViewHolder->y():_mouseCurrentPos.y()-1-_graphicsViewHolder->y();
02407                         right = _mousePressedPos.x() > _mouseCurrentPos.x() ? _mousePressedPos.x()-_graphicsViewHolder->x():_mouseCurrentPos.x()-_graphicsViewHolder->x();
02408                         bottom = _mousePressedPos.y() > _mouseCurrentPos.y() ? _mousePressedPos.y()-_graphicsViewHolder->y():_mouseCurrentPos.y()-_graphicsViewHolder->y();
02409                         if(left <= 0)
02410                         {
02411                                 left = 1;
02412                         }
02413                         if(right >= _graphicsViewHolder->width())
02414                         {
02415                                 right = _graphicsViewHolder->width()-1;
02416                         }
02417                         if(top <= 0)
02418                         {
02419                                 top = 1;
02420                         }
02421                         if(bottom >= _graphicsViewHolder->height())
02422                         {
02423                                 bottom = _graphicsViewHolder->height()-1;
02424                         }
02425                         painter.setPen(Qt::NoPen);
02426                         painter.setBrush(QBrush(QColor(255-_bgColor.red(),255-_bgColor.green(),255-_bgColor.blue(),100)));
02427                         painter.drawRect(0, 0, _graphicsViewHolder->width(), top);
02428                         painter.drawRect(0, top, left, bottom-top);
02429                         painter.drawRect(right, top, _graphicsViewHolder->width()-right, bottom-top);
02430                         painter.drawRect(0, bottom, _graphicsViewHolder->width(), _graphicsViewHolder->height()-bottom);
02431                         painter.restore();
02432                 }
02433         }
02434         else
02435         {
02436                 QWidget::paintEvent(event);
02437         }
02438 }
02439 
02440 void UPlot::resizeEvent(QResizeEvent * event)
02441 {
02442         if(_aGraphicsView->isChecked())
02443         {
02444                 this->replot(0);
02445         }
02446         QWidget::resizeEvent(event);
02447 }
02448 
02449 void UPlot::mousePressEvent(QMouseEvent * event)
02450 {
02451         _mousePressedPos = event->pos();
02452         _mouseCurrentPos = _mousePressedPos;
02453         QWidget::mousePressEvent(event);
02454 }
02455 
02456 void UPlot::mouseMoveEvent(QMouseEvent * event)
02457 {
02458         if(!_aGraphicsView->isChecked())
02459         {
02460                 if(!(QApplication::mouseButtons() & Qt::LeftButton))
02461                 {
02462                         _mousePressedPos = _mouseCurrentPos;
02463                 }
02464 
02465                 float x,y;
02466                 if(mousePosToValue(event->pos(), x ,y))
02467                 {
02468                         if(QApplication::mouseButtons() & Qt::LeftButton)
02469                         {
02470                                 _mouseCurrentPos = event->pos();
02471                                 this->update();
02472                         }
02473 
02474                         int xPos = event->pos().x() - _graphicsViewHolder->pos().x();
02475                         int yPos = event->pos().y() - _graphicsViewHolder->pos().y();
02476                         if((QApplication::mouseButtons() & Qt::LeftButton) ||
02477                            (_aMouseTracking->isChecked() && xPos>=0 && yPos>=0 && xPos<_graphicsViewHolder->width() && yPos<_graphicsViewHolder->height()))
02478                         {
02479                                 QToolTip::showText(event->globalPos(), QString("%1,%2").arg(x).arg(y));
02480                         }
02481                         else
02482                         {
02483                                 QToolTip::hideText();
02484                         }
02485                 }
02486                 else
02487                 {
02488                         QToolTip::hideText();
02489                 }
02490         }
02491         QWidget::mouseMoveEvent(event);
02492 }
02493 
02494 void UPlot::mouseReleaseEvent(QMouseEvent * event)
02495 {
02496         if(_mousePressedPos != _mouseCurrentPos)
02497         {
02498                 int left,top,bottom,right;
02499 
02500                 left = _mousePressedPos.x() < _mouseCurrentPos.x() ? _mousePressedPos.x():_mouseCurrentPos.x();
02501                 top = _mousePressedPos.y() < _mouseCurrentPos.y() ? _mousePressedPos.y():_mouseCurrentPos.y();
02502                 right = _mousePressedPos.x() > _mouseCurrentPos.x() ? _mousePressedPos.x():_mouseCurrentPos.x();
02503                 bottom = _mousePressedPos.y() > _mouseCurrentPos.y() ? _mousePressedPos.y():_mouseCurrentPos.y();
02504 
02505                 if(right - left > 5 || bottom - top > 5)
02506                 {
02507                         float axis[4];
02508                         if(mousePosToValue(QPoint(left, top), axis[0], axis[3]) && mousePosToValue(QPoint(right, bottom), axis[1], axis[2]))
02509                         {
02510 #if PRINT_DEBUG
02511                                 UDEBUG("resize! new axis = [%f, %f, %f, %f]", axis[0], axis[1], axis[2], axis[3]);
02512 #endif
02513                                 //update axis (only if not fixed)
02514                                 for(int i=0; i<4; ++i)
02515                                 {
02516                                         if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
02517                                         {
02518                                                 _axisMaximums[i] = axis[i];
02519                                         }
02520                                 }
02521                                 _aGraphicsView->isChecked()?this->replot(0):this->update();
02522                         }
02523                 }
02524                 _mousePressedPos = _mouseCurrentPos;
02525         }
02526         QWidget::mouseReleaseEvent(event);
02527 }
02528 
02529 void UPlot::mouseDoubleClickEvent(QMouseEvent * event)
02530 {
02531         this->updateAxis();
02532         QWidget::mouseDoubleClickEvent(event);
02533 }
02534 
02535 bool UPlot::mousePosToValue(const QPoint & pos, float & x, float & y)
02536 {
02537         int xPos = pos.x() - _graphicsViewHolder->pos().x() - _horizontalAxis->border();
02538         int yPos = pos.y() - _graphicsViewHolder->pos().y() - _verticalAxis->border();
02539         int maxX = _graphicsViewHolder->width() - _horizontalAxis->border()*2;
02540         int maxY = _graphicsViewHolder->height() - _verticalAxis->border()*2;
02541         if(maxX == 0 || maxY == 0)
02542         {
02543                 return false;
02544         }
02545 
02546         if(xPos < 0)
02547         {
02548                 xPos = 0;
02549         }
02550         else if(xPos > maxX)
02551         {
02552                 xPos = maxX;
02553         }
02554 
02555         if(yPos < 0)
02556         {
02557                 yPos = 0;
02558         }
02559         else if(yPos > maxY)
02560         {
02561                 yPos = maxY;
02562         }
02563 
02564         //UDEBUG("IN");
02565         //UDEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
02566         //UDEBUG("border hor=%f ver=%f", (float)_horizontalAxis->border(), (float)_verticalAxis->border());
02567         //UDEBUG("rect = %d,%d %d,%d", _graphicsViewHolder->pos().x(), _graphicsViewHolder->pos().y(), _graphicsViewHolder->width(), _graphicsViewHolder->height());
02568         //UDEBUG("%d,%d", event->pos().x(), event->pos().y());
02569         //UDEBUG("x/y %d,%d", x, y);
02570         //UDEBUG("max %d,%d", maxX, maxY);
02571 
02572         //UDEBUG("map %f,%f", x, y);
02573         x = _axisMaximums[0] + float(xPos)*(_axisMaximums[1] - _axisMaximums[0]) / float(maxX);
02574         y = _axisMaximums[2] + float(maxY - yPos)*(_axisMaximums[3] - _axisMaximums[2]) / float(maxY);
02575         return true;
02576 }
02577 
02578 void UPlot::contextMenuEvent(QContextMenuEvent * event)
02579 {
02580         QAction * action = _menu->exec(event->globalPos());
02581 
02582         if(!action)
02583         {
02584                 return;
02585         }
02586         else if(action == _aShowLegend)
02587         {
02588                 this->showLegend(_aShowLegend->isChecked());
02589         }
02590         else if(action == _aShowGrid)
02591         {
02592                 this->showGrid(_aShowGrid->isChecked());
02593         }
02594         else if(action == _aShowRefreshRate)
02595         {
02596                 this->showRefreshRate(_aShowRefreshRate->isChecked());
02597         }
02598         else if(action == _aMouseTracking)
02599         {
02600                 this->trackMouse(_aMouseTracking->isChecked());
02601         }
02602         else if(action == _aGraphicsView)
02603         {
02604                 this->setGraphicsView(_aGraphicsView->isChecked());
02605         }
02606         else if(action == _aKeepAllData)
02607         {
02608                 this->keepAllData(_aKeepAllData->isChecked());
02609         }
02610         else if(action == _aLimit0 ||
02611                         action == _aLimit10 ||
02612                         action == _aLimit50 ||
02613                         action == _aLimit100 ||
02614                         action == _aLimit500 ||
02615                         action == _aLimit1000 ||
02616                         action == _aLimitCustom)
02617         {
02618                 this->setMaxVisibleItems(action->text().toInt());
02619         }
02620         else if(action == _aAddVerticalLine || action == _aAddHorizontalLine)
02621         {
02622                 bool ok;
02623                 QString text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
02624                 while(ok && text.isEmpty())
02625                 {
02626                         QMessageBox::warning(this, action->text(), tr("The name is not valid or it is already used in this plot."));
02627                         text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
02628                 }
02629                 if(ok)
02630                 {
02631                         double min = _axisMaximums[2];
02632                         double max = _axisMaximums[3];
02633                         QString axis = "Y";
02634                         if(action == _aAddVerticalLine)
02635                         {
02636                                 min = _axisMaximums[0];
02637                                 max = _axisMaximums[1];
02638                                 axis = "X";
02639                         }
02640                         double value = QInputDialog::getDouble(this,
02641                                         action->text(),
02642                                         tr("%1 value (min=%2, max=%3):").arg(axis).arg(min).arg(max),
02643                                         (min+max)/2,
02644                                         -2147483647,
02645                                         2147483647,
02646                                         4,
02647                                         &ok);
02648                         if(ok)
02649                         {
02650                                 if(action == _aAddHorizontalLine)
02651                                 {
02652                                         this->addThreshold(text, value, Qt::Horizontal);
02653                                 }
02654                                 else
02655                                 {
02656                                         this->addThreshold(text, value, Qt::Vertical);
02657                                 }
02658                         }
02659                 }
02660         }
02661         else if(action == _aChangeTitle)
02662         {
02663                 bool ok;
02664                 QString text = _title->text();
02665                 if(text.isEmpty())
02666                 {
02667                         text = this->objectName();
02668                 }
02669                 text = QInputDialog::getText(this, _aChangeTitle->text(), tr("Title :"), QLineEdit::Normal, text, &ok);
02670                 if(ok)
02671                 {
02672                         this->setTitle(text);
02673                 }
02674         }
02675         else if(action == _aChangeXLabel)
02676         {
02677                 bool ok;
02678                 QString text = QInputDialog::getText(this, _aChangeXLabel->text(), tr("X axis label :"), QLineEdit::Normal, _xLabel->text(), &ok);
02679                 if(ok)
02680                 {
02681                         this->setXLabel(text);
02682                 }
02683         }
02684         else if(action == _aChangeYLabel)
02685         {
02686                 bool ok;
02687                 QString text = QInputDialog::getText(this, _aChangeYLabel->text(), tr("Y axis label :"), QLineEdit::Normal, _yLabel->text(), &ok);
02688                 if(ok)
02689                 {
02690                         this->setYLabel(text, _yLabel->orientation());
02691                 }
02692         }
02693         else if(action == _aYLabelVertical)
02694         {
02695                 this->setYLabel(_yLabel->text(), _aYLabelVertical->isChecked()?Qt::Vertical:Qt::Horizontal);
02696         }
02697         else if(action == _aChangeBackgroundColor)
02698         {
02699                 QColor color = QColorDialog::getColor(_bgColor, this);
02700                 if(color.isValid())
02701                 {
02702                         this->setBackgroundColor(color);
02703                 }
02704         }
02705         else if(action == _aSaveFigure)
02706         {
02707 
02708                 QString text;
02709 #ifdef QT_SVG_LIB
02710                 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf *.svg");
02711 #else
02712                 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf");
02713 #endif
02714                 if(!text.isEmpty())
02715                 {
02716                         bool flatModified = false;
02717                         if(!_legend->isFlat())
02718                         {
02719                                 _legend->setFlat(true);
02720                                 flatModified = true;
02721                         }
02722 
02723                         QPalette p(palette());
02724                         // Set background color to white
02725                         QColor c = p.color(QPalette::Background);
02726                         p.setColor(QPalette::Background, Qt::white);
02727                         setPalette(p);
02728 
02729 #ifdef QT_SVG_LIB
02730                         if(QFileInfo(text).suffix().compare("svg") == 0)
02731                         {
02732                                 QSvgGenerator generator;
02733                                 generator.setFileName(text);
02734                                 generator.setSize(this->size());
02735                                 QPainter painter;
02736                                 painter.begin(&generator);
02737                                 this->render(&painter);
02738                                 painter.end();
02739                         }
02740                         else
02741                         {
02742 #endif
02743                                 if(QFileInfo(text).suffix().compare("pdf") == 0)
02744                                 {
02745                                         QPrinter printer;
02746                                         printer.setOutputFormat(QPrinter::PdfFormat);
02747                                         printer.setOutputFileName(text);
02748                                         this->render(&printer);
02749                                 }
02750                                 else
02751                                 {
02752                                         QPixmap figure = QPixmap::grabWidget(this);
02753                                         figure.save(text);
02754                                 }
02755 #ifdef QT_SVG_LIB
02756                         }
02757 #endif
02758                         // revert background color
02759                         p.setColor(QPalette::Background, c);
02760                         setPalette(p);
02761 
02762                         if(flatModified)
02763                         {
02764                                 _legend->setFlat(false);
02765                         }
02766                 }
02767         }
02768         else if(action == _aAutoScreenCapture)
02769         {
02770                 if(_aAutoScreenCapture->isChecked())
02771                 {
02772                         this->selectScreenCaptureFormat();
02773                 }
02774         }
02775         else if(action == _aClearData)
02776         {
02777                 this->clearData();
02778         }
02779         else
02780         {
02781                 ULOGGER_WARN("Unknown action");
02782         }
02783 }
02784 
02785 void UPlot::setWorkingDirectory(const QString & workingDirectory)
02786 {
02787         if(QDir(_workingDirectory).exists())
02788         {
02789                 _workingDirectory = workingDirectory;
02790         }
02791         else
02792         {
02793                 ULOGGER_ERROR("The directory \"%s\" doesn't exist", workingDirectory.toStdString().c_str());
02794         }
02795 }
02796 
02797 void UPlot::captureScreen()
02798 {
02799         if(!_aAutoScreenCapture->isChecked())
02800         {
02801                 return;
02802         }
02803         QString targetDir = _workingDirectory + "/ScreensCaptured";
02804         QDir dir;
02805         if(!dir.exists(targetDir))
02806         {
02807                 dir.mkdir(targetDir);
02808         }
02809         targetDir += "/";
02810         targetDir += this->title().replace(" ", "_");
02811         if(!dir.exists(targetDir))
02812         {
02813                 dir.mkdir(targetDir);
02814         }
02815         targetDir += "/";
02816         QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + ".") + _autoScreenCaptureFormat;
02817         QPixmap figure = QPixmap::grabWidget(this);
02818         figure.save(targetDir + name);
02819 }
02820 
02821 void UPlot::selectScreenCaptureFormat()
02822 {
02823         QStringList items;
02824         items << QString("png") << QString("jpg");
02825         bool ok;
02826         QString item = QInputDialog::getItem(this, tr("Select format"), tr("Format:"), items, 0, false, &ok);
02827         if(ok && !item.isEmpty())
02828         {
02829                 _autoScreenCaptureFormat = item;
02830         }
02831         this->captureScreen();
02832 }
02833 
02834 void UPlot::clearData()
02835 {
02836         for(int i=0; i<_curves.size(); ++i)
02837         {
02838                 // Don't clear threshold curves
02839                 if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
02840                 {
02841                         _curves.at(i)->clear();
02842                 }
02843         }
02844         _aGraphicsView->isChecked()?this->replot(0):this->update();
02845 }
02846 
02847 // for convenience...
02848 UPlotCurveThreshold * UPlot::addThreshold(const QString & name, float value, Qt::Orientation orientation)
02849 {
02850         UPlotCurveThreshold * curve = new UPlotCurveThreshold(name, value, orientation, this);
02851         QPen pen = curve->pen();
02852         pen.setStyle((Qt::PenStyle)(_penStyleCount++ % 4 + 2));
02853         curve->setPen(pen);
02854         if(!this->addCurve(curve))
02855         {
02856                 if(curve)
02857                 {
02858                         delete curve;
02859                 }
02860         }
02861         else
02862         {
02863                 _aGraphicsView->isChecked()?this->replot(0):this->update();
02864         }
02865         return curve;
02866 }
02867 
02868 void UPlot::setTitle(const QString & text)
02869 {
02870         _title->setText(text);
02871         _title->setVisible(!text.isEmpty());
02872         this->update();
02873         if(_aGraphicsView->isChecked())
02874         {
02875                 QTimer::singleShot(10, this, SLOT(updateAxis()));
02876         }
02877 }
02878 
02879 void UPlot::setXLabel(const QString & text)
02880 {
02881         _xLabel->setText(text);
02882         _xLabel->setVisible(!text.isEmpty());
02883         this->update();
02884         if(_aGraphicsView->isChecked())
02885         {
02886                 QTimer::singleShot(10, this, SLOT(updateAxis()));
02887         }
02888 }
02889 
02890 void UPlot::setYLabel(const QString & text, Qt::Orientation orientation)
02891 {
02892         _yLabel->setText(text);
02893         _yLabel->setOrientation(orientation);
02894         _yLabel->setVisible(!text.isEmpty());
02895         _aYLabelVertical->setChecked(orientation==Qt::Vertical);
02896         this->update();
02897         if(_aGraphicsView->isChecked())
02898         {
02899                 QTimer::singleShot(10, this, SLOT(updateAxis()));
02900         }
02901 }
02902 
02903 void UPlot::setBackgroundColor(const QColor & color)
02904 {
02905         if(color.isValid())
02906         {
02907                 _bgColor = color;
02908                 _view->scene()->setBackgroundBrush(QBrush(_bgColor));
02909                 for(QList<UPlotCurve*>::iterator iter=_curves.begin(); iter!=_curves.end(); ++iter)
02910                 {
02911                         (*iter)->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), _bgColor.alpha()));
02912                 }
02913         }
02914 }
02915 
02916 void UPlot::addItem(QGraphicsItem * item)
02917 {
02918         item->setParentItem(_sceneRoot);
02919         item->setZValue(1.0f);
02920 }
02921 
02922 void UPlot::showLegend(bool shown)
02923 {
02924         _legend->setVisible(shown);
02925         _aShowLegend->setChecked(shown);
02926         this->update();
02927         if(_aGraphicsView->isChecked())
02928         {
02929                 QTimer::singleShot(10, this, SLOT(updateAxis()));
02930         }
02931 }
02932 
02933 void UPlot::showGrid(bool shown)
02934 {
02935         _aShowGrid->setChecked(shown);
02936         _aGraphicsView->isChecked()?this->replot(0):this->update();
02937 }
02938 
02939 void UPlot::showRefreshRate(bool shown)
02940 {
02941         _aShowRefreshRate->setChecked(shown);
02942         _refreshRate->setVisible(shown);
02943         this->update();
02944         if(_aGraphicsView->isChecked())
02945         {
02946                 QTimer::singleShot(10, this, SLOT(updateAxis()));
02947         }
02948 }
02949 
02950 void UPlot::trackMouse(bool tracking)
02951 {
02952         _aMouseTracking->setChecked(tracking);
02953         this->setMouseTracking(tracking);
02954 }
02955 
02956 void UPlot::setGraphicsView(bool on)
02957 {
02958         _aGraphicsView->setChecked(on);
02959         _view->setVisible(on);
02960         _aGraphicsView->isChecked()?this->replot(0):this->update();
02961         _aMouseTracking->setEnabled(!on);
02962 }
02963 
02964 void UPlot::keepAllData(bool kept)
02965 {
02966         _aKeepAllData->setChecked(kept);
02967 }
02968 
02969 void UPlot::setMaxVisibleItems(int maxVisibleItems)
02970 {
02971         if(maxVisibleItems <= 0)
02972         {
02973                 _aLimit0->setChecked(true);
02974         }
02975         else if(maxVisibleItems == 10)
02976         {
02977                 _aLimit10->setChecked(true);
02978         }
02979         else if(maxVisibleItems == 50)
02980         {
02981                 _aLimit50->setChecked(true);
02982         }
02983         else if(maxVisibleItems == 100)
02984         {
02985                 _aLimit100->setChecked(true);
02986         }
02987         else if(maxVisibleItems == 500)
02988         {
02989                 _aLimit500->setChecked(true);
02990         }
02991         else if(maxVisibleItems == 1000)
02992         {
02993                 _aLimit1000->setChecked(true);
02994         }
02995         else
02996         {
02997                 _aLimitCustom->setVisible(true);
02998                 _aLimitCustom->setChecked(true);
02999                 _aLimitCustom->setText(QString::number(maxVisibleItems));
03000         }
03001         _maxVisibleItems = maxVisibleItems;
03002         updateAxis();
03003 }
03004 
03005 QRectF UPlot::sceneRect() const
03006 {
03007         return _view->sceneRect();
03008 }
03009 
03010 void UPlot::removeCurves()
03011 {
03012         QList<UPlotCurve*> tmp = _curves;
03013         for(QList<UPlotCurve*>::iterator iter=tmp.begin(); iter!=tmp.end(); ++iter)
03014         {
03015                 this->removeCurve(*iter);
03016         }
03017         _curves.clear();
03018 }
03019 
03020 void UPlot::removeCurve(const UPlotCurve * curve)
03021 {
03022         QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
03023 #if PRINT_DEBUG
03024         ULOGGER_DEBUG("Plot=\"%s\" removing curve=\"%s\"", this->objectName().toStdString().c_str(), curve?curve->name().toStdString().c_str():"");
03025 #endif
03026         if(iter!=_curves.end())
03027         {
03028                 UPlotCurve * c = *iter;
03029                 c->detach(this);
03030                 _curves.erase(iter);
03031                 _legend->remove(c);
03032                 if(!qobject_cast<UPlotCurveThreshold*>(c))
03033                 {
03034                         // transfer update connection to next curve
03035                         for(int i=_curves.size()-1; i>=0; --i)
03036                         {
03037                                 if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
03038                                 {
03039                                         connect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
03040                                         break;
03041                                 }
03042                         }
03043                 }
03044 
03045                 if(c->parent() == this)
03046                 {
03047                         delete c;
03048                 }
03049                 // Update axis
03050                 updateAxis();
03051         }
03052 }
03053 
03054 void UPlot::showCurve(const UPlotCurve * curve, bool shown)
03055 {
03056         QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
03057         if(iter!=_curves.end())
03058         {
03059                 UPlotCurve * value = *iter;
03060                 if(value->isVisible() != shown)
03061                 {
03062                         value->setVisible(shown);
03063                         this->updateAxis();
03064                 }
03065         }
03066 }
03067 
03068 void UPlot::moveCurve(const UPlotCurve * curve, int index)
03069 {
03070         // this will change the print order
03071         int currentIndex = -1;
03072         UPlotCurve * c = 0;
03073         for(int i=0; i<_curves.size(); ++i)
03074         {
03075                 if(_curves.at(i) == curve)
03076                 {
03077                         c = _curves.at(i);
03078                         currentIndex = i;
03079                         break;
03080                 }
03081         }
03082 
03083         if(c && currentIndex != index)
03084         {
03085                 _curves.removeAt(currentIndex);
03086                 QList<QGraphicsItem *> children = _sceneRoot->childItems();
03087                 _curves.insert(index, c);
03088                 if(currentIndex > index)
03089                 {
03090                         children[currentIndex]->stackBefore(children[index]);
03091                 }
03092                 else
03093                 {
03094                         if(currentIndex<children.size()-2)
03095                         {
03096                                 if(index < children.size()-1)
03097                                 {
03098                                         children[index]->stackBefore(children[currentIndex]);
03099                                 }
03100                                 else
03101                                 {
03102                                         children[currentIndex]->stackBefore(children[index]);
03103                                 }
03104                         }
03105                         if(currentIndex == children.size()-2 && currentIndex < index)
03106                         {
03107                                 children[index]->stackBefore(children[currentIndex]);
03108                         }
03109                 }
03110                 this->update();
03111         }
03112 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:59:32