Implement queueing of status messages
MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -123,7 +123,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
connect(&name##StatusManager::get().emitter, &StatusEmitter::statusChanged, name##StatusLabel, &QLabel::setText); \
connect(&name##StatusManager::get().emitter, &StatusEmitter::clear, name##StatusLabel, &QLabel::clear);
-#define setupPermanentStatusWidget(name) _setupStatusWidget(name, Permanent)
+#define setupPermanentStatusWidget(name) \
+ _setupStatusWidget(name, Permanent); \
+ name##StatusManager::get().setPermanent();
#define setupStatusWidget(name) _setupStatusWidget(name, )
@@ -136,7 +138,7 @@ void MainWindow::setupStatusBar() {
const auto& desc = ProcessorRegistry::getDescription(ProcessorHandler::getID());
QString status =
"Processor: " + desc.name + " ISA: " + ProcessorHandler::getProcessor()->implementsISA()->name();
- ProcessorInfoStatusManager::get().setStatus(status);
+ ProcessorInfoStatusManager::get().setStatusPermanent(status);
};
connect(ProcessorHandler::get(), &ProcessorHandler::processorChanged, updateProcessorInfo);
updateProcessorInfo();
@@ -358,7 +360,7 @@ void MainWindow::saveFilesTriggered() {
}
if (didSave) {
- GeneralStatusManager::setStatusTimed("Saved files " + savedFiles.join(", "), 2000);
+ GeneralStatusManager::setStatusTimed("Saved files " + savedFiles.join(", "), 1000);
}
}

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -154,7 +154,7 @@ void ProcessorHandler::_clock() {
}
void ProcessorHandler::_run() {
- ProcessorStatusManager::setStatus("Running...");
+ ProcessorStatusManager::setStatusTimed("Running...");
emit runStarted();
// Start running through the VSRTL Widget interface

MODIFY
src/statusmanager.h
src/statusmanager.h
#include <QObject>
#include <QString>
+#include <QStringList>
#include <QTimer>
+#include <memory>
namespace Ripes {
class StatusEmitter : public QObject {
Q_OBJECT
public:
- void setStatus(const QString& s) { emit statusChanged(s); }
+ void setStatus(const QString& s) {
+ // Ensure that status messages are not multiline - this will expand the bottom status bar in the main window,
+ // which we don't want.
+ QString singleLineStatus = s;
+ singleLineStatus.replace("\n", " ");
+ emit statusChanged(singleLineStatus);
+ }
void clearStatus() { emit clear(); }
signals:
@@ -20,35 +28,79 @@ signals:
#define UniqueType(name) \
struct NamedTypeUniquer__##name {};
+/**
+ * @brief StatusManager
+ * Defines a singleton class which may be used to send or clear a message to a specific label within the main window
+ * status bar. Each status manager is a singleton based on the status manager name.
+ */
template <typename T>
class StatusManagerBase {
+ struct TimedMessage {
+ int time = -1;
+ QString message;
+ };
+
public:
static StatusManagerBase& get() {
static StatusManagerBase s;
return s;
}
- static void setStatus(const QString& s) { get().emitter.setStatus(s); }
- static void setStatusTimed(const QString& s, int ms = 2000) {
- setStatus(s);
- get().m_timer.start(ms);
+ static void setPermanent() { get().isPermanent = true; }
+
+ static void setStatusPermanent(const QString& s) {
+ auto& me = get();
+ assert(me.isPermanent);
+ clearStatus();
+ me.statusQueue.insert(0, TimedMessage());
+ auto& message = me.statusQueue[0];
+ message.message = s;
+ me.emitCurrentStatus();
+ }
+
+ // Pushes a message to the message queue of this status manager. If ms is set and >0, the message will be removed
+ // after ms milliseconds.
+ static void setStatusTimed(const QString& s, int ms = 1000) {
+ auto& me = get();
+ assert(!me.isPermanent && "Cannot set timed messages on permanent status managers.");
+ me.statusQueue.insert(0, TimedMessage());
+ auto& message = me.statusQueue[0];
+ message.message = s;
+ message.time = ms;
+ me.emitCurrentStatus();
+ }
+
+ static void clearStatus() {
+ auto& me = get();
+ if (!me.statusQueue.empty())
+ me.statusQueue.pop_back();
+ if (!me.statusQueue.empty())
+ me.emitCurrentStatus();
+ else
+ me.emitter.clearStatus();
}
- static void clearStatus() { get().emitter.clearStatus(); }
StatusEmitter emitter;
private:
+ void emitCurrentStatus() {
+ if (m_timer.isActive())
+ return;
+ auto& curMsg = statusQueue.back();
+ emitter.setStatus(curMsg.message);
+ if (curMsg.time > 0)
+ m_timer.start(curMsg.time);
+ }
StatusManagerBase() {
m_timer.setSingleShot(true);
m_timer.connect(&m_timer, &QTimer::timeout, [this] { this->clearStatus(); });
}
QTimer m_timer;
+ QList<TimedMessage> statusQueue;
+
+ // If true, does not allow timed status messages and disables the status queue.
+ bool isPermanent;
};
-/**
- * @brief StatusManager
- * Defines a singleton class which may be used to send or clear a message to a specific label within the main window
- * status bar. Each status manager is a singleton based on the status manager name.
- */
#define StatusManager(name) \
using name##TypeUniquer = UniqueType(name); \
using name##StatusManager = StatusManagerBase<name##TypeUniquer>;

MODIFY
src/syscall/ripes_syscall.cpp
src/syscall/ripes_syscall.cpp
@@ -16,7 +16,7 @@ bool SyscallManager::execute(SyscallID id) {
return false;
} else {
const auto& syscall = m_syscalls.at(id);
- SyscallStatusManager::setStatus("Handling system call: " + syscall->name() + " (" + QString::number(id) + ")");
+ SyscallStatusManager::setStatusTimed("Handling system call: " + syscall->name() + " (" + QString::number(id) + ")");
syscall->execute();
SyscallStatusManager::clearStatus();
return true;

MODIFY
src/syscall/systemio.h
src/syscall/systemio.h
@@ -324,7 +324,7 @@ public:
auto& InputStream = FileIOData::getStreamInUse(fd);
if (fd == STDIN) {
- SystemIOStatusManager::setStatus("Waiting for user input...");
+ SystemIOStatusManager::setStatusTimed("Waiting for user input...");
while (myBuffer.size() == 0) {
// Lock the stdio objects and try to read from stdio. If no data is present, wait until so.
FileIOData::s_stdioMutex.lock();

Implement queueing of status messages