1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-20 10:54:14 +01:00

LP-517 gcs: fix uavtalk logging UI state handling

fix issues affecting the UI
fix LP-271 : it was not possible to log after a replay
remove the possibility to log while replaying
more translation aware
This commit is contained in:
Philippe Renon 2017-05-11 02:53:30 +02:00
parent 5220cb0d6f
commit 3b8bfabf28
7 changed files with 185 additions and 107 deletions

View File

@ -34,6 +34,7 @@ LogFile::LogFile(QObject *parent) : QIODevice(parent),
m_lastPlayed(0),
m_timeOffset(0),
m_playbackSpeed(1.0),
paused(false),
m_useProvidedTimeStamp(false),
m_providedTimeStamp(0)
{
@ -203,6 +204,11 @@ void LogFile::timerFired()
}
}
bool LogFile::isPlaying() const
{
return m_file.isOpen() && m_timer.isActive();
}
bool LogFile::startReplay()
{
if (!m_file.isOpen() || m_timer.isActive()) {
@ -226,6 +232,7 @@ bool LogFile::startReplay()
m_timer.setInterval(10);
m_timer.start();
paused = false;
emit replayStarted();
return true;
@ -233,23 +240,42 @@ bool LogFile::startReplay()
bool LogFile::stopReplay()
{
if (!m_file.isOpen() || !m_timer.isActive()) {
if (!m_file.isOpen() || !(m_timer.isActive() || paused)) {
return false;
}
qDebug() << "LogFile - stopReplay";
m_timer.stop();
paused = false;
emit replayFinished();
return true;
}
void LogFile::pauseReplay()
bool LogFile::pauseReplay()
{
if (!m_timer.isActive()) {
return false;
}
qDebug() << "LogFile - pauseReplay";
m_timer.stop();
paused = true;
// hack to notify UI that replay paused
emit replayStarted();
return true;
}
void LogFile::resumeReplay()
bool LogFile::resumeReplay()
{
if (m_timer.isActive()) {
return false;
}
qDebug() << "LogFile - resumeReplay";
m_timeOffset = m_myTime.elapsed();
m_timer.start();
paused = false;
// hack to notify UI that replay resumed
emit replayStarted();
return true;
}

View File

@ -51,6 +51,8 @@ public:
bool isSequential() const;
bool isPlaying() const;
bool open(OpenMode mode);
void close();
@ -81,8 +83,8 @@ public slots:
};
bool startReplay();
bool stopReplay();
void pauseReplay();
void resumeReplay();
bool pauseReplay();
bool resumeReplay();
protected slots:
void timerFired();
@ -106,6 +108,7 @@ protected:
int m_timeOffset;
double m_playbackSpeed;
bool paused;
private:
bool m_useProvidedTimeStamp;

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>536</width>
<width>439</width>
<height>122</height>
</rect>
</property>
@ -29,15 +29,15 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="2,2,0,0">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<widget class="QCommandLinkButton" name="playButton">
<widget class="QPushButton" name="playButton">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>30</horstretch>
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
@ -57,10 +57,10 @@
</widget>
</item>
<item>
<widget class="QCommandLinkButton" name="pauseButton">
<widget class="QPushButton" name="pauseButton">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>30</horstretch>
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
@ -71,7 +71,7 @@
</size>
</property>
<property name="text">
<string>Pause</string>
<string notr="true">Pause</string>
</property>
<property name="icon">
<iconset resource="../notify/res.qrc">
@ -79,6 +79,19 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
@ -88,8 +101,14 @@
</item>
<item>
<widget class="QLabel" name="statusLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Idle</string>
<string notr="true">&lt;Status&gt;</string>
</property>
</widget>
</item>

View File

@ -25,17 +25,15 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "logginggadgetwidget.h"
#include "ui_logging.h"
#include <QDebug>
#include <QStringList>
#include <QWidget>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QPushButton>
#include <loggingplugin.h>
LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QLabel(parent)
#include <QWidget>
#include <QPushButton>
LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QWidget(parent), loggingPlugin(NULL)
{
m_logging = new Ui_Logging();
m_logging->setupUi(this);
@ -52,20 +50,42 @@ LoggingGadgetWidget::~LoggingGadgetWidget()
void LoggingGadgetWidget::setPlugin(LoggingPlugin *p)
{
loggingPlugin = p;
connect(p, SIGNAL(stateChanged(QString)), this, SLOT(stateChanged(QString)));
connect(m_logging->playButton, SIGNAL(clicked()), p->getLogfile(), SLOT(resumeReplay()));
connect(m_logging->playButton, SIGNAL(clicked()), scpPlugin, SLOT(startPlotting()));
connect(m_logging->pauseButton, SIGNAL(clicked()), p->getLogfile(), SLOT(pauseReplay()));
connect(m_logging->pauseButton, SIGNAL(clicked()), scpPlugin, SLOT(stopPlotting()));
connect(m_logging->playbackSpeed, SIGNAL(valueChanged(double)), p->getLogfile(), SLOT(setReplaySpeed(double)));
void pauseReplay();
void resumeReplay();
connect(m_logging->playButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::startPlotting);
connect(m_logging->pauseButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::stopPlotting);
LogFile *logFile = loggingPlugin->getLogfile();
connect(m_logging->playButton, &QPushButton::clicked, logFile, &LogFile::resumeReplay);
connect(m_logging->pauseButton, &QPushButton::clicked, logFile, &LogFile::pauseReplay);
connect(m_logging->playbackSpeed, static_cast<void(QDoubleSpinBox::*) (double)>(&QDoubleSpinBox::valueChanged), logFile, &LogFile::setReplaySpeed);
connect(loggingPlugin, &LoggingPlugin::stateChanged, this, &LoggingGadgetWidget::stateChanged);
stateChanged(loggingPlugin->getState());
}
void LoggingGadgetWidget::stateChanged(QString status)
void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
{
QString status;
bool enabled = false;
switch (state) {
case LoggingPlugin::IDLE:
status = tr("Idle");
break;
case LoggingPlugin::LOGGING:
status = tr("Logging");
break;
case LoggingPlugin::REPLAY:
status = tr("Replaying");
enabled = true;
break;
}
m_logging->statusLabel->setText(status);
bool playing = loggingPlugin->getLogfile()->isPlaying();
m_logging->playButton->setEnabled(enabled && !playing);
m_logging->pauseButton->setEnabled(enabled && playing);
}
/**

View File

@ -28,16 +28,17 @@
#ifndef LoggingGADGETWIDGET_H_
#define LoggingGADGETWIDGET_H_
#include <QLabel>
#include "loggingplugin.h"
#include "extensionsystem/pluginmanager.h"
#include "scope/scopeplugin.h"
#include "scope/scopegadgetfactory.h"
#include <QWidget>
class Ui_Logging;
class LoggingPlugin;
class LoggingGadgetWidget : public QLabel {
class LoggingGadgetWidget : public QWidget {
Q_OBJECT
public:
@ -46,7 +47,7 @@ public:
void setPlugin(LoggingPlugin *p);
protected slots:
void stateChanged(QString status);
void stateChanged(LoggingPlugin::State state);
signals:
void pause();

View File

@ -29,7 +29,14 @@
*/
#include "loggingplugin.h"
#include "gcstelemetrystats.h"
#include "logginggadgetfactory.h"
#include "uavobjectmanager.h"
#include <uavtalk/uavtalk.h>
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <QApplication>
#include <QDebug>
@ -41,11 +48,7 @@
#include <QList>
#include <QErrorMessage>
#include <QWriteLocker>
#include <extensionsystem/pluginmanager.h>
#include <QKeySequence>
#include "uavobjectmanager.h"
LoggingConnection::LoggingConnection() :
m_deviceOpened(false), logFile()
@ -159,7 +162,6 @@ void LoggingThread::objectUpdated(UAVObject *obj)
void LoggingThread::run()
{
qDebug() << "LoggingThread - run";
startLogging();
}
@ -170,6 +172,7 @@ void LoggingThread::run()
void LoggingThread::startLogging()
{
qDebug() << "LoggingThread - start logging";
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
@ -181,7 +184,7 @@ void LoggingThread::startLogging()
for (i = list.constBegin(); i != list.constEnd(); ++i) {
for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) {
connect(*j, SIGNAL(objectUpdated(UAVObject *)), (LoggingThread *)this, SLOT(objectUpdated(UAVObject *)));
connect(*j, &UAVObject::objectUpdated, this, &LoggingThread::objectUpdated);
objects++;
}
}
@ -199,13 +202,15 @@ void LoggingThread::startLogging()
}
/**
* Pass this command to the correct thread then close the file
* Disconnect signals from all the objects, close the log file and stop
* the event loop
*/
void LoggingThread::stopLogging()
{
qDebug() << "LoggingThread - stop logging";
QWriteLocker locker(&lock);
qDebug() << "LoggingThread - stop logging";
// Disconnect all objects we registered with:
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
@ -217,7 +222,7 @@ void LoggingThread::stopLogging()
for (i = list.constBegin(); i != list.constEnd(); ++i) {
for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) {
disconnect(*j, SIGNAL(objectUpdated(UAVObject *)), (LoggingThread *)this, SLOT(objectUpdated(UAVObject *)));
disconnect(*j, &UAVObject::objectUpdated, this, &LoggingThread::objectUpdated);
}
}
@ -248,8 +253,7 @@ void LoggingThread::retrieveSettings()
}
}
// Start retrieving
qDebug() << QString("LoggingThread - retrieve settings objects from the autopilot (%1 objects)")
.arg(queue.length());
qDebug() << "LoggingThread - retrieving" << queue.length() << "objects";
retrieveNextObject();
}
@ -266,7 +270,7 @@ void LoggingThread::retrieveNextObject()
// Get next object from the queue
UAVObject *obj = queue.dequeue();
// Connect to object
connect(obj, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool)));
connect(obj, &UAVObject::transactionCompleted, this, &LoggingThread::transactionCompleted);
// Request update
obj->requestUpdate();
}
@ -294,11 +298,10 @@ void LoggingThread::transactionCompleted(UAVObject *obj, bool success)
}
LoggingPlugin::LoggingPlugin() :
loggingCommand(NULL),
state(IDLE),
loggingThread(NULL),
logConnection(new LoggingConnection()),
mf(NULL),
cmd(NULL)
logConnection(new LoggingConnection())
{}
LoggingPlugin::~LoggingPlugin()
@ -319,26 +322,28 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg)
Core::ActionManager *am = Core::ICore::instance()->actionManager();
Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS);
// Command to start logging
cmd = am->registerAction(new QAction(this),
"LoggingPlugin.Logging",
QList<int>() <<
Core::Constants::C_GLOBAL_ID);
cmd->setDefaultKeySequence(QKeySequence("Ctrl+L"));
cmd->action()->setText(tr("Start logging..."));
// Command to start/stop logging
loggingCommand = am->registerAction(new QAction(this),
"LoggingPlugin.Logging",
QList<int>() <<
Core::Constants::C_GLOBAL_ID);
loggingCommand->setDefaultKeySequence(QKeySequence("Ctrl+L"));
ac->menu()->addSeparator();
ac->appendGroup("Logging");
ac->addAction(cmd, "Logging");
ac->addAction(loggingCommand, "Logging");
connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(toggleLogging()));
connect(loggingCommand->action(), &QAction::triggered, this, &LoggingPlugin::toggleLogging);
mf = new LoggingGadgetFactory(this);
LoggingGadgetFactory *mf = new LoggingGadgetFactory(this);
addAutoReleasedObject(mf);
// Map signal from end of replay to replay stopped
connect(getLogfile(), SIGNAL(replayFinished()), this, SLOT(replayStopped()));
connect(getLogfile(), SIGNAL(replayStarted()), this, SLOT(replayStarted()));
connect(getLogfile(), &LogFile::replayFinished, this, &LoggingPlugin::replayStopped);
connect(getLogfile(), &LogFile::replayStarted, this, &LoggingPlugin::replayStarted);
// update state and command
loggingStopped();
return true;
}
@ -369,7 +374,6 @@ void LoggingPlugin::toggleLogging()
*/
void LoggingPlugin::startLogging(QString file)
{
qDebug() << "LoggingPlugin - start logging to " << file;
// needed ?
stopLogging();
// Start logging thread
@ -396,7 +400,6 @@ void LoggingPlugin::stopLogging()
return;
}
qDebug() << "LoggingPlugin - stop logging";
loggingThread->stopLogging();
delete loggingThread;
@ -405,9 +408,11 @@ void LoggingPlugin::stopLogging()
void LoggingPlugin::loggingStarted()
{
state = LOGGING;
cmd->action()->setText(tr("Stop logging"));
emit stateChanged("LOGGING");
loggingCommand->action()->setText(tr("Stop logging"));
if (state == IDLE) {
state = LOGGING;
emit stateChanged(state);
}
}
/**
@ -416,31 +421,37 @@ void LoggingPlugin::loggingStarted()
*/
void LoggingPlugin::loggingStopped()
{
loggingCommand->action()->setText(tr("Start logging..."));
if (state == LOGGING) {
state = IDLE;
cmd->action()->setText(tr("Start logging..."));
emit stateChanged("IDLE");
emit stateChanged(state);
}
}
/**
* Received the replay stopped signal from the LogFile
*/
void LoggingPlugin::replayStopped()
{
state = IDLE;
emit stateChanged("IDLE");
}
/**
* Received the replay started signal from the LogFile
*/
void LoggingPlugin::replayStarted()
{
if (state == LOGGING) {
stopLogging();
}
loggingCommand->action()->setEnabled(false);
state = REPLAY;
emit stateChanged("REPLAY");
emit stateChanged(state);
}
/**
* Received the replay stopped signal from the LogFile
*/
void LoggingPlugin::replayStopped()
{
loggingCommand->action()->setEnabled(true);
if (state == REPLAY) {
state = IDLE;
emit stateChanged(state);
}
}
void LoggingPlugin::extensionsInitialized()
{

View File

@ -30,21 +30,24 @@
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/iconnection.h>
#include <extensionsystem/iplugin.h>
#include "uavobjectmanager.h"
#include "gcstelemetrystats.h"
#include <uavtalk/uavtalk.h>
#include <utils/logfile.h>
#include <QThread>
#include <QQueue>
#include <QReadWriteLock>
class UAVObject;
class UAVDataObject;
class UAVTalk;
class LoggingPlugin;
class LoggingGadgetFactory;
namespace Core {
class Command;
}
/**
* Define a connection via the IConnection interface
* Plugin will add a instance of this class to the pool,
@ -86,10 +89,6 @@ public:
bool openFile(QString file);
private slots:
void objectUpdated(UAVObject *obj);
void transactionCompleted(UAVObject *obj, bool success);
public slots:
void startLogging();
void stopLogging();
@ -97,13 +96,15 @@ public slots:
protected:
void run();
QReadWriteLock lock;
LogFile logFile;
UAVTalk *uavTalk;
private slots:
void objectUpdated(UAVObject *obj);
void transactionCompleted(UAVObject *obj, bool success);
private:
QReadWriteLock lock;
QQueue<UAVDataObject *> queue;
LogFile logFile;
UAVTalk *uavTalk;
void retrieveSettings();
void retrieveNextObject();
@ -116,6 +117,8 @@ class LoggingPlugin : public ExtensionSystem::IPlugin {
friend class LoggingConnection;
public:
enum State { IDLE, LOGGING, REPLAY };
LoggingPlugin();
~LoggingPlugin();
@ -123,26 +126,18 @@ public:
bool initialize(const QStringList & arguments, QString *errorString);
void shutdown();
LoggingConnection *getLogConnection()
{
return logConnection;
};
LogFile *getLogfile()
{
return logConnection->getLogfile();
}
void setLogMenuTitle(QString str);
State getState()
{
return state;
}
signals:
void stateChanged(QString);
protected:
enum { IDLE, LOGGING, REPLAY } state;
LoggingThread *loggingThread;
// These are used for replay, logging in its own thread
LoggingConnection *logConnection;
void stateChanged(State);
private slots:
void toggleLogging();
@ -154,8 +149,11 @@ private slots:
void replayStopped();
private:
LoggingGadgetFactory *mf;
Core::Command *cmd;
Core::Command *loggingCommand;
State state;
// These are used for replay, logging in its own thread
LoggingThread *loggingThread;
LoggingConnection *logConnection;
};
#endif /* LoggingPLUGIN_H_ */
/**