Implemented restore snapshot function
This commit is contained in:
@@ -97,6 +97,7 @@ target_sources(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressContainer.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressContainer.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressItem.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressItem.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ContextMenuAction.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemoryRegion.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemoryRegion.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/FocusedMemoryRegion.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/FocusedMemoryRegion.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/ExcludedMemoryRegion.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/ExcludedMemoryRegion.cpp
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
#include "SnapshotManager.hpp"
|
#include "SnapshotManager.hpp"
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
#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/RetrieveMemorySnapshots.hpp"
|
||||||
|
#include "src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.hpp"
|
||||||
|
#include "src/Insight/InsightWorker/Tasks/WriteTargetMemory.hpp"
|
||||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||||
|
|
||||||
#include "src/Services/PathService.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>(
|
const auto retrieveSnapshotsTask = QSharedPointer<RetrieveMemorySnapshots>(
|
||||||
new RetrieveMemorySnapshots(this->memoryDescriptor.type),
|
new RetrieveMemorySnapshots(this->memoryDescriptor.type),
|
||||||
&QObject::deleteLater
|
&QObject::deleteLater
|
||||||
@@ -190,4 +222,122 @@ namespace Bloom::Widgets
|
|||||||
|
|
||||||
this->selectedItem = item;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PaneWidget.hpp"
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PaneWidget.hpp"
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp"
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp"
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListView.hpp"
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListView.hpp"
|
||||||
|
|
||||||
|
#include "src/Targets/TargetState.hpp"
|
||||||
#include "src/Targets/TargetMemory.hpp"
|
#include "src/Targets/TargetMemory.hpp"
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp"
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp"
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/FocusedMemoryRegion.hpp"
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/FocusedMemoryRegion.hpp"
|
||||||
@@ -43,6 +45,7 @@ namespace Bloom::Widgets
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void insightWorkerTaskCreated(const QSharedPointer<InsightWorkerTask>& task);
|
void insightWorkerTaskCreated(const QSharedPointer<InsightWorkerTask>& task);
|
||||||
|
void snapshotRestored(const QString& snapshotId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
@@ -56,6 +59,8 @@ namespace Bloom::Widgets
|
|||||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions;
|
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions;
|
||||||
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions;
|
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions;
|
||||||
|
|
||||||
|
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
|
||||||
|
|
||||||
QMap<QString, MemorySnapshot> snapshotsById;
|
QMap<QString, MemorySnapshot> snapshotsById;
|
||||||
QMap<QString, MemorySnapshotItem*> snapshotItemsById;
|
QMap<QString, MemorySnapshotItem*> snapshotItemsById;
|
||||||
|
|
||||||
@@ -68,6 +73,11 @@ namespace Bloom::Widgets
|
|||||||
ListView* snapshotListView = nullptr;
|
ListView* snapshotListView = nullptr;
|
||||||
ListScene* snapshotListScene = nullptr;
|
ListScene* snapshotListScene = nullptr;
|
||||||
|
|
||||||
|
MemorySnapshotItem* contextMenuSnapshotItem = nullptr;
|
||||||
|
|
||||||
|
QAction* deleteSnapshotAction = new QAction("Delete", this);
|
||||||
|
QAction* restoreSnapshotAction = new QAction("Restore", this);
|
||||||
|
|
||||||
void createSnapshot(
|
void createSnapshot(
|
||||||
const QString& name,
|
const QString& name,
|
||||||
const QString& description,
|
const QString& description,
|
||||||
@@ -76,5 +86,8 @@ namespace Bloom::Widgets
|
|||||||
);
|
);
|
||||||
void addSnapshot(MemorySnapshot&& snapshotTmp);
|
void addSnapshot(MemorySnapshot&& snapshotTmp);
|
||||||
void onSnapshotItemSelected(MemorySnapshotItem* item);
|
void onSnapshotItemSelected(MemorySnapshotItem* item);
|
||||||
|
void restoreSnapshot(const QString& snapshotId, bool confirmationPromptEnabled);
|
||||||
|
void onSnapshotItemContextMenu(ListItem* item, QPoint sourcePosition);
|
||||||
|
void onTargetStateChanged(Targets::TargetState newState);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,6 +203,12 @@ namespace Bloom::Widgets
|
|||||||
this,
|
this,
|
||||||
&TargetMemoryInspectionPane::onSubtaskCreated
|
&TargetMemoryInspectionPane::onSubtaskCreated
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->snapshotManager,
|
||||||
|
&SnapshotManager::snapshotRestored,
|
||||||
|
this,
|
||||||
|
&TargetMemoryInspectionPane::onSnapshotRestored
|
||||||
);
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
@@ -637,6 +643,10 @@ namespace Bloom::Widgets
|
|||||||
this->taskProgressIndicator->addTask(task);
|
this->taskProgressIndicator->addTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TargetMemoryInspectionPane::onSnapshotRestored(const QString& snapshotId) {
|
||||||
|
this->refreshButton->click();
|
||||||
|
}
|
||||||
|
|
||||||
void TargetMemoryInspectionPane::setStaleData(bool staleData) {
|
void TargetMemoryInspectionPane::setStaleData(bool staleData) {
|
||||||
this->staleData = staleData;
|
this->staleData = staleData;
|
||||||
this->staleDataLabelContainer->setVisible(this->staleData);
|
this->staleDataLabelContainer->setVisible(this->staleData);
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ namespace Bloom::Widgets
|
|||||||
Targets::TargetMemoryAddressRange addressRange
|
Targets::TargetMemoryAddressRange addressRange
|
||||||
);
|
);
|
||||||
void onSubtaskCreated(const QSharedPointer<InsightWorkerTask>& task);
|
void onSubtaskCreated(const QSharedPointer<InsightWorkerTask>& task);
|
||||||
|
void onSnapshotRestored(const QString& snapshotId);
|
||||||
void setStaleData(bool staleData);
|
void setStaleData(bool staleData);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user