diff --git a/install/ui/mergecontroldialog.fbp b/install/ui/mergecontroldialog.fbp index 81c87fda14..5ba9feaf9b 100644 --- a/install/ui/mergecontroldialog.fbp +++ b/install/ui/mergecontroldialog.fbp @@ -2143,7 +2143,7 @@ 1 1 - ,93,90,-1,70,0 + ,90,90,-1,70,0 0 0 wxID_ANY @@ -2165,7 +2165,7 @@ Resizable 1 - -1,40 + -1,55 ; ; forward_declare 0 @@ -2176,6 +2176,161 @@ 280 + + 0 + wxEXPAND + 1 + + + bSizer272 + wxHORIZONTAL + none + + 6 + wxRIGHT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Accept this change + + 0 + + 0 + + + 0 + + 1 + ResolveAcceptButton + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 0 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Reject this change + + 0 + + 0 + + + 0 + + 1 + ResolveRejectButton + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + diff --git a/install/ui/mergecontroldialog.xrc b/install/ui/mergecontroldialog.xrc index c2fdf01edd..0726aa6ade 100644 --- a/install/ui/mergecontroldialog.xrc +++ b/install/ui/mergecontroldialog.xrc @@ -437,9 +437,9 @@ wxALL 5 - -1,40 + -1,55 - + normal 0 @@ -447,6 +447,36 @@ 280 + + + wxEXPAND + 0 + + wxHORIZONTAL + + + wxRIGHT + 6 + + + 0 + 0 + + + + + + wxALL + 0 + + + 0 + 0 + + + + + diff --git a/radiant/ui/einspector/EntityInspector.cpp b/radiant/ui/einspector/EntityInspector.cpp index f48abc04b8..dc3a822564 100644 --- a/radiant/ui/einspector/EntityInspector.cpp +++ b/radiant/ui/einspector/EntityInspector.cpp @@ -1539,6 +1539,22 @@ void EntityInspector::changeSelectedEntity(const scene::INodePtr& newEntity, con } } +void EntityInspector::handleKeyValueMergeAction(const scene::merge::IEntityKeyValueMergeAction::Ptr& mergeAction) +{ + // Remember this action in the map, it will be used in onKeyChange() + _mergeActions[mergeAction->getKey()] = mergeAction; + + auto selectedEntity = _selectedEntity.lock(); + + // Keys added by a merge operation won't be handled in onKeyChange(), so do this here + if (mergeAction->getType() == scene::merge::ActionType::AddKeyValue || + (mergeAction->getType() == scene::merge::ActionType::ChangeKeyValue && selectedEntity && + Node_getEntity(selectedEntity)->getKeyValue(mergeAction->getKey()).empty())) + { + onKeyChange(mergeAction->getKey(), mergeAction->getValue()); + } +} + void EntityInspector::handleMergeActions(const scene::INodePtr& selectedNode) { // Any possible merge actions go in first @@ -1560,14 +1576,7 @@ void EntityInspector::handleMergeActions(const scene::INodePtr& selectedNode) if (entityKeyValueAction) { - // Remember this action in the map, it will be used in onKeyChange() - _mergeActions[entityKeyValueAction->getKey()] = entityKeyValueAction; - - // Keys added by a merge operation won't be handled in onKeyChange(), so do this here - if (entityKeyValueAction->getType() == scene::merge::ActionType::AddKeyValue) - { - onKeyChange(entityKeyValueAction->getKey(), entityKeyValueAction->getValue()); - } + handleKeyValueMergeAction(entityKeyValueAction); } auto conflictAction = std::dynamic_pointer_cast(action); @@ -1582,8 +1591,7 @@ void EntityInspector::handleMergeActions(const scene::INodePtr& selectedNode) if (sourceAction) { - // The source action will be rendered as change - _mergeActions[sourceAction->getKey()] = sourceAction; + handleKeyValueMergeAction(sourceAction); // Remember the conflict action if it's not yet resolved if (conflictIsUnresolved) diff --git a/radiant/ui/einspector/EntityInspector.h b/radiant/ui/einspector/EntityInspector.h index bd5da0be84..4c1b9d4723 100644 --- a/radiant/ui/einspector/EntityInspector.h +++ b/radiant/ui/einspector/EntityInspector.h @@ -215,6 +215,7 @@ class EntityInspector : void changeSelectedEntity(const scene::INodePtr& newEntity, const scene::INodePtr& selectedNode); void handleMergeActions(const scene::INodePtr& selectedNode); + void handleKeyValueMergeAction(const scene::merge::IEntityKeyValueMergeAction::Ptr& mergeAction); // Set the keyval on all selected entities from the key and value textboxes void setPropertyFromEntries(); diff --git a/radiant/ui/merge/MergeControlDialog.cpp b/radiant/ui/merge/MergeControlDialog.cpp index 5932b7b877..10ee0eebf4 100644 --- a/radiant/ui/merge/MergeControlDialog.cpp +++ b/radiant/ui/merge/MergeControlDialog.cpp @@ -59,6 +59,12 @@ MergeControlDialog::MergeControlDialog() : auto* finishButton = findNamedObject(this, "FinishMergeButton"); finishButton->Bind(wxEVT_BUTTON, &MergeControlDialog::onFinishMerge, this); + auto* resolveAcceptButton = findNamedObject(this, "ResolveAcceptButton"); + resolveAcceptButton->Bind(wxEVT_BUTTON, &MergeControlDialog::onResolveAccept, this); + + auto* resolveRejectButton = findNamedObject(this, "ResolveRejectButton"); + resolveRejectButton->Bind(wxEVT_BUTTON, &MergeControlDialog::onResolveReject, this); + findNamedObject(this, "KeepSelectionGroupsIntact")->SetValue(true); findNamedObject(this, "MergeLayers")->SetValue(true); @@ -168,6 +174,48 @@ void MergeControlDialog::onRejectSelection(wxCommandEvent& ev) scene::removeNodeFromParent(mergeNode); } + updateSummary(); + updateControlSensitivity(); +} + +void MergeControlDialog::onResolveAccept(wxCommandEvent& ev) +{ + auto conflictNode = getSingleSelectedConflictNode(); + + if (conflictNode) + { + conflictNode->foreachMergeAction([&](const scene::merge::IMergeAction::Ptr& action) + { + auto conflictAction = std::dynamic_pointer_cast(action); + assert(conflictAction); + + conflictAction->setResolution(scene::merge::ResolutionType::ApplySourceChange); + }); + } + + updateSummary(); + updateControlSensitivity(); +} + +void MergeControlDialog::onResolveReject(wxCommandEvent& ev) +{ + auto conflictNode = getSingleSelectedConflictNode(); + + if (conflictNode) + { + conflictNode->foreachMergeAction([&](const scene::merge::IMergeAction::Ptr& action) + { + auto conflictAction = std::dynamic_pointer_cast(action); + assert(conflictAction); + + conflictAction->setResolution(scene::merge::ResolutionType::RejectSourceChange); + }); + + UndoableCommand undo("deleteSelectedConflictNode"); + scene::removeNodeFromParent(conflictNode); + } + + updateSummary(); updateControlSensitivity(); } @@ -235,12 +283,24 @@ std::size_t MergeControlDialog::getNumSelectedMergeNodes() return getSelectedMergeNodes().size(); } -inline std::string getEntityName(const scene::merge::IConflictResolutionAction& action) +inline std::string getEntityName(const scene::merge::IConflictResolutionAction::Ptr& action) { - auto entity = Node_getEntity(action.getConflictingEntity()); + auto entity = Node_getEntity(action->getConflictingEntity()); return entity ? entity->getKeyValue("name") : "?"; } +inline std::string getKeyName(const scene::merge::IConflictResolutionAction::Ptr& action) +{ + auto keyConflictAction = std::dynamic_pointer_cast(action->getSourceAction()); + return keyConflictAction ? keyConflictAction->getKey() : std::string(); +} + +inline std::string getKeyValue(const scene::merge::IConflictResolutionAction::Ptr& action) +{ + auto keyConflictAction = std::dynamic_pointer_cast(action->getSourceAction()); + return keyConflictAction ? keyConflictAction->getValue() : std::string(); +} + inline std::string getConflictDescription(const std::shared_ptr& node) { std::string text; @@ -260,11 +320,26 @@ inline std::string getConflictDescription(const std::shared_ptr(this, "NoMergeConflictSelected")->Show(conflictNode == nullptr); findNamedObject(this, "ConflictDescription")->Show(conflictNode != nullptr); + findNamedObject(this, "ResolveAcceptButton")->Show(conflictNode != nullptr); + findNamedObject(this, "ResolveRejectButton")->Show(conflictNode != nullptr); if (conflictNode) { diff --git a/radiant/ui/merge/MergeControlDialog.h b/radiant/ui/merge/MergeControlDialog.h index 8c354605bd..bba504746b 100644 --- a/radiant/ui/merge/MergeControlDialog.h +++ b/radiant/ui/merge/MergeControlDialog.h @@ -53,6 +53,8 @@ class MergeControlDialog : void onFinishMerge(wxCommandEvent& ev); void onAbortMerge(wxCommandEvent& ev); void onRejectSelection(wxCommandEvent& ev); + void onResolveAccept(wxCommandEvent& ev); + void onResolveReject(wxCommandEvent& ev); void updateControlSensitivity(); void queueUpdate(); void onIdle(wxIdleEvent& ev);