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


find_object_2d
Author(s): Mathieu Labbe
autogenerated on Thu Feb 11 2016 22:57:56