diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp index 9e4e87ba..b170e245 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp @@ -80,6 +80,17 @@ namespace Bloom::Widgets this->dataBPrimaryLabel->setText("Current"); this->dataASecondaryLabel->setText(snapshotA.createdDate.toString("dd/MM/yyyy hh:mm")); this->dataBSecondaryLabel->setVisible(false); + + this->restoreBytesAction = new ContextMenuAction("Restore Selection", std::nullopt, this); + + QObject::connect( + this->restoreBytesAction, + &ContextMenuAction::invoked, + this, + [this] (const std::unordered_map& selectedByteItemsByAddress) { + this->restoreSelectedBytes(selectedByteItemsByAddress, true); + } + ); } void SnapshotDiff::refreshB( @@ -154,8 +165,6 @@ namespace Bloom::Widgets this->syncHexViewerHoverButton = toolBar->findChild("sync-hover-btn"); this->syncHexViewerSelectionButton = toolBar->findChild("sync-selection-btn"); - this->restoreBytesAction = new ContextMenuAction("Restore Selection", std::nullopt, this); - this->dataAContainer = this->container->findChild("data-a-container"); this->dataBContainer = this->container->findChild("data-b-container"); @@ -203,6 +212,9 @@ namespace Bloom::Widgets this->bottomBar = this->container->findChild("bottom-bar"); this->bottomBarLayout = this->bottomBar->findChild(); + this->taskProgressIndicator = new TaskProgressIndicator(this); + this->bottomBarLayout->insertWidget(0, this->taskProgressIndicator); + this->setSyncHexViewerSettingsEnabled(this->settings.syncHexViewerSettings); this->setSyncHexViewerScrollEnabled(this->settings.syncHexViewerScroll); this->setSyncHexViewerHoverEnabled(this->settings.syncHexViewerHover); @@ -256,7 +268,10 @@ namespace Bloom::Widgets void SnapshotDiff::onHexViewerAReady() { this->hexViewerWidgetB->setOther(this->hexViewerWidgetA); -// this->hexViewerWidgetA->addExternalContextMenuAction(this->restoreBytesAction); + if (this->restoreBytesAction != nullptr) { + this->hexViewerWidgetA->addExternalContextMenuAction(this->restoreBytesAction); + } + if (this->memoryDescriptor.type == Targets::TargetMemoryType::RAM) { this->hexViewerWidgetA->setStackPointer(this->stackPointerA); } @@ -289,4 +304,114 @@ namespace Bloom::Widgets this->settings.syncHexViewerSelection = enabled; this->syncHexViewerSelectionButton->setChecked(this->settings.syncHexViewerSelection); } + + void SnapshotDiff::restoreSelectedBytes( + const std::unordered_map& selectedByteItemsByAddress, + bool confirmationPromptEnabled + ) { + auto sortedByteItemsByAddress = std::map(); + + for (const auto& pair : selectedByteItemsByAddress) { + if (pair.second->excluded) { + continue; + } + + sortedByteItemsByAddress.insert(pair); + } + + if (sortedByteItemsByAddress.empty()) { + // The user has only selected bytes that are within an excluded region - nothing to do here + return; + } + + if (confirmationPromptEnabled) { + auto* confirmationDialog = new ConfirmationDialog( + "Restore selected bytes", + "This operation will write " + QString::number(sortedByteItemsByAddress.size()) + + " byte(s) to the target's " + + QString(this->memoryDescriptor.type == Targets::TargetMemoryType::EEPROM ? "EEPROM" : "RAM") + + ".

Are you sure you want to proceed?", + "Proceed", + std::nullopt, + this + ); + + QObject::connect( + confirmationDialog, + &ConfirmationDialog::confirmed, + this, + [this, selectedByteItemsByAddress] { + this->restoreSelectedBytes(selectedByteItemsByAddress, false); + } + ); + + confirmationDialog->show(); + return; + } + + auto writeBlocks = std::vector(); + + Targets::TargetMemoryAddress blockStartAddress = sortedByteItemsByAddress.begin()->first; + Targets::TargetMemoryAddress blockEndAddress = blockStartAddress; + + for (const auto& [address, byteItem] : sortedByteItemsByAddress) { + if (address > (blockEndAddress + 1)) { + // Commit the block + const auto dataBeginOffset = blockStartAddress - this->memoryDescriptor.addressRange.startAddress; + const auto dataEndOffset = blockEndAddress - this->memoryDescriptor.addressRange.startAddress + 1; + + writeBlocks.emplace_back( + blockStartAddress, + Targets::TargetMemoryBuffer( + this->hexViewerDataA->begin() + dataBeginOffset, + this->hexViewerDataA->begin() + dataEndOffset + ) + ); + + blockStartAddress = address; + blockEndAddress = address; + continue; + } + + blockEndAddress = address; + } + + { + const auto dataBeginOffset = blockStartAddress - this->memoryDescriptor.addressRange.startAddress; + const auto dataEndOffset = blockEndAddress - this->memoryDescriptor.addressRange.startAddress + 1; + + writeBlocks.emplace_back( + blockStartAddress, + Targets::TargetMemoryBuffer( + this->hexViewerDataA->begin() + dataBeginOffset, + this->hexViewerDataA->begin() + dataEndOffset + ) + ); + } + + const auto after = [this, writeBlocks] { + auto& hexViewerDataB = this->hexViewerDataB.value(); + + for (const auto& writeBlock : writeBlocks) { + std::copy( + writeBlock.data.begin(), + writeBlock.data.end(), + hexViewerDataB.begin() + + (writeBlock.startAddress - this->memoryDescriptor.addressRange.startAddress) + ); + } + + this->hexViewerWidgetB->updateValues(); + }; + + const auto writeMemoryTask = QSharedPointer( + new WriteTargetMemory(this->memoryDescriptor, std::move(writeBlocks)), + &QObject::deleteLater + ); + + QObject::connect(writeMemoryTask.get(), &WriteTargetMemory::targetMemoryWritten, this, after); + + this->taskProgressIndicator->addTask(writeMemoryTask); + InsightWorker::queueTask(writeMemoryTask); + } } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp index 1f1e19e3..ff38e124 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp @@ -98,6 +98,8 @@ namespace Bloom::Widgets QWidget* bottomBar = nullptr; QHBoxLayout* bottomBarLayout = nullptr; + TaskProgressIndicator* taskProgressIndicator = nullptr; + void init(); void onHexViewerAReady(); @@ -107,5 +109,10 @@ namespace Bloom::Widgets void setSyncHexViewerScrollEnabled(bool enabled); void setSyncHexViewerHoverEnabled(bool enabled); void setSyncHexViewerSelectionEnabled(bool enabled); + + void restoreSelectedBytes( + const std::unordered_map& selectedByteItemsByAddress, + bool confirmationPromptEnabled + ); }; }