PlotWidget.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002  * Copyright (C) 2015 by Ralf Kaestner                                        *
00003  * ralf.kaestner@gmail.com                                                    *
00004  *                                                                            *
00005  * This program is free software; you can redistribute it and/or modify       *
00006  * it under the terms of the Lesser GNU General Public License as published by*
00007  * the Free Software Foundation; either version 3 of the License, or          *
00008  * (at your option) any later version.                                        *
00009  *                                                                            *
00010  * This program is distributed in the hope that it will be useful,            *
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the               *
00013  * Lesser GNU General Public License for more details.                        *
00014  *                                                                            *
00015  * You should have received a copy of the Lesser GNU General Public License   *
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.       *
00017  ******************************************************************************/
00018 
00019 #include <QDragEnterEvent>
00020 #include <QDropEvent>
00021 #include <QFile>
00022 #include <QFileDialog>
00023 #include <QFontMetrics>
00024 #include <QPainter>
00025 #include <QTextStream>
00026 #include <QMimeData>
00027 
00028 #include <qwt/qwt_plot_canvas.h>
00029 #include <qwt/qwt_plot_curve.h>
00030 #include <qwt/qwt_plot_picker.h>
00031 #include <qwt/qwt_plot_renderer.h>
00032 #include <qwt/qwt_scale_widget.h>
00033 #include <qwt/qwt_plot.h>
00034 
00035 #include <ros/package.h>
00036 
00037 #include <rqt_multiplot/CurveData.h>
00038 #include <rqt_multiplot/PlotConfigDialog.h>
00039 #include <rqt_multiplot/PlotConfigWidget.h>
00040 #include <rqt_multiplot/PlotCursor.h>
00041 #include <rqt_multiplot/PlotCurve.h>
00042 #include <rqt_multiplot/PlotLegend.h>
00043 #include <rqt_multiplot/PlotMagnifier.h>
00044 #include <rqt_multiplot/PlotPanner.h>
00045 #include <rqt_multiplot/PlotZoomer.h>
00046 
00047 #include <ui_PlotWidget.h>
00048 
00049 #include "rqt_multiplot/PlotWidget.h"
00050 
00051 namespace rqt_multiplot {
00052 
00053 /*****************************************************************************/
00054 /* Constructors and Destructor                                               */
00055 /*****************************************************************************/
00056 
00057 PlotWidget::PlotWidget(QWidget* parent) :
00058   QWidget(parent),
00059   ui_(new Ui::PlotWidget()),
00060   timer_(new QTimer(this)),
00061   menuImportExport_(new QMenu(this)),
00062   config_(0),
00063   broker_(0),
00064   legend_(0),
00065   cursor_(0),
00066   panner_(0),
00067   magnifier_(0),
00068   zoomer_(0),
00069   paused_(true),
00070   rescale_(false),
00071   replot_(false),
00072   state_(Normal) {
00073   qRegisterMetaType<BoundingRectangle>("BoundingRectangle");
00074 
00075   ui_->setupUi(this);
00076 
00077   setAcceptDrops(true);
00078 
00079   runIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00080     "rqt_multiplot").append("/resource/16x16/run.png")));
00081   pauseIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00082     "rqt_multiplot").append("/resource/16x16/pause.png")));
00083   normalIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00084     "rqt_multiplot").append("/resource/16x16/zoom_in.png")));
00085   maximizedIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00086     "rqt_multiplot").append("/resource/16x16/zoom_out.png")));
00087 
00088   ui_->pushButtonRunPause->setIcon(runIcon_);
00089   ui_->pushButtonClear->setIcon(
00090     QIcon(QString::fromStdString(ros::package::getPath("rqt_multiplot").
00091     append("/resource/16x16/clear.png"))));
00092   ui_->pushButtonImportExport->setIcon(
00093     QIcon(QString::fromStdString(ros::package::getPath("rqt_multiplot").
00094     append("/resource/16x16/eject.png"))));
00095   ui_->pushButtonSetup->setIcon(
00096     QIcon(QString::fromStdString(ros::package::getPath("rqt_multiplot").
00097     append("/resource/16x16/setup.png"))));
00098   ui_->pushButtonState->setIcon(normalIcon_);
00099 
00100   ui_->plot->setAutoReplot(false);
00101   static_cast<QFrame*>(ui_->plot->canvas())->setFrameStyle(QFrame::NoFrame);
00102 
00103   ui_->plot->enableAxis(QwtPlot::xTop);
00104   ui_->plot->enableAxis(QwtPlot::yRight);
00105 
00106   ui_->plot->setAxisAutoScale(QwtPlot::yLeft, false);
00107   ui_->plot->setAxisAutoScale(QwtPlot::yRight, false);
00108   ui_->plot->setAxisAutoScale(QwtPlot::xTop, false);
00109   ui_->plot->setAxisAutoScale(QwtPlot::xBottom, false);
00110 
00111   ui_->plot->axisScaleDraw(QwtPlot::xTop)->enableComponent(
00112     QwtAbstractScaleDraw::Labels, false);
00113   ui_->plot->axisScaleDraw(QwtPlot::yRight)->enableComponent(
00114     QwtAbstractScaleDraw::Labels, false);
00115 
00116   ui_->horizontalSpacerRight->changeSize(
00117     ui_->plot->axisWidget(QwtPlot::yRight)->width()-5, 20);
00118 
00119   timer_->setInterval(1e3/30.0);
00120   timer_->start();
00121 
00122   menuImportExport_->addAction("Export to image file...", this,
00123     SLOT(menuExportImageFileTriggered()));
00124   menuImportExport_->addAction("Export to text file...", this,
00125     SLOT(menuExportTextFileTriggered()));
00126 
00127   QwtPlotCanvas* canvas = static_cast<QwtPlotCanvas*>(ui_->plot->canvas());
00128   cursor_ = new PlotCursor(canvas);
00129   magnifier_ = new PlotMagnifier(canvas);
00130   panner_ = new PlotPanner(canvas);
00131   zoomer_ = new PlotZoomer(canvas);
00132   zoomer_->setTrackerMode(QwtPicker::AlwaysOff);
00133 
00134   #if QWT_VERSION >= 0x060100
00135     currentBounds_.getMinimum().setX(ui_->plot->axisScaleDiv(
00136       QwtPlot::xBottom).lowerBound());
00137     currentBounds_.getMinimum().setY(ui_->plot->axisScaleDiv(
00138       QwtPlot::yLeft).lowerBound());
00139     currentBounds_.getMaximum().setX(ui_->plot->axisScaleDiv(
00140       QwtPlot::xBottom).upperBound());
00141     currentBounds_.getMaximum().setY(ui_->plot->axisScaleDiv(
00142       QwtPlot::yLeft).upperBound());
00143   #else
00144     currentBounds_.getMinimum().setX(ui_->plot->axisScaleDiv(
00145       QwtPlot::xBottom)->lowerBound());
00146     currentBounds_.getMinimum().setY(ui_->plot->axisScaleDiv(
00147       QwtPlot::yLeft)->lowerBound());
00148     currentBounds_.getMaximum().setX(ui_->plot->axisScaleDiv(
00149       QwtPlot::xBottom)->upperBound());
00150     currentBounds_.getMaximum().setY(ui_->plot->axisScaleDiv(
00151       QwtPlot::yLeft)->upperBound());
00152   #endif
00153 
00154   connect(ui_->lineEditTitle, SIGNAL(textChanged(const QString&)), this,
00155     SLOT(lineEditTitleTextChanged(const QString&)));
00156   connect(ui_->lineEditTitle, SIGNAL(editingFinished()), this,
00157     SLOT(lineEditTitleEditingFinished()));
00158 
00159   connect(ui_->pushButtonRunPause, SIGNAL(clicked()), this,
00160     SLOT(pushButtonRunPauseClicked()));
00161   connect(ui_->pushButtonClear, SIGNAL(clicked()), this,
00162     SLOT(pushButtonClearClicked()));
00163   connect(ui_->pushButtonSetup, SIGNAL(clicked()), this,
00164     SLOT(pushButtonSetupClicked()));
00165   connect(ui_->pushButtonImportExport, SIGNAL(clicked()), this,
00166     SLOT(pushButtonImportExportClicked()));
00167   connect(ui_->pushButtonState, SIGNAL(clicked()), this,
00168     SLOT(pushButtonStateClicked()));
00169 
00170   connect(ui_->plot->axisWidget(QwtPlot::xBottom),
00171     SIGNAL(scaleDivChanged()), this, SLOT(plotXBottomScaleDivChanged()));
00172   connect(ui_->plot->axisWidget(QwtPlot::yLeft),
00173     SIGNAL(scaleDivChanged()), this, SLOT(plotYLeftScaleDivChanged()));
00174 
00175   connect(timer_, SIGNAL(timeout()), this, SLOT(timerTimeout()));
00176 
00177   ui_->plot->axisWidget(QwtPlot::yLeft)->installEventFilter(this);
00178   ui_->plot->axisWidget(QwtPlot::yRight)->installEventFilter(this);
00179 }
00180 
00181 PlotWidget::~PlotWidget() {
00182   delete ui_;
00183 }
00184 
00185 /*****************************************************************************/
00186 /* Accessors                                                                 */
00187 /*****************************************************************************/
00188 
00189 void PlotWidget::setConfig(PlotConfig* config) {
00190   if (config != config_) {
00191     if (config_) {
00192       disconnect(config_, SIGNAL(titleChanged(const QString&)), this,
00193         SLOT(configTitleChanged(const QString&)));
00194       disconnect(config_, SIGNAL(curveAdded(size_t)), this,
00195         SLOT(configCurveAdded(size_t)));
00196       disconnect(config_, SIGNAL(curveRemoved(size_t)), this,
00197         SLOT(configCurveRemoved(size_t)));
00198       disconnect(config_, SIGNAL(curvesCleared()), this,
00199         SLOT(configCurvesCleared()));
00200       disconnect(config_, SIGNAL(curveConfigChanged(size_t)), this,
00201         SLOT(configCurveConfigChanged(size_t)));
00202       disconnect(config_->getAxesConfig()->getAxisConfig(PlotAxesConfig::X),
00203         SIGNAL(changed()), this, SLOT(configXAxisConfigChanged()));
00204       disconnect(config_->getAxesConfig()->getAxisConfig(PlotAxesConfig::Y),
00205         SIGNAL(changed()), this, SLOT(configYAxisConfigChanged()));
00206       disconnect(config_->getLegendConfig(), SIGNAL(changed()), this,
00207         SLOT(configLegendConfigChanged()));
00208       disconnect(config_, SIGNAL(plotRateChanged(double)), this,
00209         SLOT(configPlotRateChanged(double)));
00210 
00211       configCurvesCleared();
00212     }
00213 
00214     config_ = config;
00215 
00216     if (config) {
00217       connect(config, SIGNAL(titleChanged(const QString&)), this,
00218         SLOT(configTitleChanged(const QString&)));
00219       connect(config, SIGNAL(curveAdded(size_t)), this,
00220         SLOT(configCurveAdded(size_t)));
00221       connect(config, SIGNAL(curveRemoved(size_t)), this,
00222         SLOT(configCurveRemoved(size_t)));
00223       connect(config, SIGNAL(curvesCleared()), this,
00224         SLOT(configCurvesCleared()));
00225       connect(config, SIGNAL(curveConfigChanged(size_t)), this,
00226         SLOT(configCurveConfigChanged(size_t)));
00227       connect(config->getAxesConfig()->getAxisConfig(PlotAxesConfig::X),
00228         SIGNAL(changed()), this, SLOT(configXAxisConfigChanged()));
00229       connect(config->getAxesConfig()->getAxisConfig(PlotAxesConfig::Y),
00230         SIGNAL(changed()), this, SLOT(configYAxisConfigChanged()));
00231       connect(config->getLegendConfig(), SIGNAL(changed()), this,
00232         SLOT(configLegendConfigChanged()));
00233       connect(config, SIGNAL(plotRateChanged(double)), this,
00234         SLOT(configPlotRateChanged(double)));
00235 
00236       configTitleChanged(config->getTitle());
00237       configPlotRateChanged(config->getPlotRate());
00238       configXAxisConfigChanged();
00239       configYAxisConfigChanged();
00240       configLegendConfigChanged();
00241 
00242       for (size_t index = 0; index < config->getNumCurves(); ++index)
00243         configCurveAdded(index);
00244     }
00245   }
00246 }
00247 
00248 PlotConfig* PlotWidget::getConfig() const {
00249   return config_;
00250 }
00251 
00252 void PlotWidget::setBroker(MessageBroker* broker) {
00253   if (broker != broker_) {
00254     broker_ = broker;
00255 
00256     for (size_t index = 0; index < curves_.count(); ++index)
00257       curves_[index]->setBroker(broker);
00258   }
00259 }
00260 
00261 MessageBroker* PlotWidget::getBroker() const {
00262   return broker_;
00263 }
00264 
00265 PlotCursor* PlotWidget::getCursor() const {
00266   return cursor_;
00267 }
00268 
00269 BoundingRectangle PlotWidget::getPreferredScale() const {
00270   BoundingRectangle bounds;
00271 
00272   for (size_t index = 0; index < curves_.count(); ++index)
00273     bounds += curves_[index]->getPreferredScale();
00274 
00275   return bounds;
00276 }
00277 
00278 void PlotWidget::setCurrentScale(const BoundingRectangle& bounds) {
00279   if (bounds != currentBounds_) {
00280     if (bounds.getMaximum().x() == bounds.getMinimum().x())
00281       ui_->plot->setAxisScale(QwtPlot::xBottom, bounds.getMinimum().x() - 0.1,
00282                               bounds.getMaximum().x() + 0.1);
00283     else if (bounds.getMaximum().x() > bounds.getMinimum().x())
00284       ui_->plot->setAxisScale(QwtPlot::xBottom, bounds.getMinimum().x(),
00285         bounds.getMaximum().x());
00286     if (bounds.getMaximum().y() == bounds.getMinimum().y())
00287       ui_->plot->setAxisScale(QwtPlot::yLeft, bounds.getMinimum().y() - 0.1,
00288                               bounds.getMaximum().y() + 0.1);
00289     else if (bounds.getMaximum().y() > bounds.getMinimum().y())
00290       ui_->plot->setAxisScale(QwtPlot::yLeft, bounds.getMinimum().y(),
00291         bounds.getMaximum().y());
00292 
00293     rescale_ = false;
00294 
00295     forceReplot();
00296   }
00297 }
00298 
00299 const BoundingRectangle& PlotWidget::getCurrentScale() const {
00300   return currentBounds_;
00301 }
00302 
00303 bool PlotWidget::isPaused() const {
00304   return paused_;
00305 }
00306 
00307 bool PlotWidget::isReplotRequested() const {
00308   return replot_;
00309 }
00310 
00311 void PlotWidget::setState(State state) {
00312   if ((state != state_) && canChangeState()) {
00313     state_ = state;
00314 
00315     if (state == Maximized)
00316       ui_->pushButtonState->setIcon(maximizedIcon_);
00317     else
00318       ui_->pushButtonState->setIcon(normalIcon_);
00319 
00320     emit stateChanged(state);
00321   }
00322 }
00323 
00324 PlotWidget::State PlotWidget::getState() const {
00325   return state_;
00326 }
00327 
00328 void PlotWidget::setCanChangeState(bool can) {
00329   ui_->pushButtonState->setEnabled(can);
00330 }
00331 
00332 bool PlotWidget::canChangeState() const {
00333   return ui_->pushButtonState->isEnabled();
00334 }
00335 
00336 /*****************************************************************************/
00337 /* Methods                                                                   */
00338 /*****************************************************************************/
00339 
00340 void PlotWidget::run() {
00341   if (paused_) {
00342     paused_ = false;
00343 
00344     for (size_t index = 0; index < curves_.count(); ++index)
00345       curves_[index]->run();
00346 
00347     ui_->pushButtonRunPause->setIcon(pauseIcon_);
00348 
00349     emit pausedChanged(false);
00350   }
00351 }
00352 
00353 void PlotWidget::pause() {
00354   if (!paused_) {
00355     for (size_t index = 0; index < curves_.count(); ++index)
00356       curves_[index]->pause();
00357 
00358     paused_ = true;
00359 
00360     ui_->pushButtonRunPause->setIcon(runIcon_);
00361 
00362     emit pausedChanged(true);
00363   }
00364 }
00365 
00366 void PlotWidget::clear() {
00367   for (size_t index = 0; index < curves_.count(); ++index)
00368     curves_[index]->clear();
00369 
00370   forceReplot();
00371 
00372   emit cleared();
00373 }
00374 
00375 void PlotWidget::requestReplot() {
00376   replot_ = true;
00377 }
00378 
00379 void PlotWidget::forceReplot() {
00380   BoundingRectangle preferredBounds = getPreferredScale();
00381 
00382   if (rescale_) {
00383     emit preferredScaleChanged(preferredBounds);
00384 
00385     rescale_ = false;
00386   }
00387 
00388   zoomer_->setZoomBase(preferredBounds.getRectangle());
00389 
00390   ui_->plot->replot();
00391 
00392   replot_ = false;
00393 }
00394 
00395 void PlotWidget::renderToPixmap(QPixmap& pixmap, const QRectF& bounds) {
00396   QRectF plotBounds = bounds;
00397 
00398   if (plotBounds.isEmpty())
00399     plotBounds = QRectF(0, 0, pixmap.width(), pixmap.height());
00400 
00401   QwtPlotRenderer renderer;
00402 
00403   renderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground, true);
00404   renderer.setDiscardFlag(QwtPlotRenderer::DiscardCanvasBackground, true);
00405 
00406   QPainter painter(&pixmap);
00407   size_t textHeight = 0;
00408 
00409   if (config_) {
00410     textHeight = painter.fontMetrics().boundingRect(config_->
00411       getTitle()).height();
00412 
00413     painter.drawText(QRectF(plotBounds.x(), plotBounds.y(),
00414       plotBounds.width(), textHeight), Qt::AlignHCenter |
00415       Qt::AlignVCenter, config_->getTitle());
00416   }
00417 
00418   renderer.render(ui_->plot, &painter, QRectF(plotBounds.x(),
00419     plotBounds.y()+textHeight+10, plotBounds.width(), plotBounds.
00420     height()-textHeight-10));
00421 }
00422 
00423 void PlotWidget::writeFormattedCurveData(QList<QStringList>& formattedData) {
00424   formattedData.clear();
00425 
00426   for (size_t index = 0; index < curves_.count(); ++index) {
00427     QStringList formattedX, formattedY;
00428 
00429     curves_[index]->getData()->writeFormatted(formattedX, formattedY);
00430 
00431     formattedData.append(formattedX);
00432     formattedData.append(formattedY);
00433   }
00434 }
00435 
00436 void PlotWidget::writeFormattedCurveAxisTitles(QStringList&
00437     formattedAxisTitles) {
00438   formattedAxisTitles.clear();
00439 
00440   for (size_t index = 0; index < curves_.count(); ++index) {
00441     CurveAxisConfig* xAxisConfig = curves_[index]->getConfig()->
00442       getAxisConfig(CurveConfig::X);
00443     CurveAxisConfig* yAxisConfig = curves_[index]->getConfig()->
00444       getAxisConfig(CurveConfig::Y);
00445 
00446     QString xAxisTitle = xAxisConfig->getTopic();
00447     QString yAxisTitle = yAxisConfig->getTopic();
00448 
00449     if (xAxisConfig->getFieldType() == CurveAxisConfig::MessageData)
00450       xAxisTitle += "/"+xAxisConfig->getField();
00451     else
00452       xAxisTitle += "/recceipt_time";
00453 
00454     if (yAxisConfig->getFieldType() == CurveAxisConfig::MessageData)
00455       yAxisTitle += "/"+yAxisConfig->getField();
00456     else
00457       yAxisTitle += "/recceipt_time";
00458 
00459     formattedAxisTitles.append(xAxisTitle);
00460     formattedAxisTitles.append(yAxisTitle);
00461   }
00462 }
00463 
00464 void PlotWidget::saveToImageFile(const QString& fileName) {
00465   QPixmap pixmap(1280, 1024);
00466 
00467   pixmap.fill(Qt::transparent);
00468   renderToPixmap(pixmap);
00469 
00470   pixmap.save(fileName, "PNG");
00471 }
00472 
00473 void PlotWidget::saveToTextFile(const QString& fileName) {
00474   QFile file(fileName);
00475 
00476   if (file.open(QIODevice::WriteOnly)) {
00477     QStringList formattedAxisTitles;
00478     QList<QStringList> formattedData;
00479 
00480     writeFormattedCurveAxisTitles(formattedAxisTitles);
00481     writeFormattedCurveData(formattedData);
00482 
00483     QTextStream stream(&file);
00484 
00485     stream << "# " << formattedAxisTitles.join(", ") << "\n";
00486 
00487     size_t row = 0;
00488 
00489     while (true) {
00490       QStringList dataLineParts;
00491       bool finished = true;
00492 
00493       for (size_t column = 0; column < formattedData.count(); ++column) {
00494         if (row < formattedData[column].count()) {
00495           dataLineParts.append(formattedData[column][row]);
00496           finished &= false;
00497         }
00498         else
00499           dataLineParts.append(QString());
00500       }
00501 
00502       if (!finished) {
00503         stream << dataLineParts.join(", ") << "\n";
00504         row++;
00505       }
00506       else
00507         break;
00508     }
00509   }
00510 }
00511 
00512 void PlotWidget::dragEnterEvent(QDragEnterEvent* event) {
00513   if (event->mimeData()->hasFormat(CurveConfig::MimeType) &&
00514       (event->source() != legend_) && config_)
00515     event->acceptProposedAction();
00516   else
00517     event->ignore();
00518 }
00519 
00520 void PlotWidget::dropEvent(QDropEvent* event) {
00521   if (event->mimeData()->hasFormat(CurveConfig::MimeType) &&
00522       (event->source() != legend_) && config_) {
00523     QByteArray data = event->mimeData()->data(CurveConfig::MimeType);
00524     QDataStream stream(&data, QIODevice::ReadOnly);
00525 
00526     CurveConfig* curveConfig = config_->addCurve();
00527     stream >> *curveConfig;
00528 
00529     while (config_->findCurves(curveConfig->getTitle()).count() > 1)
00530       curveConfig->setTitle("Copy of "+curveConfig->getTitle());
00531 
00532     event->acceptProposedAction();
00533   }
00534   else
00535     event->ignore();
00536 }
00537 
00538 bool PlotWidget::eventFilter(QObject* object, QEvent* event) {
00539   if ((object == ui_->plot->axisWidget(QwtPlot::yLeft)) &&
00540       (event->type() == QEvent::Resize)) {
00541     ui_->horizontalSpacerLeft->changeSize(
00542       ui_->plot->axisWidget(QwtPlot::yLeft)->width(), 20);
00543     layout()->update();
00544   }
00545   else if ((object == ui_->plot->axisWidget(QwtPlot::yRight)) &&
00546       (event->type() == QEvent::Resize)) {
00547     ui_->horizontalSpacerRight->changeSize(
00548       ui_->plot->axisWidget(QwtPlot::yRight)->width()-5, 20);
00549     layout()->update();
00550   }
00551 
00552   return false;
00553 }
00554 
00555 void PlotWidget::updateAxisTitle(PlotAxesConfig::Axis axis) {
00556   QwtPlot::Axis plotAxis = (axis == PlotAxesConfig::Y) ?
00557     QwtPlot::yLeft : QwtPlot::xBottom;
00558   CurveConfig::Axis curveAxis = (axis == PlotAxesConfig::Y) ?
00559     CurveConfig::Y : CurveConfig::X;
00560 
00561   PlotAxisConfig* plotAxisConfig = config_->getAxesConfig()->
00562     getAxisConfig(axis);
00563 
00564   if (plotAxisConfig->isTitleVisible()) {
00565     if (plotAxisConfig->getTitleType() == PlotAxisConfig::AutoTitle) {
00566       QStringList titleParts;
00567 
00568       for (size_t index = 0; index < config_->getNumCurves(); ++index) {
00569         CurveAxisConfig* curveAxisConfig = config_->getCurveConfig(index)->
00570           getAxisConfig(curveAxis);
00571 
00572         QString titlePart = curveAxisConfig->getTopic();
00573         if (curveAxisConfig->getFieldType() == CurveAxisConfig::MessageData)
00574           titlePart += "/"+curveAxisConfig->getField();
00575         else
00576           titlePart += "/receipt_time";
00577 
00578         if (!titleParts.contains(titlePart))
00579           titleParts.append(titlePart);
00580       }
00581 
00582       ui_->plot->setAxisTitle(plotAxis, QwtText(titleParts.join(", ")));
00583     }
00584     else
00585       ui_->plot->setAxisTitle(plotAxis, QwtText(plotAxisConfig->
00586         getCustomTitle()));
00587   }
00588   else
00589     ui_->plot->setAxisTitle(plotAxis, QwtText());
00590 }
00591 
00592 /*****************************************************************************/
00593 /* Slots                                                                     */
00594 /*****************************************************************************/
00595 
00596 void PlotWidget::timerTimeout() {
00597   if (replot_)
00598     forceReplot();
00599 }
00600 
00601 void PlotWidget::configTitleChanged(const QString& title) {
00602   ui_->lineEditTitle->setText(config_->getTitle());
00603 }
00604 
00605 void PlotWidget::configCurveAdded(size_t index) {
00606   PlotCurve* curve = new PlotCurve(this);
00607 
00608   curve->attach(ui_->plot);
00609   curve->setConfig(config_->getCurveConfig(index));
00610   curve->setBroker(broker_);
00611 
00612   connect(curve, SIGNAL(replotRequested()), this,
00613     SLOT(curveReplotRequested()));
00614 
00615   curves_.insert(index, curve);
00616 
00617   configXAxisConfigChanged();
00618   configYAxisConfigChanged();
00619 
00620   forceReplot();
00621 }
00622 
00623 void PlotWidget::configCurveRemoved(size_t index) {
00624   curves_[index]->detach();
00625 
00626   delete curves_[index];
00627 
00628   curves_.remove(index);
00629 
00630   configXAxisConfigChanged();
00631   configYAxisConfigChanged();
00632 
00633   forceReplot();
00634 }
00635 
00636 void PlotWidget::configCurvesCleared() {
00637   for (size_t index = 0; index < curves_.count(); ++index) {
00638     curves_[index]->detach();
00639 
00640     delete curves_[index];
00641   }
00642 
00643   curves_.clear();
00644 
00645   configXAxisConfigChanged();
00646   configYAxisConfigChanged();
00647 
00648   forceReplot();
00649 }
00650 
00651 void PlotWidget::configCurveConfigChanged(size_t index) {
00652   configXAxisConfigChanged();
00653   configYAxisConfigChanged();
00654 }
00655 
00656 void PlotWidget::configXAxisConfigChanged() {
00657   updateAxisTitle(PlotAxesConfig::X);
00658 }
00659 
00660 void PlotWidget::configYAxisConfigChanged() {
00661   updateAxisTitle(PlotAxesConfig::Y);
00662 }
00663 
00664 void PlotWidget::configLegendConfigChanged() {
00665   if (!legend_ && config_->getLegendConfig()->isVisible()) {
00666     legend_ = new PlotLegend(this);
00667     ui_->plot->insertLegend(legend_, QwtPlot::TopLegend);
00668   }
00669   else if (legend_ && !config_->getLegendConfig()->isVisible()) {
00670     ui_->plot->insertLegend(0);
00671     legend_ = 0;
00672   }
00673 }
00674 
00675 void PlotWidget::configPlotRateChanged(double rate) {
00676   timer_->setInterval(1e3/rate);
00677 }
00678 
00679 void PlotWidget::curveReplotRequested() {
00680   rescale_ = true;
00681 
00682   requestReplot();
00683 }
00684 
00685 void PlotWidget::lineEditTitleTextChanged(const QString& text) {
00686   QFontMetrics fontMetrics(ui_->lineEditTitle->font());
00687 
00688   ui_->lineEditTitle->setMinimumWidth(
00689     std::max(100, fontMetrics.width(text)+10));
00690 }
00691 
00692 void PlotWidget::lineEditTitleEditingFinished() {
00693   if (config_)
00694     config_->setTitle(ui_->lineEditTitle->text());
00695 }
00696 
00697 void PlotWidget::pushButtonRunPauseClicked() {
00698   if (paused_)
00699     run();
00700   else
00701     pause();
00702 }
00703 
00704 void PlotWidget::pushButtonClearClicked() {
00705   clear();
00706 }
00707 
00708 void PlotWidget::pushButtonSetupClicked() {
00709   if (config_) {
00710     PlotConfigDialog dialog(this);
00711 
00712     dialog.setWindowTitle(config_->getTitle().isEmpty() ?
00713       "Configure Plot" :
00714       "Configure \""+config_->getTitle()+"\"");
00715     dialog.getWidget()->setConfig(*config_);
00716 
00717     if (dialog.exec() == QDialog::Accepted)
00718       *config_ = dialog.getWidget()->getConfig();
00719   }
00720 }
00721 
00722 void PlotWidget::pushButtonImportExportClicked() {
00723   menuImportExport_->popup(QCursor::pos());
00724 }
00725 
00726 void PlotWidget::pushButtonStateClicked() {
00727   if (state_ == Maximized)
00728     setState(Normal);
00729   else
00730     setState(Maximized);
00731 }
00732 
00733 void PlotWidget::menuExportImageFileTriggered() {
00734   QFileDialog dialog(this, "Save Image File", QDir::homePath(),
00735     "Portable Network Graphics (*.png)");
00736 
00737   dialog.setAcceptMode(QFileDialog::AcceptSave);
00738   dialog.setFileMode(QFileDialog::AnyFile);
00739   dialog.selectFile("rqt_multiplot.png");
00740 
00741   if (dialog.exec() == QDialog::Accepted)
00742     saveToImageFile(dialog.selectedFiles().first());
00743 }
00744 
00745 void PlotWidget::menuExportTextFileTriggered() {
00746   QFileDialog dialog(this, "Save Text File", QDir::homePath(),
00747     "Text file (*.txt)");
00748 
00749   dialog.setAcceptMode(QFileDialog::AcceptSave);
00750   dialog.setFileMode(QFileDialog::AnyFile);
00751   dialog.selectFile("rqt_multiplot.txt");
00752 
00753   if (dialog.exec() == QDialog::Accepted)
00754     saveToTextFile(dialog.selectedFiles().first());
00755 }
00756 
00757 void PlotWidget::plotXBottomScaleDivChanged() {
00758   #if QWT_VERSION >= 0x060100
00759     const QwtScaleDiv& scale = ui_->plot->axisScaleDiv(QwtPlot::xBottom);
00760   #else
00761     const QwtScaleDiv& scale = *ui_->plot->axisScaleDiv(QwtPlot::xBottom);
00762   #endif
00763 
00764   ui_->plot->setAxisScaleDiv(QwtPlot::xTop, scale);
00765 
00766   currentBounds_.getMinimum().setX(scale.lowerBound());
00767   currentBounds_.getMaximum().setX(scale.upperBound());
00768 
00769   emit currentScaleChanged(currentBounds_);
00770 }
00771 
00772 void PlotWidget::plotYLeftScaleDivChanged() {
00773   #if QWT_VERSION >= 0x060100
00774     const QwtScaleDiv& scale = ui_->plot->axisScaleDiv(QwtPlot::yLeft);
00775   #else
00776     const QwtScaleDiv& scale = *ui_->plot->axisScaleDiv(QwtPlot::yLeft);
00777   #endif
00778 
00779   ui_->plot->setAxisScaleDiv(QwtPlot::yRight, scale);
00780 
00781   currentBounds_.getMinimum().setY(scale.lowerBound());
00782   currentBounds_.getMaximum().setY(scale.upperBound());
00783 
00784   emit currentScaleChanged(currentBounds_);
00785 }
00786 
00787 }


rqt_multiplot
Author(s): Ralf Kaestner
autogenerated on Thu Jun 6 2019 21:49:11