PlotTableWidget.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 <QApplication>
00020 #include <QFile>
00021 #include <QTextStream>
00022 
00023 #include <rqt_multiplot/PlotCursor.h>
00024 #include <rqt_multiplot/PlotWidget.h>
00025 
00026 #include "rqt_multiplot/PlotTableWidget.h"
00027 
00028 namespace rqt_multiplot {
00029 
00030 /*****************************************************************************/
00031 /* Constructors and Destructor                                               */
00032 /*****************************************************************************/
00033 
00034 PlotTableWidget::PlotTableWidget(QWidget* parent) :
00035   QWidget(parent),
00036   layout_(new QGridLayout(this)),
00037   config_(0),
00038   registry_(new MessageSubscriberRegistry(this)),
00039   bagReader_(new BagReader(this)) {
00040   setLayout(layout_);
00041   setAutoFillBackground(true);
00042   
00043   layout_->setHorizontalSpacing(20);
00044   layout_->setVerticalSpacing(20);
00045   
00046   connect(bagReader_, SIGNAL(readingStarted()), this,
00047     SLOT(bagReaderReadingStarted()));
00048   connect(bagReader_, SIGNAL(readingProgressChanged(double)), this,
00049     SLOT(bagReaderReadingProgressChanged(double)));
00050   connect(bagReader_, SIGNAL(readingFinished()), this,
00051     SLOT(bagReaderReadingFinished()));
00052   connect(bagReader_, SIGNAL(readingFailed(const QString&)), this,
00053     SLOT(bagReaderReadingFailed(const QString&)));
00054 }
00055 
00056 PlotTableWidget::~PlotTableWidget() {
00057 }
00058 
00059 /*****************************************************************************/
00060 /* Accessors                                                                 */
00061 /*****************************************************************************/
00062 
00063 void PlotTableWidget::setConfig(PlotTableConfig* config) {
00064   if (config != config_) {
00065     if (config_) {
00066       disconnect(config_, SIGNAL(backgroundColorChanged(const QColor&)),
00067         this, SLOT(configBackgroundColorChanged(const QColor&)));
00068       disconnect(config_, SIGNAL(foregroundColorChanged(const QColor&)),
00069         this, SLOT(configForegroundColorChanged(const QColor&)));
00070       disconnect(config_, SIGNAL(numPlotsChanged(size_t, size_t)), this,
00071         SLOT(configNumPlotsChanged(size_t, size_t)));
00072       disconnect(config_, SIGNAL(linkScaleChanged(bool)), this,
00073         SLOT(configLinkScaleChanged(bool)));
00074       disconnect(config_, SIGNAL(trackPointsChanged(bool)), this,
00075         SLOT(configTrackPointsChanged(bool)));
00076     }
00077     
00078     config_ = config;
00079     
00080     if (config) {
00081       connect(config, SIGNAL(backgroundColorChanged(const QColor&)),
00082         this, SLOT(configBackgroundColorChanged(const QColor&)));
00083       connect(config, SIGNAL(foregroundColorChanged(const QColor&)),
00084         this, SLOT(configForegroundColorChanged(const QColor&)));
00085       connect(config, SIGNAL(numPlotsChanged(size_t, size_t)), this,
00086         SLOT(configNumPlotsChanged(size_t, size_t)));
00087       connect(config, SIGNAL(linkScaleChanged(bool)), this,
00088         SLOT(configLinkScaleChanged(bool)));
00089       connect(config, SIGNAL(trackPointsChanged(bool)), this,
00090         SLOT(configTrackPointsChanged(bool)));
00091       
00092       configBackgroundColorChanged(config->getBackgroundColor());
00093       configForegroundColorChanged(config->getForegroundColor());
00094       configNumPlotsChanged(config->getNumRows(), config->getNumColumns());
00095       configLinkScaleChanged(config->isScaleLinked());
00096       configTrackPointsChanged(config->arePointsTracked());
00097     }
00098   }
00099 }
00100 
00101 PlotTableConfig* PlotTableWidget::getConfig() const {
00102   return config_;
00103 }
00104 
00105 size_t PlotTableWidget::getNumRows() const {
00106   return plotWidgets_.count();
00107 }
00108 
00109 size_t PlotTableWidget::getNumColumns() const {
00110   if (!plotWidgets_.isEmpty())
00111     return plotWidgets_[0].count();
00112   else
00113     return 0;
00114 }
00115 
00116 PlotWidget* PlotTableWidget::getPlotWidget(size_t row, size_t column) const {
00117   return plotWidgets_[row][column];
00118 }
00119 
00120 MessageSubscriberRegistry* PlotTableWidget::getRegistry() const {
00121   return registry_;
00122 }
00123 
00124 BagReader* PlotTableWidget::getBagReader() const {
00125   return bagReader_;
00126 }
00127 
00128 /*****************************************************************************/
00129 /* Methods                                                                   */
00130 /*****************************************************************************/
00131 
00132 void PlotTableWidget::runPlots() {
00133   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00134     for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00135       plotWidgets_[row][column]->run();
00136 }
00137 
00138 void PlotTableWidget::pausePlots() {
00139   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00140     for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00141       plotWidgets_[row][column]->pause();
00142 }
00143 
00144 void PlotTableWidget::clearPlots() {
00145   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00146     for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00147       plotWidgets_[row][column]->clear();
00148 }
00149 
00150 void PlotTableWidget::requestReplot() {
00151   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00152     for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00153       plotWidgets_[row][column]->requestReplot();
00154 }
00155 
00156 void PlotTableWidget::forceReplot() {
00157   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00158     for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00159       plotWidgets_[row][column]->forceReplot();
00160 }
00161 
00162 void PlotTableWidget::renderToPixmap(QPixmap& pixmap) {
00163   size_t numRows = getNumRows();
00164   size_t numColumns = getNumColumns();
00165   
00166   if (numRows && numColumns) {
00167     double plotWidth = (pixmap.width()-20.0*(numColumns-1.0))/numColumns;
00168     double plotHeight = (pixmap.height()-20.0*(numRows-1.0))/numRows;
00169     
00170     double y = 0.0;
00171     for (size_t row = 0; row < plotWidgets_.count();
00172         ++row, y += plotHeight+20.0) {
00173       double x = 0.0;
00174       
00175       for (size_t column = 0; column < plotWidgets_[row].count();
00176           ++column, x += plotWidth+20.0)
00177         plotWidgets_[row][column]->renderToPixmap(pixmap,
00178           QRectF(x, y, plotWidth, plotHeight));
00179     }
00180   }
00181 }
00182 
00183 void PlotTableWidget::writeFormattedCurveAxisTitles(QStringList&
00184     formattedAxisTitles) {
00185   formattedAxisTitles.clear();
00186   
00187   for (size_t row = 0; row < plotWidgets_.count(); ++row) {
00188     for (size_t column = 0; column < plotWidgets_[row].count(); ++column) {
00189       QStringList formattedCurveAxisTitles;
00190       
00191       plotWidgets_[row][column]->writeFormattedCurveAxisTitles(
00192         formattedCurveAxisTitles);
00193       
00194       formattedAxisTitles.append(formattedCurveAxisTitles);
00195     }
00196   }
00197 }
00198 
00199 void PlotTableWidget::writeFormattedCurveData(QList<QStringList>&
00200     formattedData) {
00201   formattedData.clear();
00202   
00203   for (size_t row = 0; row < plotWidgets_.count(); ++row) {
00204     for (size_t column = 0; column < plotWidgets_[row].count(); ++column) {
00205       QList<QStringList> formattedCurveData;
00206       
00207       plotWidgets_[row][column]->writeFormattedCurveData(
00208         formattedCurveData);
00209       
00210       formattedData.append(formattedCurveData);
00211     }
00212   }
00213 }
00214 
00215 void PlotTableWidget::loadFromBagFile(const QString& fileName) {
00216   clearPlots();
00217   
00218   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00219     for (size_t column = 0; column < plotWidgets_[row].count(); ++column)
00220       plotWidgets_[row][column]->setBroker(bagReader_);
00221   
00222   runPlots();
00223     
00224   bagReader_->read(fileName);
00225 }
00226 
00227 void PlotTableWidget::saveToImageFile(const QString& fileName) {
00228   QPixmap pixmap(1280, 1024);
00229 
00230   pixmap.fill(Qt::transparent);  
00231   renderToPixmap(pixmap);
00232   
00233   pixmap.save(fileName, "PNG");
00234 }
00235 
00236 void PlotTableWidget::saveToTextFile(const QString& fileName) {
00237   QFile file(fileName);
00238   
00239   if (file.open(QIODevice::WriteOnly)) {
00240     QStringList formattedAxisTitles;
00241     QList<QStringList> formattedData;
00242     
00243     writeFormattedCurveAxisTitles(formattedAxisTitles);
00244     writeFormattedCurveData(formattedData);
00245   
00246     QTextStream stream(&file);
00247 
00248     stream << "# " << formattedAxisTitles.join(", ") << "\n";
00249     
00250     size_t row = 0;
00251     
00252     while (true) {
00253       QStringList dataLineParts;
00254       bool finished = true;
00255       
00256       for (size_t column = 0; column < formattedData.count(); ++column) {
00257         if (row < formattedData[column].count()) {
00258           dataLineParts.append(formattedData[column][row]);
00259           finished &= false;
00260         }
00261         else
00262           dataLineParts.append(QString());
00263       }
00264 
00265       if (!finished) {
00266         stream << dataLineParts.join(", ") << "\n";
00267         row++;
00268       }
00269       else
00270         break;
00271     }
00272   }
00273 }
00274 
00275 void PlotTableWidget::updatePlotScale(const BoundingRectangle& bounds,
00276     PlotWidget* excluded) {
00277   BoundingRectangle validBounds = bounds;
00278   
00279   if (!bounds.isValid()) {
00280     BoundingRectangle currentBounds;
00281     
00282     for (size_t row = 0; row < plotWidgets_.count(); ++row)
00283       for (size_t column = 0; column < plotWidgets_[row].count(); ++column)
00284         currentBounds += plotWidgets_[row][column]->getCurrentScale();
00285       
00286     if (bounds.getMaximum().x() <= bounds.getMinimum().x()) {
00287       validBounds.getMinimum().setX(currentBounds.getMinimum().x());
00288       validBounds.getMaximum().setX(currentBounds.getMaximum().x());
00289     }
00290     
00291     if (bounds.getMaximum().y() <= bounds.getMinimum().y()) {
00292       validBounds.getMinimum().setY(currentBounds.getMinimum().y());
00293       validBounds.getMaximum().setY(currentBounds.getMaximum().y());
00294     }  
00295   }
00296   
00297   for (size_t row = 0; row < plotWidgets_.count(); ++row) {
00298     for (size_t column = 0; column < plotWidgets_[row].count(); ++column) {
00299       if (excluded != plotWidgets_[row][column])
00300         plotWidgets_[row][column]->setCurrentScale(validBounds);
00301     }
00302   }
00303 }
00304 
00305 /*****************************************************************************/
00306 /* Slots                                                                     */
00307 /*****************************************************************************/
00308 
00309 void PlotTableWidget::configBackgroundColorChanged(const QColor& color) {
00310   QPalette currentPalette = palette();
00311   
00312   currentPalette.setColor(QPalette::Window, color);
00313   currentPalette.setColor(QPalette::Base, color);
00314   
00315   setPalette(currentPalette);
00316 
00317   forceReplot();
00318 }
00319 
00320 void PlotTableWidget::configForegroundColorChanged(const QColor& color) {
00321   QPalette currentPalette = palette();
00322   
00323   currentPalette.setColor(QPalette::WindowText, color);
00324   currentPalette.setColor(QPalette::Text, color);
00325   
00326   setPalette(currentPalette);
00327 }
00328 
00329 void PlotTableWidget::configNumPlotsChanged(size_t numRows, size_t
00330     numColumns) {
00331   size_t oldNumRows = plotWidgets_.count();
00332   size_t oldNumColumns = oldNumRows ? plotWidgets_[0].count() : 0;
00333   
00334   if (!numRows || !numColumns) {
00335     numRows = 0;
00336     numColumns = 0;
00337   }
00338   
00339   QVector<QVector<PlotWidget* > > plotWidgets(numRows);  
00340   QGridLayout* layout = new QGridLayout();
00341   
00342   layout->setHorizontalSpacing(20);
00343   layout->setVerticalSpacing(20);
00344   
00345   for (size_t row = 0; row < numRows; ++row) {
00346     plotWidgets[row].resize(numColumns);
00347     
00348     for (size_t column = 0; column < numColumns; ++column) {
00349       if ((row < oldNumRows) && (column < oldNumColumns))
00350         plotWidgets[row][column] = plotWidgets_[row][column];
00351       else {
00352         plotWidgets[row][column] = new PlotWidget(this);
00353         
00354         connect(plotWidgets[row][column], SIGNAL(preferredScaleChanged(
00355           const BoundingRectangle&)), this, SLOT(plotPreferredScaleChanged(
00356           const BoundingRectangle&)));
00357         connect(plotWidgets[row][column], SIGNAL(currentScaleChanged(
00358           const BoundingRectangle&)), this, SLOT(plotCurrentScaleChanged(
00359           const BoundingRectangle&)));
00360         connect(plotWidgets[row][column]->getCursor(), SIGNAL(
00361           activeChanged(bool)), this, SLOT(plotCursorActiveChanged(bool)));
00362         connect(plotWidgets[row][column]->getCursor(), SIGNAL(
00363           currentPositionChanged(const QPointF&)), this, SLOT(
00364           plotCursorCurrentPositionChanged(const QPointF&)));
00365         connect(plotWidgets[row][column], SIGNAL(pausedChanged(bool)),
00366           this, SLOT(plotPausedChanged(bool)));        
00367         connect(plotWidgets[row][column], SIGNAL(stateChanged(int)),
00368           this, SLOT(plotStateChanged(int)));        
00369       }
00370       
00371       plotWidgets[row][column]->setConfig(config_->getPlotConfig(
00372         row, column));
00373       plotWidgets[row][column]->setBroker(registry_);
00374       
00375       if (config_->isScaleLinked())
00376         plotWidgets[row][column]->setCurrentScale(plotWidgets[0][0]->
00377           getCurrentScale());
00378         
00379       plotWidgets[row][column]->getCursor()->setTrackPoints(
00380         config_->arePointsTracked());
00381       
00382       layout->addWidget(plotWidgets[row][column], row, column);
00383     }
00384   }
00385   
00386   if ((numRows == 1) && (numColumns == 1))
00387     plotWidgets[0][0]->setCanChangeState(false);
00388   else 
00389     plotWidgets[0][0]->setCanChangeState(true);
00390   
00391   for (size_t row = 0; row < oldNumRows; ++row)
00392     for (size_t column = 0; column < oldNumColumns; ++column)
00393       if ((row >= numRows) || (column >= numColumns))
00394         delete plotWidgets_[row][column];
00395   
00396   plotWidgets_ = plotWidgets;
00397   
00398   delete layout_;
00399   layout_ = layout;
00400   setLayout(layout);
00401   
00402   emit plotPausedChanged();
00403 }
00404 
00405 void PlotTableWidget::configLinkScaleChanged(bool link) {
00406   if (link) {
00407     BoundingRectangle bounds;
00408     
00409     for (size_t row = 0; row < plotWidgets_.count(); ++row)
00410       for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00411         bounds += plotWidgets_[row][column]->getPreferredScale();
00412         
00413     updatePlotScale(bounds);
00414   }
00415 }
00416 
00417 void PlotTableWidget::configTrackPointsChanged(bool track) {
00418   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00419     for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00420       plotWidgets_[row][column]->getCursor()->setTrackPoints(track);
00421 }
00422 
00423 void PlotTableWidget::bagReaderReadingStarted() {
00424   emit jobStarted("Reading bag from [file://"+
00425     bagReader_->getFileName()+"]...");
00426 }
00427 
00428 void PlotTableWidget::bagReaderReadingProgressChanged(double progress) {
00429   emit jobProgressChanged(progress);
00430 }
00431 
00432 void PlotTableWidget::bagReaderReadingFinished() {
00433   pausePlots();
00434   
00435   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00436     for (size_t column = 0; column < plotWidgets_[row].count(); ++column)
00437       plotWidgets_[row][column]->setBroker(registry_);
00438     
00439   emit jobFinished("Read bag from [file://"+
00440     bagReader_->getFileName()+"]");
00441 }
00442 
00443 void PlotTableWidget::bagReaderReadingFailed(const QString& error) {
00444   pausePlots();
00445   
00446   for (size_t row = 0; row < plotWidgets_.count(); ++row)
00447     for (size_t column = 0; column < plotWidgets_[row].count(); ++column)
00448       plotWidgets_[row][column]->setBroker(registry_);
00449     
00450   emit jobFailed("Failed to read bag from [file://"+
00451     bagReader_->getFileName()+"]");
00452 }
00453 
00454 void PlotTableWidget::plotPreferredScaleChanged(const BoundingRectangle&
00455     bounds) {
00456   if (config_) {
00457     if (config_->isScaleLinked()) {
00458       BoundingRectangle bounds;
00459       
00460       for (size_t row = 0; row < plotWidgets_.count(); ++row)
00461         for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00462           bounds += plotWidgets_[row][column]->getPreferredScale();
00463 
00464       updatePlotScale(bounds);
00465     }
00466     else
00467       static_cast<PlotWidget*>(sender())->setCurrentScale(bounds);
00468   }
00469 }
00470 
00471 void PlotTableWidget::plotCurrentScaleChanged(const BoundingRectangle&
00472     bounds) {
00473   if (config_ && config_->isScaleLinked())
00474     updatePlotScale(bounds, static_cast<PlotWidget*>(sender()));
00475 }
00476 
00477 void PlotTableWidget::plotCursorActiveChanged(bool active) {
00478   if (config_ && config_->isCursorLinked()) {
00479     for (size_t row = 0; row < plotWidgets_.count(); ++row)
00480       for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00481         if (sender() != plotWidgets_[row][column])
00482           plotWidgets_[row][column]->getCursor()->setActive(active);
00483   }
00484 }
00485 
00486 void PlotTableWidget::plotCursorCurrentPositionChanged(const QPointF&
00487     position) {
00488   if (config_ && config_->isCursorLinked()) {
00489     for (size_t row = 0; row < plotWidgets_.count(); ++row)
00490       for (size_t column = 0; column < plotWidgets_[row].count(); ++ column)
00491         if (sender() != plotWidgets_[row][column])
00492           plotWidgets_[row][column]->getCursor()->setCurrentPosition(
00493             position);
00494   }
00495 }
00496 
00497 void PlotTableWidget::plotPausedChanged(bool paused) {
00498   emit plotPausedChanged();
00499 }
00500 
00501 void PlotTableWidget::plotStateChanged(int state) {
00502   for (size_t row = 0; row < plotWidgets_.count(); ++row) {
00503     for (size_t column = 0; column < plotWidgets_[row].count(); ++ column) {
00504       if (state == PlotWidget::Maximized) {
00505         if (sender() != plotWidgets_[row][column])
00506           plotWidgets_[row][column]->hide();
00507       }
00508       else if (state == PlotWidget::Normal)
00509         plotWidgets_[row][column]->show();
00510     }
00511   }
00512 }
00513 
00514 }


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