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
+
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);