New background tasks window
This commit is contained in:
@@ -39,10 +39,14 @@ target_sources(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/CaptureMemorySnapshot.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/CaptureMemorySnapshot.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/RetrieveMemorySnapshots.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/RetrieveMemorySnapshots.cpp
|
||||||
|
|
||||||
# Task indicator
|
# Task indicators
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TaskProgressIndicator/TaskProgressIndicator.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TaskProgressIndicator/TaskProgressIndicator.cpp
|
||||||
|
|
||||||
|
# Task window
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TaskWindow/TaskWindow.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TaskWindow/Task.cpp
|
||||||
|
|
||||||
# Error dialogue window
|
# Error dialogue window
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp
|
||||||
|
|
||||||
@@ -155,6 +159,10 @@ qt_add_resources(
|
|||||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Images/ascii-view-disabled.svg"
|
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Images/ascii-view-disabled.svg"
|
||||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/Images/new-snapshot-icon.svg"
|
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/Images/new-snapshot-icon.svg"
|
||||||
|
|
||||||
|
# Task window
|
||||||
|
"./UserInterfaces/InsightWindow/Widgets/TaskWindow/UiFiles/TaskWindow.ui"
|
||||||
|
"./UserInterfaces/InsightWindow/Widgets/TaskWindow/Stylesheets/TaskWindow.qss"
|
||||||
|
|
||||||
# Target package widgets
|
# Target package widgets
|
||||||
"./UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss"
|
"./UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss"
|
||||||
"./UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss"
|
"./UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss"
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ namespace Bloom::Widgets
|
|||||||
this->setObjectName("task-indicator");
|
this->setObjectName("task-indicator");
|
||||||
this->setFixedSize(50, 26);
|
this->setFixedSize(50, 26);
|
||||||
|
|
||||||
|
this->taskWindow = new TaskWindow(this);
|
||||||
|
|
||||||
auto* insightSignals = InsightSignals::instance();
|
auto* insightSignals = InsightSignals::instance();
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
@@ -42,6 +44,11 @@ namespace Bloom::Widgets
|
|||||||
this->update();
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TaskIndicator::mousePressEvent(QMouseEvent* event) {
|
||||||
|
this->taskWindow->show();
|
||||||
|
this->taskWindow->activateWindow();
|
||||||
|
}
|
||||||
|
|
||||||
void TaskIndicator::paintEvent(QPaintEvent* event) {
|
void TaskIndicator::paintEvent(QPaintEvent* event) {
|
||||||
auto painter = QPainter(this);
|
auto painter = QPainter(this);
|
||||||
painter.setPen(Qt::PenStyle::NoPen);
|
painter.setPen(Qt::PenStyle::NoPen);
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
#include "src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp"
|
#include "src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp"
|
||||||
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TaskWindow/TaskWindow.hpp"
|
||||||
|
|
||||||
namespace Bloom::Widgets
|
namespace Bloom::Widgets
|
||||||
{
|
{
|
||||||
@@ -19,12 +21,15 @@ namespace Bloom::Widgets
|
|||||||
protected:
|
protected:
|
||||||
void enterEvent(QEnterEvent* event) override;
|
void enterEvent(QEnterEvent* event) override;
|
||||||
void leaveEvent(QEvent* event) override;
|
void leaveEvent(QEvent* event) override;
|
||||||
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<InsightWorkerTask::IdType, QSharedPointer<InsightWorkerTask>> activeTasksById;
|
std::unordered_map<InsightWorkerTask::IdType, QSharedPointer<InsightWorkerTask>> activeTasksById;
|
||||||
bool hovered = false;
|
bool hovered = false;
|
||||||
|
|
||||||
|
TaskWindow* taskWindow = nullptr;
|
||||||
|
|
||||||
void onTaskQueued(QSharedPointer<InsightWorkerTask> task);
|
void onTaskQueued(QSharedPointer<InsightWorkerTask> task);
|
||||||
void onTaskFinished(QSharedPointer<InsightWorkerTask> task);
|
void onTaskFinished(QSharedPointer<InsightWorkerTask> task);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#task-window,
|
||||||
|
#task-window #container {
|
||||||
|
background-color: #373835;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loading-placeholder-label {
|
||||||
|
color: #737375;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
#include "Task.hpp"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
namespace Bloom::Widgets
|
||||||
|
{
|
||||||
|
Task::Task(
|
||||||
|
const QSharedPointer<InsightWorkerTask>& task,
|
||||||
|
QWidget* parent
|
||||||
|
)
|
||||||
|
: QWidget(parent)
|
||||||
|
, task(task)
|
||||||
|
{
|
||||||
|
this->setObjectName("task");
|
||||||
|
this->setFixedHeight(80);
|
||||||
|
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
this->setContentsMargins(15, 0, 15, 0);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->task.get(),
|
||||||
|
&InsightWorkerTask::started,
|
||||||
|
this,
|
||||||
|
&Task::onTaskStateChanged
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->task.get(),
|
||||||
|
&InsightWorkerTask::finished,
|
||||||
|
this,
|
||||||
|
&Task::onTaskStateChanged
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->task.get(),
|
||||||
|
&InsightWorkerTask::failed,
|
||||||
|
this,
|
||||||
|
&Task::onTaskStateChanged
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->task.get(),
|
||||||
|
&InsightWorkerTask::finished,
|
||||||
|
this,
|
||||||
|
&Task::onTaskFinished
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->task.get(),
|
||||||
|
&InsightWorkerTask::progressUpdate,
|
||||||
|
this,
|
||||||
|
&Task::onTaskProgressUpdate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Task::paintEvent(QPaintEvent* event) {
|
||||||
|
auto painter = QPainter(this);
|
||||||
|
|
||||||
|
const auto margins = this->contentsMargins();
|
||||||
|
const auto size = this->size();
|
||||||
|
|
||||||
|
static constexpr auto backgroundBarColor = QColor(0x8E, 0x8B, 0x83, 40);
|
||||||
|
static constexpr auto barColor = QColor(0x8E, 0x8B, 0x83, 90);
|
||||||
|
static constexpr auto fontColor = QColor(0x99, 0x9a, 0x9d);
|
||||||
|
static constexpr auto statusFontColor = QColor(0x99, 0x9a, 0x9d, 200);
|
||||||
|
|
||||||
|
static auto font = QFont("'Ubuntu', sans-serif");
|
||||||
|
font.setPixelSize(14);
|
||||||
|
|
||||||
|
static auto statusFont = QFont("'Ubuntu', sans-serif");
|
||||||
|
statusFont.setPixelSize(12);
|
||||||
|
|
||||||
|
painter.setFont(font);
|
||||||
|
painter.setPen(fontColor);
|
||||||
|
|
||||||
|
static constexpr auto barHeight = 5;
|
||||||
|
const auto barYPosition = 35;
|
||||||
|
|
||||||
|
painter.drawText(
|
||||||
|
margins.left(),
|
||||||
|
barYPosition - 12,
|
||||||
|
this->task->brief()
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto status = QString(
|
||||||
|
this->task->state == InsightWorkerTaskState::FAILED
|
||||||
|
? "Failed"
|
||||||
|
: this->task->state == InsightWorkerTaskState::COMPLETED
|
||||||
|
? "Completed"
|
||||||
|
: this->task->state == InsightWorkerTaskState::STARTED
|
||||||
|
? "Running"
|
||||||
|
: "Queued"
|
||||||
|
);
|
||||||
|
|
||||||
|
painter.setFont(statusFont);
|
||||||
|
painter.setPen(statusFontColor);
|
||||||
|
painter.drawText(
|
||||||
|
margins.left(),
|
||||||
|
barYPosition + barHeight + 20,
|
||||||
|
status
|
||||||
|
);
|
||||||
|
|
||||||
|
painter.setPen(Qt::PenStyle::NoPen);
|
||||||
|
painter.setBrush(backgroundBarColor);
|
||||||
|
|
||||||
|
painter.drawRect(
|
||||||
|
margins.left(),
|
||||||
|
barYPosition,
|
||||||
|
size.width() - margins.left() - margins.right(),
|
||||||
|
barHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
painter.setBrush(barColor);
|
||||||
|
|
||||||
|
painter.drawRect(
|
||||||
|
margins.left(),
|
||||||
|
barYPosition,
|
||||||
|
static_cast<int>(
|
||||||
|
static_cast<float>(size.width() - margins.left() - margins.right())
|
||||||
|
* (static_cast<float>(this->task->progressPercentage) / 100)
|
||||||
|
),
|
||||||
|
barHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
painter.setPen(backgroundBarColor);
|
||||||
|
|
||||||
|
painter.drawLine(
|
||||||
|
0,
|
||||||
|
size.height() - 1,
|
||||||
|
size.width(),
|
||||||
|
size.height() - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Task::onTaskProgressUpdate() {
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Task::onTaskStateChanged() {
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Task::onTaskFinished() {
|
||||||
|
emit this->taskComplete(this->task->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
|
#include "src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::Widgets
|
||||||
|
{
|
||||||
|
class Task: public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Task(const QSharedPointer<InsightWorkerTask>& task, QWidget* parent);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void taskComplete(InsightWorkerTask::IdType taskId);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSharedPointer<InsightWorkerTask> task;
|
||||||
|
|
||||||
|
void onTaskProgressUpdate();
|
||||||
|
void onTaskStateChanged();
|
||||||
|
void onTaskFinished();
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#include "TaskWindow.hpp"
|
||||||
|
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
||||||
|
|
||||||
|
#include "src/Insight/InsightSignals.hpp"
|
||||||
|
|
||||||
|
#include "src/Services/PathService.hpp"
|
||||||
|
#include "src/Exceptions/Exception.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::Widgets
|
||||||
|
{
|
||||||
|
TaskWindow::TaskWindow(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
this->setObjectName("task-window");
|
||||||
|
this->setMinimumSize(900, 500);
|
||||||
|
|
||||||
|
this->setWindowFlag(Qt::Window);
|
||||||
|
this->setWindowTitle("Background Tasks");
|
||||||
|
|
||||||
|
auto windowUiFile = QFile(
|
||||||
|
QString::fromStdString(Services::PathService::compiledResourcesPath()
|
||||||
|
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskWindow/UiFiles/TaskWindow.ui"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto stylesheetFile = QFile(
|
||||||
|
QString::fromStdString(Services::PathService::compiledResourcesPath()
|
||||||
|
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskWindow/Stylesheets/TaskWindow.qss"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!windowUiFile.open(QFile::ReadOnly)) {
|
||||||
|
throw Exceptions::Exception("Failed to open TaskWindow UI file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stylesheetFile.open(QFile::ReadOnly)) {
|
||||||
|
throw Exceptions::Exception("Failed to open TaskWindow stylesheet file");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto uiLoader = UiLoader(this);
|
||||||
|
this->container = uiLoader.load(&windowUiFile, this);
|
||||||
|
this->container->setStyleSheet(stylesheetFile.readAll());
|
||||||
|
|
||||||
|
this->container->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
this->taskWidgetLayout = this->container->findChild<QVBoxLayout*>();
|
||||||
|
this->taskPlaceholderLabel = this->container->findChild<Label*>("loading-placeholder-label");
|
||||||
|
|
||||||
|
auto* insightSignals = InsightSignals::instance();
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
insightSignals,
|
||||||
|
&InsightSignals::taskQueued,
|
||||||
|
this,
|
||||||
|
&TaskWindow::onTaskQueued
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskWindow::resizeEvent(QResizeEvent* event) {
|
||||||
|
this->container->setFixedSize(this->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskWindow::onTaskQueued(const QSharedPointer<InsightWorkerTask>& task) {
|
||||||
|
auto* taskWidget = new Task(task, this);
|
||||||
|
this->taskWidgetLayout->insertWidget(0, taskWidget);
|
||||||
|
|
||||||
|
QObject::connect(taskWidget, &Task::taskComplete, this, [this] (InsightWorkerTask::IdType taskId) {
|
||||||
|
auto* finishedSignalTimer = new QTimer();
|
||||||
|
finishedSignalTimer->setSingleShot(true);
|
||||||
|
finishedSignalTimer->setInterval(10000);
|
||||||
|
|
||||||
|
QObject::connect(finishedSignalTimer, &QTimer::timeout, this, [this, taskId] {
|
||||||
|
const auto& taskWidgetIt = this->taskWidgetsByTaskId.find(taskId);
|
||||||
|
|
||||||
|
if (taskWidgetIt == this->taskWidgetsByTaskId.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* taskWidget = taskWidgetIt->second;
|
||||||
|
this->taskWidgetLayout->removeWidget(taskWidget);
|
||||||
|
taskWidget->deleteLater();
|
||||||
|
this->taskWidgetsByTaskId.erase(taskWidgetIt);
|
||||||
|
|
||||||
|
if (this->taskWidgetsByTaskId.empty()) {
|
||||||
|
this->taskPlaceholderLabel->show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
finishedSignalTimer->start();
|
||||||
|
});
|
||||||
|
|
||||||
|
this->taskWidgetsByTaskId.emplace(task->id, taskWidget);
|
||||||
|
|
||||||
|
this->taskPlaceholderLabel->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
|
#include "Task.hpp"
|
||||||
|
|
||||||
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/Label.hpp"
|
||||||
|
#include "src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::Widgets
|
||||||
|
{
|
||||||
|
class TaskWindow: public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TaskWindow(QWidget* parent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget* container = nullptr;
|
||||||
|
QVBoxLayout* taskWidgetLayout = nullptr;
|
||||||
|
|
||||||
|
Label* taskPlaceholderLabel = nullptr;
|
||||||
|
|
||||||
|
std::unordered_map<InsightWorkerTask::IdType, Task*> taskWidgetsByTaskId;
|
||||||
|
|
||||||
|
void onTaskQueued(const QSharedPointer<InsightWorkerTask>& task);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<widget class="QScrollArea" name="container">
|
||||||
|
<property name="widgetResizable"><bool>true</bool></property>
|
||||||
|
<property name="verticalScrollBarPolicy"><enum>Qt::ScrollBarAsNeeded</enum></property>
|
||||||
|
<property name="sizeAdjustPolicy"><enum>QAbstractScrollArea::AdjustToContents</enum></property>
|
||||||
|
<property name="horizontalScrollBarPolicy"><enum>Qt::ScrollBarAlwaysOff</enum></property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="item-container">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="item-container-layout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||||
|
</property>
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="Label" name="loading-placeholder-label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<enum>Qt::AlignCenter</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>No background tasks</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user