mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-30 15:52:12 +01:00
LP-597 Progress bar for GCS log replay - add progress bar and a stop button
- Added stop button: - start: starts from 0 position after stop signal, resumes from current position after pause signal. - pause: freezes at current position, also freezes scopes. - stop: stops replay and resets start position to 0 (does not close the logfile) - Creates an index of the timestamp positions in the logfile for quick seeking to the target position in the log. - Start, End and current position timestamps are visible in the GUI below the position slider. - Determine replay position by moving the position slider - Update position label while changing position bar - Speed widget: lowest multiplier is now 0.1 instead of 0. Only set one decimal of precision. More decimals seem useless at this time.
This commit is contained in:
parent
a4c0bcfb1a
commit
c53e99ee41
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QThread> // DEBUG: to display the thread ID
|
||||||
|
|
||||||
LogFile::LogFile(QObject *parent) : QIODevice(parent),
|
LogFile::LogFile(QObject *parent) : QIODevice(parent),
|
||||||
m_timer(this),
|
m_timer(this),
|
||||||
@ -34,9 +36,12 @@ LogFile::LogFile(QObject *parent) : QIODevice(parent),
|
|||||||
m_lastPlayed(0),
|
m_lastPlayed(0),
|
||||||
m_timeOffset(0),
|
m_timeOffset(0),
|
||||||
m_playbackSpeed(1.0),
|
m_playbackSpeed(1.0),
|
||||||
paused(false),
|
m_replayStatus(STOPPED),
|
||||||
m_useProvidedTimeStamp(false),
|
m_useProvidedTimeStamp(false),
|
||||||
m_providedTimeStamp(0)
|
m_providedTimeStamp(0),
|
||||||
|
m_beginTimeStamp(0),
|
||||||
|
m_endTimeStamp(0),
|
||||||
|
m_timer_tick(0)
|
||||||
{
|
{
|
||||||
connect(&m_timer, &QTimer::timeout, this, &LogFile::timerFired);
|
connect(&m_timer, &QTimer::timeout, this, &LogFile::timerFired);
|
||||||
}
|
}
|
||||||
@ -137,14 +142,58 @@ qint64 LogFile::bytesAvailable() const
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
timerFired()
|
||||||
|
|
||||||
|
This function is called at a 10 ms interval to fill the replay buffers.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
void LogFile::timerFired()
|
void LogFile::timerFired()
|
||||||
{
|
{
|
||||||
|
if (m_replayStatus != PLAYING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_timer_tick++;
|
||||||
|
if ( m_timer_tick % 100 == 0 ) {
|
||||||
|
qDebug() << "----------------------------------------------------------";
|
||||||
|
qDebug() << "LogFile::timerFired() -> Tick = " << m_timer_tick;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_file.bytesAvailable() > 4) {
|
if (m_file.bytesAvailable() > 4) {
|
||||||
int time;
|
int time;
|
||||||
time = m_myTime.elapsed();
|
time = m_myTime.elapsed();
|
||||||
|
|
||||||
// TODO: going back in time will be a problem
|
/*
|
||||||
while ((m_lastPlayed + ((double)(time - m_timeOffset) * m_playbackSpeed) > m_nextTimeStamp)) {
|
This code generates an advancing window. All samples that fit in the window
|
||||||
|
are replayed. The window is about the size of the timer interval: 10 ms.
|
||||||
|
|
||||||
|
Description of used variables:
|
||||||
|
|
||||||
|
time : time passed since start of playback (in ms) - current
|
||||||
|
m_timeOffset : time passed since start of playback (in ms) - when timerFired() was previously run
|
||||||
|
m_lastPlayed : next log timestamp to advance to (in ms)
|
||||||
|
m_nextTimeStamp : timestamp of most recently read log entry (in ms)
|
||||||
|
m_playbackSpeed : 1 .. 10 replay speedup factor
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
while ( m_nextTimeStamp < (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed) ) {
|
||||||
|
// if ( m_timer_tick % 100 == 0 ) {
|
||||||
|
// if ( true ) {
|
||||||
|
// qDebug() << "LogFile::timerFired() -> m_lastPlayed = " << m_lastPlayed;
|
||||||
|
// qDebug() << "LogFile::timerFired() -> m_nextTimeStamp = " << m_nextTimeStamp;
|
||||||
|
// qDebug() << "LogFile::timerFired() -> time = " << time;
|
||||||
|
// qDebug() << "LogFile::timerFired() -> m_timeOffset = " << m_timeOffset;
|
||||||
|
// qDebug() << "---";
|
||||||
|
// qDebug() << "LogFile::timerFired() -> m_nextTimeStamp = " << m_nextTimeStamp;
|
||||||
|
// qDebug() << "LogFile::timerFired() -> (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed) = " << (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed);
|
||||||
|
// qDebug() << "---";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// advance the replay window for the next time period
|
||||||
|
|
||||||
m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed);
|
m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed);
|
||||||
|
|
||||||
// read data size
|
// read data size
|
||||||
@ -178,6 +227,10 @@ void LogFile::timerFired()
|
|||||||
|
|
||||||
emit readyRead();
|
emit readyRead();
|
||||||
|
|
||||||
|
// rate-limit slider bar position updates to 10 updates per second
|
||||||
|
if (m_timer_tick % 10 == 0) {
|
||||||
|
emit replayPosition(m_nextTimeStamp);
|
||||||
|
}
|
||||||
// read next timestamp
|
// read next timestamp
|
||||||
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
|
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
|
||||||
qDebug() << "LogFile - end of log file reached";
|
qDebug() << "LogFile - end of log file reached";
|
||||||
@ -196,7 +249,7 @@ void LogFile::timerFired()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_timeOffset = time;
|
m_timeOffset = time;
|
||||||
time = m_myTime.elapsed();
|
time = m_myTime.elapsed(); // number of milliseconds since start of playback
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "LogFile - end of log file reached";
|
qDebug() << "LogFile - end of log file reached";
|
||||||
@ -209,8 +262,28 @@ bool LogFile::isPlaying() const
|
|||||||
return m_file.isOpen() && m_timer.isActive();
|
return m_file.isOpen() && m_timer.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION: startReplay()
|
||||||
|
*
|
||||||
|
* Starts replaying a newly opened logfile.
|
||||||
|
* Starts a timer: m_timer
|
||||||
|
*
|
||||||
|
* This function and the stopReplay() function should only ever be called from the same thread.
|
||||||
|
* This is required for correctly controlling the timer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
bool LogFile::startReplay()
|
bool LogFile::startReplay()
|
||||||
{
|
{
|
||||||
|
qDebug() << "startReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
|
||||||
|
// Walk through logfile and create timestamp index
|
||||||
|
// Don't start replay if there was a problem indexing the logfile.
|
||||||
|
if (!buildIndex()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_timer_tick = 0;
|
||||||
|
|
||||||
if (!m_file.isOpen() || m_timer.isActive()) {
|
if (!m_file.isOpen() || m_timer.isActive()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -221,7 +294,9 @@ bool LogFile::startReplay()
|
|||||||
m_lastPlayed = 0;
|
m_lastPlayed = 0;
|
||||||
m_previousTimeStamp = 0;
|
m_previousTimeStamp = 0;
|
||||||
m_nextTimeStamp = 0;
|
m_nextTimeStamp = 0;
|
||||||
|
m_mutex.lock();
|
||||||
m_dataBuffer.clear();
|
m_dataBuffer.clear();
|
||||||
|
m_mutex.unlock();
|
||||||
|
|
||||||
// read next timestamp
|
// read next timestamp
|
||||||
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
|
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
|
||||||
@ -232,50 +307,312 @@ bool LogFile::startReplay()
|
|||||||
|
|
||||||
m_timer.setInterval(10);
|
m_timer.setInterval(10);
|
||||||
m_timer.start();
|
m_timer.start();
|
||||||
paused = false;
|
m_replayStatus = PLAYING;
|
||||||
|
|
||||||
emit replayStarted();
|
emit replayStarted();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION: stopReplay()
|
||||||
|
*
|
||||||
|
* Stops replaying the logfile.
|
||||||
|
* Stops the timer: m_timer
|
||||||
|
*
|
||||||
|
* This function and the startReplay() function should only ever be called from the same thread.
|
||||||
|
* This is a requirement to be able to control the timer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
bool LogFile::stopReplay()
|
bool LogFile::stopReplay()
|
||||||
{
|
{
|
||||||
if (!m_file.isOpen() || !(m_timer.isActive() || paused)) {
|
qDebug() << "stopReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
|
||||||
|
if (!m_file.isOpen() || !m_timer.isActive()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qDebug() << "LogFile - stopReplay";
|
qDebug() << "LogFile - stopReplay";
|
||||||
m_timer.stop();
|
m_timer.stop();
|
||||||
paused = false;
|
m_replayStatus = STOPPED;
|
||||||
|
|
||||||
emit replayFinished();
|
emit replayFinished();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SLOT: restartReplay()
|
||||||
|
*
|
||||||
|
* This function starts replay from the begining of the currently opened logfile.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void LogFile::restartReplay()
|
||||||
|
{
|
||||||
|
qDebug() << "restartReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
|
||||||
|
resumeReplayFrom(0);
|
||||||
|
|
||||||
|
qDebug() << "restartReplay(): end of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SLOT: haltReplay()
|
||||||
|
*
|
||||||
|
* Stops replay without storing the current playback position
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void LogFile::haltReplay()
|
||||||
|
{
|
||||||
|
qDebug() << "haltReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
|
||||||
|
qDebug() << "haltReplay() time = m_myTime.elapsed() = " << m_myTime.elapsed();
|
||||||
|
qDebug() << "haltReplay() m_timeOffset = " << m_timeOffset;
|
||||||
|
qDebug() << "haltReplay() m_nextTimeStamp = " << m_nextTimeStamp;
|
||||||
|
qDebug() << "haltReplay() m_lastPlayed = " << m_lastPlayed;
|
||||||
|
|
||||||
|
m_replayStatus = STOPPED;
|
||||||
|
|
||||||
|
qDebug() << "haltReplay(): end of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* SLOT: pauseReplay()
|
||||||
|
*
|
||||||
|
* Pauses replay while storing the current playback position
|
||||||
|
*
|
||||||
|
*/
|
||||||
bool LogFile::pauseReplay()
|
bool LogFile::pauseReplay()
|
||||||
{
|
{
|
||||||
|
qDebug() << "pauseReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
|
||||||
|
qDebug() << "pauseReplay() time = m_myTime.elapsed() = " << m_myTime.elapsed();
|
||||||
|
qDebug() << "pauseReplay() m_timeOffset = " << m_timeOffset;
|
||||||
|
qDebug() << "pauseReplay() m_nextTimeStamp = " << m_nextTimeStamp;
|
||||||
|
qDebug() << "pauseReplay() m_lastPlayed = " << m_lastPlayed;
|
||||||
|
|
||||||
if (!m_timer.isActive()) {
|
if (!m_timer.isActive()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qDebug() << "LogFile - pauseReplay";
|
qDebug() << "LogFile - pauseReplay";
|
||||||
m_timer.stop();
|
m_timer.stop();
|
||||||
paused = true;
|
m_replayStatus = PAUSED;
|
||||||
|
|
||||||
// hack to notify UI that replay paused
|
// hack to notify UI that replay paused
|
||||||
emit replayStarted();
|
emit replayStarted();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SLOT: resumeReplay()
|
||||||
|
*
|
||||||
|
* Resumes replay from the stored playback position
|
||||||
|
*
|
||||||
|
*/
|
||||||
bool LogFile::resumeReplay()
|
bool LogFile::resumeReplay()
|
||||||
{
|
{
|
||||||
|
qDebug() << "resumeReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
|
||||||
|
m_mutex.lock();
|
||||||
|
m_dataBuffer.clear();
|
||||||
|
m_mutex.unlock();
|
||||||
|
|
||||||
|
m_file.seek(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_timeStamps.size(); ++i) {
|
||||||
|
if (m_timeStamps.at(i) >= m_lastPlayed) {
|
||||||
|
m_file.seek(m_timeStampPositions.at(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
|
||||||
|
|
||||||
|
m_myTime.restart();
|
||||||
|
m_myTime = m_myTime.addMSecs(-m_timeOffset); // Set startpoint this far back in time.
|
||||||
|
|
||||||
|
qDebug() << "resumeReplay() time = m_myTime.elapsed() = " << m_myTime.elapsed();
|
||||||
|
qDebug() << "resumeReplay() m_timeOffset = " << m_timeOffset;
|
||||||
|
qDebug() << "resumeReplay() m_nextTimeStamp = " << m_nextTimeStamp;
|
||||||
|
qDebug() << "resumeReplay() m_lastPlayed = " << m_lastPlayed;
|
||||||
|
|
||||||
|
qDebug() << "resumeReplay(): end of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
if (m_timer.isActive()) {
|
if (m_timer.isActive()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qDebug() << "LogFile - resumeReplay";
|
qDebug() << "LogFile - resumeReplay";
|
||||||
m_timeOffset = m_myTime.elapsed();
|
m_timeOffset = m_myTime.elapsed();
|
||||||
m_timer.start();
|
m_timer.start();
|
||||||
paused = false;
|
m_replayStatus = PLAYING;
|
||||||
|
|
||||||
// hack to notify UI that replay resumed
|
// Notify UI that replay has been resumed
|
||||||
emit replayStarted();
|
emit replayStarted();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SLOT: resumeReplayFrom()
|
||||||
|
*
|
||||||
|
* Resumes replay from the given position
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void LogFile::resumeReplayFrom(quint32 desiredPosition)
|
||||||
|
{
|
||||||
|
qDebug() << "resumeReplayFrom(): start of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
|
||||||
|
m_mutex.lock();
|
||||||
|
m_dataBuffer.clear();
|
||||||
|
m_mutex.unlock();
|
||||||
|
|
||||||
|
m_file.seek(0);
|
||||||
|
|
||||||
|
qint32 i;
|
||||||
|
for (i = 0; i < m_timeStamps.size(); ++i) {
|
||||||
|
if (m_timeStamps.at(i) >= desiredPosition) {
|
||||||
|
m_file.seek(m_timeStampPositions.at(i));
|
||||||
|
m_lastPlayed = m_timeStamps.at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
|
||||||
|
|
||||||
|
if (m_nextTimeStamp != m_timeStamps.at(i)) {
|
||||||
|
qDebug() << "resumeReplayFrom() m_nextTimeStamp != m_timeStamps.at(i) -> " << m_nextTimeStamp << " != " << m_timeStamps.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_timeOffset = (m_lastPlayed - m_nextTimeStamp) / m_playbackSpeed;
|
||||||
|
m_timeOffset = 0;
|
||||||
|
|
||||||
|
m_myTime.restart();
|
||||||
|
// m_myTime = m_myTime.addMSecs(-m_timeOffset); // Set startpoint this far back in time.
|
||||||
|
// TODO: The above line is a possible memory leak. I'm not sure how to handle this correctly.
|
||||||
|
|
||||||
|
qDebug() << "resumeReplayFrom() time = m_myTime.elapsed() = " << m_myTime.elapsed();
|
||||||
|
qDebug() << "resumeReplayFrom() m_timeOffset = " << m_timeOffset;
|
||||||
|
qDebug() << "resumeReplayFrom() m_nextTimeStamp = " << m_nextTimeStamp;
|
||||||
|
qDebug() << "resumeReplayFrom() m_lastPlayed = " << m_lastPlayed;
|
||||||
|
|
||||||
|
m_replayStatus = PLAYING;
|
||||||
|
emit replayStarted();
|
||||||
|
|
||||||
|
qDebug() << "resumeReplayFrom(): end of function, current Thread ID is: " << QThread::currentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION: getReplayStatus()
|
||||||
|
*
|
||||||
|
* Returns the current replay status.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ReplayState LogFile::getReplayStatus()
|
||||||
|
{
|
||||||
|
return m_replayStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION: buildIndex()
|
||||||
|
*
|
||||||
|
* Walk through the opened logfile and sets the start and end position timestamps
|
||||||
|
* Also builds an index for quickly skipping to a specific position in the logfile.
|
||||||
|
*
|
||||||
|
* returns true when indexing has completed successfully
|
||||||
|
* returns false when a problem was encountered
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool LogFile::buildIndex()
|
||||||
|
{
|
||||||
|
quint32 timeStamp;
|
||||||
|
qint64 totalSize;
|
||||||
|
qint64 readPointer = 0;
|
||||||
|
quint64 index = 0;
|
||||||
|
|
||||||
|
QByteArray arr = m_file.readAll();
|
||||||
|
|
||||||
|
totalSize = arr.size();
|
||||||
|
QDataStream dataStream(&arr, QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
// set the start timestamp
|
||||||
|
if (totalSize - readPointer >= 4) {
|
||||||
|
dataStream.readRawData((char *)&timeStamp, 4);
|
||||||
|
m_timeStamps.append(timeStamp);
|
||||||
|
m_timeStampPositions.append(readPointer);
|
||||||
|
qDebug() << "LogFile::buildIndex() element index = " << index << " \t-> timestamp = " << timeStamp << " \t-> bytes in file = " << readPointer;
|
||||||
|
readPointer += 4;
|
||||||
|
index++;
|
||||||
|
m_beginTimeStamp = timeStamp;
|
||||||
|
m_endTimeStamp = timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
qint64 dataSize;
|
||||||
|
|
||||||
|
// Check if there are enough bytes remaining for a correct "dataSize" field
|
||||||
|
if (totalSize - readPointer < (qint64)sizeof(dataSize)) {
|
||||||
|
qDebug() << "Error: Logfile corrupted! Unexpected end of file";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the dataSize field
|
||||||
|
dataStream.readRawData((char *)&dataSize, sizeof(dataSize));
|
||||||
|
readPointer += sizeof(dataSize);
|
||||||
|
|
||||||
|
if (dataSize < 1 || dataSize > (1024 * 1024)) {
|
||||||
|
qDebug() << "Error: Logfile corrupted! Unlikely packet size: " << dataSize << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there are enough bytes remaining
|
||||||
|
if (totalSize - readPointer < dataSize) {
|
||||||
|
qDebug() << "Error: Logfile corrupted! Unexpected end of file";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip reading the data (we don't need it at this point)
|
||||||
|
readPointer += dataStream.skipRawData(dataSize);
|
||||||
|
|
||||||
|
// read the next timestamp
|
||||||
|
if (totalSize - readPointer >= 4) {
|
||||||
|
dataStream.readRawData((char *)&timeStamp, 4);
|
||||||
|
qDebug() << "LogFile::buildIndex() element index = " << index << " \t-> timestamp = " << timeStamp << " \t-> bytes in file = " << readPointer;
|
||||||
|
|
||||||
|
// some validity checks
|
||||||
|
if (timeStamp < m_endTimeStamp // logfile goes back in time
|
||||||
|
|| (timeStamp - m_endTimeStamp) > (60 * 60 * 1000)) { // gap of more than 60 minutes)
|
||||||
|
qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << timeStamp << " after " << m_endTimeStamp;
|
||||||
|
// return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_timeStamps.append(timeStamp);
|
||||||
|
m_timeStampPositions.append(readPointer);
|
||||||
|
readPointer += 4;
|
||||||
|
index++;
|
||||||
|
m_endTimeStamp = timeStamp;
|
||||||
|
} else {
|
||||||
|
// Break without error (we expect to end at this location when we are at the end of the logfile)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "buildIndex() -> first timestamp in log = " << m_beginTimeStamp;
|
||||||
|
qDebug() << "buildIndex() -> last timestamp in log = " << m_endTimeStamp;
|
||||||
|
|
||||||
|
emit updateBeginAndEndtimes(m_beginTimeStamp, m_endTimeStamp);
|
||||||
|
|
||||||
|
// reset the read pointer to the start of the file
|
||||||
|
m_file.seek(0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION: setReplaySpeed()
|
||||||
|
*
|
||||||
|
* Update the replay speed.
|
||||||
|
*
|
||||||
|
* FIXME: currently, changing the replay speed, while skipping through the logfile
|
||||||
|
* with the position bar causes position alignment to be lost.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void LogFile::setReplaySpeed(double val)
|
||||||
|
{
|
||||||
|
m_playbackSpeed = val;
|
||||||
|
qDebug() << "Playback speed is now " << QString("%1").arg(m_playbackSpeed, 4, 'f', 2, QChar('0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +34,9 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
typedef enum { PLAYING, PAUSED, STOPPED } ReplayState;
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice {
|
class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -75,32 +78,34 @@ public:
|
|||||||
m_providedTimeStamp = providedTimestamp;
|
m_providedTimeStamp = providedTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReplayState getReplayStatus();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setReplaySpeed(double val)
|
void setReplaySpeed(double val);
|
||||||
{
|
|
||||||
m_playbackSpeed = val;
|
|
||||||
qDebug() << "Playback speed is now" << m_playbackSpeed;
|
|
||||||
};
|
|
||||||
bool startReplay();
|
bool startReplay();
|
||||||
bool stopReplay();
|
bool stopReplay();
|
||||||
bool pauseReplay();
|
bool pauseReplay();
|
||||||
bool resumeReplay();
|
bool resumeReplay();
|
||||||
|
void resumeReplayFrom(quint32);
|
||||||
|
void restartReplay();
|
||||||
|
void haltReplay();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void timerFired();
|
void timerFired();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void readReady();
|
|
||||||
void replayStarted();
|
void replayStarted();
|
||||||
void replayFinished();
|
void replayFinished();
|
||||||
|
void replayPosition(quint32);
|
||||||
|
void updateBeginAndEndtimes(quint32, quint32);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QByteArray m_dataBuffer;
|
QByteArray m_dataBuffer;
|
||||||
QTimer m_timer;
|
QTimer m_timer;
|
||||||
QTime m_myTime;
|
QTime m_myTime;
|
||||||
QFile m_file;
|
QFile m_file;
|
||||||
qint32 m_previousTimeStamp;
|
quint32 m_previousTimeStamp;
|
||||||
qint32 m_nextTimeStamp;
|
quint32 m_nextTimeStamp;
|
||||||
double m_lastPlayed;
|
double m_lastPlayed;
|
||||||
// QMutex wants to be mutable
|
// QMutex wants to be mutable
|
||||||
// http://stackoverflow.com/questions/25521570/can-mutex-locking-function-be-marked-as-const
|
// http://stackoverflow.com/questions/25521570/can-mutex-locking-function-be-marked-as-const
|
||||||
@ -108,11 +113,18 @@ protected:
|
|||||||
|
|
||||||
int m_timeOffset;
|
int m_timeOffset;
|
||||||
double m_playbackSpeed;
|
double m_playbackSpeed;
|
||||||
bool paused;
|
ReplayState m_replayStatus;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_useProvidedTimeStamp;
|
bool m_useProvidedTimeStamp;
|
||||||
qint32 m_providedTimeStamp;
|
qint32 m_providedTimeStamp;
|
||||||
|
quint32 m_beginTimeStamp;
|
||||||
|
quint32 m_endTimeStamp;
|
||||||
|
quint32 m_timer_tick;
|
||||||
|
QVector<quint32> m_timeStamps;
|
||||||
|
QVector<qint64> m_timeStampPositions;
|
||||||
|
|
||||||
|
bool buildIndex();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOGFILE_H
|
#endif // LOGFILE_H
|
||||||
|
@ -7,19 +7,19 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>439</width>
|
<width>439</width>
|
||||||
<height>122</height>
|
<height>150</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<horstretch>100</horstretch>
|
<horstretch>1</horstretch>
|
||||||
<verstretch>80</verstretch>
|
<verstretch>1</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>100</width>
|
<width>100</width>
|
||||||
<height>80</height>
|
<height>150</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -27,9 +27,9 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
|
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0">
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="2,2,2,0,0,0">
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
<enum>QLayout::SetNoConstraint</enum>
|
<enum>QLayout::SetNoConstraint</enum>
|
||||||
</property>
|
</property>
|
||||||
@ -71,7 +71,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">Pause</string>
|
<string>Pause</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../notify/res.qrc">
|
<iconset resource="../notify/res.qrc">
|
||||||
@ -79,6 +79,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="stopButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Stop</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../notify/res.qrc">
|
||||||
|
<normaloff>:/notify/images/delete.png</normaloff>:/notify/images/delete.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_2">
|
<spacer name="horizontalSpacer_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -125,11 +148,17 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDoubleSpinBox" name="playbackSpeed">
|
<widget class="QDoubleSpinBox" name="playbackSpeed">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.10000000000000</double>
|
||||||
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<double>10.000000000000000</double>
|
<double>10.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
<property name="singleStep">
|
<property name="singleStep">
|
||||||
<double>0.100000000000000</double>
|
<double>0.10000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<double>1.000000000000000</double>
|
<double>1.000000000000000</double>
|
||||||
@ -151,6 +180,106 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSlider" name="playBackPosition">
|
||||||
|
<property name="tracking">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="invertedAppearance">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="invertedControls">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::TicksBothSides</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickInterval">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="startTimeLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<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="positionTimestampLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</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="endTimeLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -40,6 +40,15 @@ LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QWidget(parent), log
|
|||||||
|
|
||||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||||
scpPlugin = pm->getObject<ScopeGadgetFactory>();
|
scpPlugin = pm->getObject<ScopeGadgetFactory>();
|
||||||
|
|
||||||
|
disableButtons();
|
||||||
|
|
||||||
|
sliderActionDelay.setSingleShot(true);
|
||||||
|
sliderActionDelay.setInterval(200); // Delay for 200 ms
|
||||||
|
|
||||||
|
connect(&sliderActionDelay, SIGNAL(timeout()), this, SLOT(sendResumeReplayFrom()));
|
||||||
|
|
||||||
|
m_storedPosition = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoggingGadgetWidget::~LoggingGadgetWidget()
|
LoggingGadgetWidget::~LoggingGadgetWidget()
|
||||||
@ -51,6 +60,31 @@ void LoggingGadgetWidget::setPlugin(LoggingPlugin *p)
|
|||||||
{
|
{
|
||||||
loggingPlugin = p;
|
loggingPlugin = p;
|
||||||
|
|
||||||
|
connect(p->getLogfile(), SIGNAL(updateBeginAndEndtimes(quint32, quint32)), this, SLOT(updateBeginAndEndtimes(quint32, quint32)));
|
||||||
|
connect(p->getLogfile(), SIGNAL(replayPosition(quint32)), this, SLOT(replayPosition(quint32)));
|
||||||
|
connect(m_logging->playBackPosition, SIGNAL(valueChanged(int)), this, SLOT(sliderMoved(int)));
|
||||||
|
connect(this, SIGNAL(resumeReplayFrom(quint32)), p->getLogfile(), SLOT(resumeReplayFrom(quint32)));
|
||||||
|
|
||||||
|
connect(this, SIGNAL(startReplay()), p->getLogfile(), SLOT(restartReplay()));
|
||||||
|
connect(this, SIGNAL(stopReplay()), p->getLogfile(), SLOT(haltReplay()));
|
||||||
|
connect(this, SIGNAL(pauseReplay()), p->getLogfile(), SLOT(pauseReplay()));
|
||||||
|
connect(this, SIGNAL(resumeReplay()), p->getLogfile(), SLOT(resumeReplay()));
|
||||||
|
|
||||||
|
connect(this, SIGNAL(startReplay()), scpPlugin, SLOT(startPlotting()));
|
||||||
|
connect(this, SIGNAL(stopReplay()), scpPlugin, SLOT(stopPlotting()));
|
||||||
|
connect(this, SIGNAL(pauseReplay()), scpPlugin, SLOT(stopPlotting()));
|
||||||
|
connect(this, SIGNAL(resumeReplay()), scpPlugin, SLOT(startPlotting()));
|
||||||
|
|
||||||
|
connect(m_logging->playButton, SIGNAL(clicked()), this, SLOT(playButton()));
|
||||||
|
connect(m_logging->pauseButton, SIGNAL(clicked()), this, SLOT(pauseButton()));
|
||||||
|
connect(m_logging->stopButton, SIGNAL(clicked()), this, SLOT(stopButton()));
|
||||||
|
|
||||||
|
connect(p->getLogfile(), SIGNAL(replayStarted()), this, SLOT(enableButtons()));
|
||||||
|
connect(p->getLogfile(), SIGNAL(replayFinished()), this, SLOT(disableButtons()));
|
||||||
|
connect(p->getLogfile(), SIGNAL(replayFinished()), scpPlugin, SLOT(stopPlotting()));
|
||||||
|
|
||||||
|
connect(m_logging->playbackSpeed, SIGNAL(valueChanged(double)), p->getLogfile(), SLOT(setReplaySpeed(double)));
|
||||||
|
|
||||||
connect(m_logging->playButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::startPlotting);
|
connect(m_logging->playButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::startPlotting);
|
||||||
connect(m_logging->pauseButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::stopPlotting);
|
connect(m_logging->pauseButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::stopPlotting);
|
||||||
|
|
||||||
@ -64,6 +98,46 @@ void LoggingGadgetWidget::setPlugin(LoggingPlugin *p)
|
|||||||
stateChanged(loggingPlugin->getState());
|
stateChanged(loggingPlugin->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::playButton()
|
||||||
|
{
|
||||||
|
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
|
||||||
|
|
||||||
|
if (replayState == STOPPED) {
|
||||||
|
emit startReplay();
|
||||||
|
} else if (replayState == PAUSED) {
|
||||||
|
emit resumeReplay();
|
||||||
|
}
|
||||||
|
m_logging->playButton->setEnabled(false);
|
||||||
|
m_logging->pauseButton->setEnabled(true);
|
||||||
|
m_logging->stopButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::pauseButton()
|
||||||
|
{
|
||||||
|
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
|
||||||
|
|
||||||
|
if (replayState == PLAYING) {
|
||||||
|
emit pauseReplay();
|
||||||
|
}
|
||||||
|
m_logging->playButton->setEnabled(true);
|
||||||
|
m_logging->pauseButton->setEnabled(false);
|
||||||
|
m_logging->stopButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::stopButton()
|
||||||
|
{
|
||||||
|
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
|
||||||
|
|
||||||
|
if (replayState != STOPPED) {
|
||||||
|
emit stopReplay();
|
||||||
|
}
|
||||||
|
m_logging->playButton->setEnabled(true);
|
||||||
|
m_logging->pauseButton->setEnabled(false);
|
||||||
|
m_logging->stopButton->setEnabled(false);
|
||||||
|
|
||||||
|
replayPosition(0);
|
||||||
|
}
|
||||||
|
|
||||||
void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
|
void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
|
||||||
{
|
{
|
||||||
QString status;
|
QString status;
|
||||||
@ -86,8 +160,122 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
|
|||||||
bool playing = loggingPlugin->getLogfile()->isPlaying();
|
bool playing = loggingPlugin->getLogfile()->isPlaying();
|
||||||
m_logging->playButton->setEnabled(enabled && !playing);
|
m_logging->playButton->setEnabled(enabled && !playing);
|
||||||
m_logging->pauseButton->setEnabled(enabled && playing);
|
m_logging->pauseButton->setEnabled(enabled && playing);
|
||||||
|
m_logging->stopButton->setEnabled(enabled && playing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::updateBeginAndEndtimes(quint32 startTimeStamp, quint32 endTimeStamp)
|
||||||
|
{
|
||||||
|
int startSec, startMin, endSec, endMin;
|
||||||
|
|
||||||
|
startSec = (startTimeStamp / 1000) % 60;
|
||||||
|
startMin = startTimeStamp / (60 * 1000);
|
||||||
|
|
||||||
|
endSec = (endTimeStamp / 1000) % 60;
|
||||||
|
endMin = endTimeStamp / (60 * 1000);
|
||||||
|
|
||||||
|
// update start and end labels
|
||||||
|
m_logging->startTimeLabel->setText(QString("%1:%2").arg(startMin, 2, 10, QChar('0')).arg(startSec, 2, 10, QChar('0')));
|
||||||
|
m_logging->endTimeLabel->setText(QString("%1:%2").arg(endMin, 2, 10, QChar('0')).arg(endSec, 2, 10, QChar('0')));
|
||||||
|
|
||||||
|
// Update position bar
|
||||||
|
m_logging->playBackPosition->setMinimum(startTimeStamp);
|
||||||
|
m_logging->playBackPosition->setMaximum(endTimeStamp);
|
||||||
|
|
||||||
|
m_logging->playBackPosition->setSingleStep((endTimeStamp - startTimeStamp) / 100);
|
||||||
|
m_logging->playBackPosition->setPageStep((endTimeStamp - startTimeStamp) / 10);
|
||||||
|
m_logging->playBackPosition->setTickInterval((endTimeStamp - startTimeStamp) / 10);
|
||||||
|
m_logging->playBackPosition->setTickPosition(QSlider::TicksBothSides);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::replayPosition(quint32 positionTimeStamp)
|
||||||
|
{
|
||||||
|
// Update position bar, but only if the user is not updating the slider position
|
||||||
|
if (!m_logging->playBackPosition->isSliderDown() && !sliderActionDelay.isActive()) {
|
||||||
|
// Block signals during slider position update:
|
||||||
|
m_logging->playBackPosition->blockSignals(true);
|
||||||
|
m_logging->playBackPosition->setValue(positionTimeStamp);
|
||||||
|
m_logging->playBackPosition->blockSignals(false);
|
||||||
|
|
||||||
|
// update current position label
|
||||||
|
updatePositionLabel(positionTimeStamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::enableButtons()
|
||||||
|
{
|
||||||
|
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
|
||||||
|
|
||||||
|
switch (replayState)
|
||||||
|
{
|
||||||
|
case STOPPED:
|
||||||
|
m_logging->playButton->setEnabled(true);
|
||||||
|
m_logging->pauseButton->setEnabled(false);
|
||||||
|
m_logging->stopButton->setEnabled(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLAYING:
|
||||||
|
m_logging->playButton->setEnabled(false);
|
||||||
|
m_logging->pauseButton->setEnabled(true);
|
||||||
|
m_logging->stopButton->setEnabled(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PAUSED:
|
||||||
|
m_logging->playButton->setEnabled(true);
|
||||||
|
m_logging->pauseButton->setEnabled(false);
|
||||||
|
m_logging->stopButton->setEnabled(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_logging->playBackPosition->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::disableButtons()
|
||||||
|
{
|
||||||
|
// m_logging->startTimeLabel->setText(QString(""));
|
||||||
|
// m_logging->endTimeLabel->setText(QString(""));
|
||||||
|
|
||||||
|
m_logging->playButton->setEnabled(false);
|
||||||
|
m_logging->pauseButton->setEnabled(false);
|
||||||
|
m_logging->stopButton->setEnabled(false);
|
||||||
|
|
||||||
|
m_logging->playBackPosition->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::sliderMoved(int position)
|
||||||
|
{
|
||||||
|
qDebug() << "sliderMoved(): start of function, stored position was: " << m_storedPosition;
|
||||||
|
|
||||||
|
m_storedPosition = position;
|
||||||
|
// pause
|
||||||
|
emit pauseButton();
|
||||||
|
|
||||||
|
updatePositionLabel(position);
|
||||||
|
|
||||||
|
// Start or restarts a time-out after which replay is resumed from the new position.
|
||||||
|
sliderActionDelay.start();
|
||||||
|
|
||||||
|
qDebug() << "sliderMoved(): end of function, stored position is now: " << m_storedPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::updatePositionLabel(quint32 positionTimeStamp)
|
||||||
|
{
|
||||||
|
// update position timestamp label
|
||||||
|
int sec = (positionTimeStamp / 1000) % 60;
|
||||||
|
int min = positionTimeStamp / (60 * 1000);
|
||||||
|
m_logging->positionTimestampLabel->setText(QString("%1:%2").arg(min, 2, 10, QChar('0')).arg(sec, 2, 10, QChar('0')));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggingGadgetWidget::sendResumeReplayFrom()
|
||||||
|
{
|
||||||
|
qDebug() << "sendResumeReplayFrom(): start of function, stored position is: " << m_storedPosition;
|
||||||
|
|
||||||
|
emit resumeReplayFrom(m_storedPosition);
|
||||||
|
|
||||||
|
emit resumeReplay();
|
||||||
|
|
||||||
|
qDebug() << "sendResumeReplayFrom(): end of function, stored position is: " << m_storedPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
* @}
|
* @}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class Ui_Logging;
|
class Ui_Logging;
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
class LoggingGadgetWidget : public QWidget {
|
class LoggingGadgetWidget : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -48,15 +49,32 @@ public:
|
|||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void stateChanged(LoggingPlugin::State state);
|
void stateChanged(LoggingPlugin::State state);
|
||||||
|
void updateBeginAndEndtimes(quint32 startTimeStamp, quint32 endTimeStamp);
|
||||||
|
void replayPosition(quint32 positionTimeStamp);
|
||||||
|
void playButton();
|
||||||
|
void pauseButton();
|
||||||
|
void stopButton();
|
||||||
|
void enableButtons();
|
||||||
|
void disableButtons();
|
||||||
|
void sliderMoved(int);
|
||||||
|
void sendResumeReplayFrom();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void pause();
|
void startReplay();
|
||||||
void play();
|
void stopReplay();
|
||||||
|
void pauseReplay();
|
||||||
|
void resumeReplay();
|
||||||
|
void resumeReplayFrom(quint32 positionTimeStamp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui_Logging *m_logging;
|
Ui_Logging *m_logging;
|
||||||
LoggingPlugin *loggingPlugin;
|
LoggingPlugin *loggingPlugin;
|
||||||
ScopeGadgetFactory *scpPlugin;
|
ScopeGadgetFactory *scpPlugin;
|
||||||
|
QTimer sliderActionDelay;
|
||||||
|
quint32 m_storedPosition;
|
||||||
|
|
||||||
|
void updatePositionLabel(quint32 positionTimeStamp);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* LoggingGADGETWIDGET_H_ */
|
#endif /* LoggingGADGETWIDGET_H_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user