Implemented restore snapshot function

This commit is contained in:
Nav
2023-04-12 22:47:11 +01:00
parent 54b766b0e7
commit 694ba6385b
5 changed files with 176 additions and 1 deletions

View File

@@ -1,11 +1,15 @@
#include "SnapshotManager.hpp"
#include <QDesktopServices>
#include <algorithm>
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ConfirmationDialog.hpp"
#include "src/Insight/InsightSignals.hpp"
#include "src/Insight/InsightWorker/Tasks/RetrieveMemorySnapshots.hpp"
#include "src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.hpp"
#include "src/Insight/InsightWorker/Tasks/WriteTargetMemory.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
#include "src/Services/PathService.hpp"
@@ -96,6 +100,34 @@ namespace Bloom::Widgets
}
);
QObject::connect(
this->snapshotListScene,
&ListScene::itemContextMenu,
this,
&SnapshotManager::onSnapshotItemContextMenu
);
QObject::connect(
this->restoreSnapshotAction,
&QAction::triggered,
this,
[this] {
if (this->contextMenuSnapshotItem != nullptr) {
this->restoreSnapshot(this->contextMenuSnapshotItem->memorySnapshot.id, true);
}
}
);
auto* insightSignals = InsightSignals::instance();
QObject::connect(
insightSignals,
&InsightSignals::targetStateUpdated,
this,
&SnapshotManager::onTargetStateChanged
);
const auto retrieveSnapshotsTask = QSharedPointer<RetrieveMemorySnapshots>(
new RetrieveMemorySnapshots(this->memoryDescriptor.type),
&QObject::deleteLater
@@ -190,4 +222,122 @@ namespace Bloom::Widgets
this->selectedItem = item;
}
void SnapshotManager::restoreSnapshot(const QString& snapshotId, bool confirmationPromptEnabled) {
const auto& snapshotIt = this->snapshotsById.find(snapshotId);
assert(snapshotIt != this->snapshotsById.end());
const auto& snapshot = snapshotIt.value();
if (confirmationPromptEnabled) {
auto* confirmationDialog = new ConfirmationDialog(
"Restore snapshot",
"This operation will overwrite the entire address range of the target's "
+ QString(this->memoryDescriptor.type == Targets::TargetMemoryType::EEPROM ? "EEPROM" : "RAM")
+ " with the contents of the selected snapshot.<br/><br/>Do you wish to proceed?",
"Proceed",
std::nullopt,
this
);
QObject::connect(
confirmationDialog,
&ConfirmationDialog::confirmed,
this,
[this, snapshotId] {
this->restoreSnapshot(snapshotId, false);
}
);
confirmationDialog->show();
return;
}
/*
* We don't restore any excluded regions from the snapshot, so we split the write operation into blocks of
* contiguous data, leaving out any address range that is part of an excluded region.
*/
auto writeBlocks = std::vector<WriteTargetMemory::Block>();
auto sortedExcludedRegions = std::map<Targets::TargetMemoryAddress, const ExcludedMemoryRegion*>();
std::transform(
snapshot.excludedRegions.begin(),
snapshot.excludedRegions.end(),
std::inserter(sortedExcludedRegions, sortedExcludedRegions.end()),
[] (const ExcludedMemoryRegion& excludedMemoryRegion) {
return std::pair(excludedMemoryRegion.addressRange.startAddress, &excludedMemoryRegion);
}
);
auto blockStartAddress = this->memoryDescriptor.addressRange.startAddress;
for (const auto& [excludedRegionStartAddress, excludedRegion] : sortedExcludedRegions) {
assert(excludedRegionStartAddress >= this->memoryDescriptor.addressRange.startAddress);
assert(excludedRegion->addressRange.endAddress <= this->memoryDescriptor.addressRange.endAddress);
const auto dataBeginOffset = blockStartAddress - this->memoryDescriptor.addressRange.startAddress;
const auto dataEndOffset = excludedRegionStartAddress - this->memoryDescriptor.addressRange.startAddress;
writeBlocks.emplace_back(
blockStartAddress,
Targets::TargetMemoryBuffer(
snapshot.data.begin() + dataBeginOffset,
snapshot.data.begin() + dataEndOffset
)
);
blockStartAddress = excludedRegion->addressRange.endAddress + 1;
}
if (blockStartAddress < this->memoryDescriptor.addressRange.endAddress) {
writeBlocks.emplace_back(
blockStartAddress,
Targets::TargetMemoryBuffer(
snapshot.data.begin() + (blockStartAddress - this->memoryDescriptor.addressRange.startAddress),
snapshot.data.end()
)
);
}
const auto writeMemoryTask = QSharedPointer<WriteTargetMemory>(
new WriteTargetMemory(this->memoryDescriptor, std::move(writeBlocks)),
&QObject::deleteLater
);
QObject::connect(
writeMemoryTask.get(),
&WriteTargetMemory::targetMemoryWritten,
this,
[this, snapshotId] () {
emit this->snapshotRestored(snapshotId);
}
);
emit this->insightWorkerTaskCreated(writeMemoryTask);
InsightWorker::queueTask(writeMemoryTask);
}
void SnapshotManager::onSnapshotItemContextMenu(ListItem *item, QPoint sourcePosition) {
auto* snapshotItem = dynamic_cast<MemorySnapshotItem*>(item);
if (snapshotItem == nullptr) {
return;
}
this->contextMenuSnapshotItem = snapshotItem;
auto* menu = new QMenu(this);
menu->addAction(this->deleteSnapshotAction);
menu->addSeparator();
menu->addAction(this->restoreSnapshotAction);
this->restoreSnapshotAction->setEnabled(this->targetState == Targets::TargetState::STOPPED);
menu->exec(sourcePosition);
}
void SnapshotManager::onTargetStateChanged(Targets::TargetState newState) {
this->targetState = newState;
}
}

View File

@@ -6,11 +6,13 @@
#include <QShowEvent>
#include <QVBoxLayout>
#include <QMap>
#include <QAction>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PaneWidget.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListView.hpp"
#include "src/Targets/TargetState.hpp"
#include "src/Targets/TargetMemory.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/FocusedMemoryRegion.hpp"
@@ -43,6 +45,7 @@ namespace Bloom::Widgets
signals:
void insightWorkerTaskCreated(const QSharedPointer<InsightWorkerTask>& task);
void snapshotRestored(const QString& snapshotId);
protected:
void resizeEvent(QResizeEvent* event) override;
@@ -56,6 +59,8 @@ namespace Bloom::Widgets
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions;
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions;
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
QMap<QString, MemorySnapshot> snapshotsById;
QMap<QString, MemorySnapshotItem*> snapshotItemsById;
@@ -68,6 +73,11 @@ namespace Bloom::Widgets
ListView* snapshotListView = nullptr;
ListScene* snapshotListScene = nullptr;
MemorySnapshotItem* contextMenuSnapshotItem = nullptr;
QAction* deleteSnapshotAction = new QAction("Delete", this);
QAction* restoreSnapshotAction = new QAction("Restore", this);
void createSnapshot(
const QString& name,
const QString& description,
@@ -76,5 +86,8 @@ namespace Bloom::Widgets
);
void addSnapshot(MemorySnapshot&& snapshotTmp);
void onSnapshotItemSelected(MemorySnapshotItem* item);
void restoreSnapshot(const QString& snapshotId, bool confirmationPromptEnabled);
void onSnapshotItemContextMenu(ListItem* item, QPoint sourcePosition);
void onTargetStateChanged(Targets::TargetState newState);
};
}

View File

@@ -203,6 +203,12 @@ namespace Bloom::Widgets
this,
&TargetMemoryInspectionPane::onSubtaskCreated
);
QObject::connect(
this->snapshotManager,
&SnapshotManager::snapshotRestored,
this,
&TargetMemoryInspectionPane::onSnapshotRestored
);
QObject::connect(
@@ -637,6 +643,10 @@ namespace Bloom::Widgets
this->taskProgressIndicator->addTask(task);
}
void TargetMemoryInspectionPane::onSnapshotRestored(const QString& snapshotId) {
this->refreshButton->click();
}
void TargetMemoryInspectionPane::setStaleData(bool staleData) {
this->staleData = staleData;
this->staleDataLabelContainer->setVisible(this->staleData);

View File

@@ -105,6 +105,7 @@ namespace Bloom::Widgets
Targets::TargetMemoryAddressRange addressRange
);
void onSubtaskCreated(const QSharedPointer<InsightWorkerTask>& task);
void onSnapshotRestored(const QString& snapshotId);
void setStaleData(bool staleData);
};
}