234 lines
6.9 KiB
C++
234 lines
6.9 KiB
C++
|
/*
|
||
|
* Copyright (C) 2012 Open Source Robotics Foundation
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "gazebo/gui/Diagnostics.hh"
|
||
|
#include "gazebo/gui/DiagnosticsPrivate.hh"
|
||
|
#include "gazebo/gui/IncrementalPlot.hh"
|
||
|
#include "gazebo/transport/Node.hh"
|
||
|
#include "gazebo/transport/Publisher.hh"
|
||
|
#include "gazebo/transport/TransportIface.hh"
|
||
|
|
||
|
using namespace gazebo;
|
||
|
using namespace gui;
|
||
|
|
||
|
// A special list widget that allows dragging of items from it to a
|
||
|
// plot
|
||
|
class DragableListWidget : public QListWidget
|
||
|
{
|
||
|
public: DragableListWidget(QWidget *_parent)
|
||
|
: QListWidget(_parent)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
protected: virtual void startDrag(Qt::DropActions /*_supportedActions*/)
|
||
|
{
|
||
|
QListWidgetItem *currItem = this->currentItem();
|
||
|
QMimeData *currMimeData = new QMimeData;
|
||
|
QByteArray ba;
|
||
|
ba = currItem->text().toLatin1().data();
|
||
|
currMimeData->setData("application/x-item", ba);
|
||
|
QDrag *drag = new QDrag(this);
|
||
|
drag->setMimeData(currMimeData);
|
||
|
drag->exec(Qt::LinkAction);
|
||
|
}
|
||
|
|
||
|
protected: virtual Qt::DropActions supportedDropActions()
|
||
|
{
|
||
|
return Qt::LinkAction;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Diagnostics::Diagnostics(QWidget *_parent)
|
||
|
: QDialog(_parent),
|
||
|
dataPtr(new DiagnosticsPrivate())
|
||
|
{
|
||
|
this->dataPtr->paused = false;
|
||
|
this->setWindowIcon(QIcon(":/images/gazebo.svg"));
|
||
|
this->setWindowTitle("Gazebo: Diagnostics");
|
||
|
this->setObjectName("diagnosticsPlot");
|
||
|
this->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
|
||
|
Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint);
|
||
|
|
||
|
this->dataPtr->plotLayout = new QVBoxLayout;
|
||
|
|
||
|
QScrollArea *plotScrollArea = new QScrollArea(this);
|
||
|
plotScrollArea->setLineWidth(0);
|
||
|
plotScrollArea->setFrameShape(QFrame::NoFrame);
|
||
|
plotScrollArea->setFrameShadow(QFrame::Plain);
|
||
|
plotScrollArea->setSizePolicy(QSizePolicy::Minimum,
|
||
|
QSizePolicy::Minimum);
|
||
|
|
||
|
plotScrollArea->setWidgetResizable(true);
|
||
|
plotScrollArea->viewport()->installEventFilter(this);
|
||
|
|
||
|
QFrame *plotFrame = new QFrame(plotScrollArea);
|
||
|
plotFrame->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||
|
plotFrame->setLayout(this->dataPtr->plotLayout);
|
||
|
|
||
|
plotScrollArea->setWidget(plotFrame);
|
||
|
|
||
|
|
||
|
IncrementalPlot *plot = new IncrementalPlot(this);
|
||
|
this->dataPtr->plots.push_back(plot);
|
||
|
this->dataPtr->plotLayout->addWidget(plot);
|
||
|
|
||
|
this->dataPtr->labelList = new DragableListWidget(this);
|
||
|
this->dataPtr->labelList->setDragEnabled(true);
|
||
|
this->dataPtr->labelList->setDragDropMode(QAbstractItemView::DragOnly);
|
||
|
QListWidgetItem *item = new QListWidgetItem("Real Time Factor");
|
||
|
item->setToolTip(tr("Drag onto graph to plot"));
|
||
|
this->dataPtr->labelList->addItem(item);
|
||
|
|
||
|
QPushButton *addPlotButton = new QPushButton("Add");
|
||
|
connect(addPlotButton, SIGNAL(clicked()), this, SLOT(OnAddPlot()));
|
||
|
|
||
|
QCheckBox *pauseCheck = new QCheckBox;
|
||
|
pauseCheck->setChecked(this->dataPtr->paused);
|
||
|
connect(pauseCheck, SIGNAL(clicked(bool)), this, SLOT(OnPause(bool)));
|
||
|
|
||
|
QHBoxLayout *pauseLayout = new QHBoxLayout;
|
||
|
pauseLayout->addWidget(pauseCheck);
|
||
|
pauseLayout->addWidget(new QLabel("Pause"));
|
||
|
pauseLayout->addWidget(addPlotButton);
|
||
|
pauseLayout->addStretch(1);
|
||
|
|
||
|
QVBoxLayout *leftLayout = new QVBoxLayout;
|
||
|
leftLayout->addWidget(this->dataPtr->labelList);
|
||
|
leftLayout->addLayout(pauseLayout);
|
||
|
|
||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||
|
mainLayout->addLayout(leftLayout);
|
||
|
mainLayout->addWidget(plotScrollArea, 2);
|
||
|
|
||
|
this->setLayout(mainLayout);
|
||
|
this->setSizeGripEnabled(true);
|
||
|
|
||
|
this->dataPtr->node = transport::NodePtr(new transport::Node());
|
||
|
this->dataPtr->node->Init();
|
||
|
this->dataPtr->sub = this->dataPtr->node->Subscribe("~/diagnostics",
|
||
|
&Diagnostics::OnMsg, this);
|
||
|
|
||
|
QTimer *displayTimer = new QTimer(this);
|
||
|
connect(displayTimer, SIGNAL(timeout()), this, SLOT(Update()));
|
||
|
displayTimer->start(60);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Diagnostics::~Diagnostics()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void Diagnostics::Update()
|
||
|
{
|
||
|
std::lock_guard<std::mutex> lock(this->dataPtr->mutex);
|
||
|
|
||
|
// Update all the plots
|
||
|
for (auto &plot : this->dataPtr->plots)
|
||
|
{
|
||
|
plot->Update();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void Diagnostics::OnMsg(ConstDiagnosticsPtr &_msg)
|
||
|
{
|
||
|
// Make sure plotting is not paused.
|
||
|
if (this->dataPtr->paused)
|
||
|
return;
|
||
|
|
||
|
// Make sure there is timing information
|
||
|
if (_msg->time_size() == 0)
|
||
|
return;
|
||
|
|
||
|
std::lock_guard<std::mutex> lock(this->dataPtr->mutex);
|
||
|
|
||
|
common::Time wallTime, elapsedTime;
|
||
|
|
||
|
wallTime = msgs::Convert(_msg->real_time());
|
||
|
|
||
|
// Add real-time factor if it has been requested.
|
||
|
for (auto &plot : this->dataPtr->plots)
|
||
|
{
|
||
|
if (plot->HasCurve(QString("Real Time Factor")))
|
||
|
{
|
||
|
plot->Add(QString("Real Time Factor"),
|
||
|
QPointF(wallTime.Double(), _msg->real_time_factor()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Process each time point
|
||
|
for (int i = 0; i < _msg->time_size(); ++i)
|
||
|
{
|
||
|
QString qstr = QString::fromStdString(_msg->time(i).name());
|
||
|
|
||
|
// Add the time label to the list if it's not already there.
|
||
|
QList<QListWidgetItem*> items = this->dataPtr->labelList->findItems(qstr,
|
||
|
Qt::MatchExactly);
|
||
|
|
||
|
if (items.size() == 0)
|
||
|
{
|
||
|
QListWidgetItem *item = new QListWidgetItem(qstr);
|
||
|
item->setToolTip(tr("Drag onto graph to plot"));
|
||
|
this->dataPtr->labelList->addItem(item);
|
||
|
}
|
||
|
|
||
|
QString labelStr(_msg->time(i).name().c_str());
|
||
|
|
||
|
// Check to see if the data belongs in a plot, and add it.
|
||
|
for (auto &plot : this->dataPtr->plots)
|
||
|
{
|
||
|
if (plot->HasCurve(labelStr))
|
||
|
{
|
||
|
elapsedTime = msgs::Convert(_msg->time(i).elapsed());
|
||
|
|
||
|
double msTime = elapsedTime.Double() * 1e3;
|
||
|
QPointF pt(wallTime.Double(), msTime);
|
||
|
|
||
|
plot->Add(labelStr, pt);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void Diagnostics::OnPause(bool _value)
|
||
|
{
|
||
|
this->dataPtr->paused = _value;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void Diagnostics::OnAddPlot()
|
||
|
{
|
||
|
IncrementalPlot *plot = new IncrementalPlot(this);
|
||
|
this->dataPtr->plotLayout->addWidget(plot);
|
||
|
this->dataPtr->plots.push_back(plot);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
bool Diagnostics::eventFilter(QObject *o, QEvent *e)
|
||
|
{
|
||
|
if (e->type() == QEvent::Wheel)
|
||
|
{
|
||
|
e->ignore();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return QWidget::eventFilter(o, e);
|
||
|
}
|