From 3b8bfabf2860eff4f37ae813cbf0082a9a530721 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 11 May 2017 02:53:30 +0200 Subject: [PATCH] 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 --- ground/gcs/src/libs/utils/logfile.cpp | 32 +++++- ground/gcs/src/libs/utils/logfile.h | 7 +- ground/gcs/src/plugins/logging/logging.ui | 39 ++++++-- .../plugins/logging/logginggadgetwidget.cpp | 54 ++++++---- .../src/plugins/logging/logginggadgetwidget.h | 9 +- .../gcs/src/plugins/logging/loggingplugin.cpp | 99 ++++++++++--------- .../gcs/src/plugins/logging/loggingplugin.h | 52 +++++----- 7 files changed, 185 insertions(+), 107 deletions(-) diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index 3706319c7..95b400d68 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -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; } diff --git a/ground/gcs/src/libs/utils/logfile.h b/ground/gcs/src/libs/utils/logfile.h index 396ed95e8..3c3616e20 100644 --- a/ground/gcs/src/libs/utils/logfile.h +++ b/ground/gcs/src/libs/utils/logfile.h @@ -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; diff --git a/ground/gcs/src/plugins/logging/logging.ui b/ground/gcs/src/plugins/logging/logging.ui index b5fa5b110..05bad61aa 100644 --- a/ground/gcs/src/plugins/logging/logging.ui +++ b/ground/gcs/src/plugins/logging/logging.ui @@ -6,7 +6,7 @@ 0 0 - 536 + 439 122 @@ -29,15 +29,15 @@ - + QLayout::SetNoConstraint - + - - 30 + + 0 0 @@ -57,10 +57,10 @@ - + - - 30 + + 0 0 @@ -71,7 +71,7 @@ - Pause + Pause @@ -79,6 +79,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -88,8 +101,14 @@ + + + 75 + true + + - Idle + <Status> diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp index 9c1838682..659a65b30 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp @@ -25,17 +25,15 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "logginggadgetwidget.h" + #include "ui_logging.h" -#include -#include -#include -#include -#include -#include #include -LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QLabel(parent) +#include +#include + +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(&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); } /** diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.h b/ground/gcs/src/plugins/logging/logginggadgetwidget.h index 05e760505..60b268e21 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.h +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.h @@ -28,16 +28,17 @@ #ifndef LoggingGADGETWIDGET_H_ #define LoggingGADGETWIDGET_H_ -#include +#include "loggingplugin.h" + #include "extensionsystem/pluginmanager.h" #include "scope/scopeplugin.h" #include "scope/scopegadgetfactory.h" +#include 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(); diff --git a/ground/gcs/src/plugins/logging/loggingplugin.cpp b/ground/gcs/src/plugins/logging/loggingplugin.cpp index cc7e7cccc..3d7580e56 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.cpp +++ b/ground/gcs/src/plugins/logging/loggingplugin.cpp @@ -29,7 +29,14 @@ */ #include "loggingplugin.h" + +#include "gcstelemetrystats.h" + #include "logginggadgetfactory.h" +#include "uavobjectmanager.h" +#include +#include +#include #include #include @@ -41,11 +48,7 @@ #include #include #include - -#include #include -#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(); @@ -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(); @@ -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() << - 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() << + 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() { diff --git a/ground/gcs/src/plugins/logging/loggingplugin.h b/ground/gcs/src/plugins/logging/loggingplugin.h index 6b0ecbdbb..7a1925ad0 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.h +++ b/ground/gcs/src/plugins/logging/loggingplugin.h @@ -30,21 +30,24 @@ #include #include -#include #include #include -#include "uavobjectmanager.h" -#include "gcstelemetrystats.h" -#include #include #include #include #include +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 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_ */ /**