00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "utilite/UPlot.h"
00023
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
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
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
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
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
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
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;
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;
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;
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;
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;
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;
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);
00568 }
00569 else if(_items.size()>1)
00570 {
00571 delete _items.takeAt(index+1);
00572 }
00573 UPlotItem * item = (UPlotItem *)_items.takeAt(index);
00574
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)
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
00663
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
00678 if(!item->isVisible())
00679 {
00680 break;
00681 }
00682 item->setVisible(false);
00683 }
00684 else
00685 {
00686
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
00721
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
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
00750 if(i-1>=0)
00751 {
00752 painter->save();
00753 painter->setPen(this->pen());
00754 painter->setBrush(this->brush());
00755
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
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
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
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
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
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
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
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
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
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
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
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;
01068 }
01069 #ifdef WIN32
01070 this->setMinimumSize(15, 25);
01071 #else
01072 this->setMinimumSize(15, 25);
01073 #endif
01074 this->setAxis(min, max);
01075 }
01076
01077 UPlotAxis::~UPlotAxis()
01078 {
01079 #if PRINT_DEBUG
01080 ULOGGER_DEBUG("");
01081 #endif
01082 }
01083
01084
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
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
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
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
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
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
01399 QHBoxLayout * hLayout = new QHBoxLayout();
01400 hLayout->addWidget(legendItem);
01401 hLayout->addStretch(0);
01402 hLayout->setMargin(0);
01403
01404
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
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;
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
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
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
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
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
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
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
01857 qDeleteAll(hGridLines);
01858 hGridLines.clear();
01859 qDeleteAll(vGridLines);
01860 vGridLines.clear();
01861 if(_aShowGrid->isChecked())
01862 {
01863
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }