diff --git a/radiantcore/layers/LayerManager.cpp b/radiantcore/layers/LayerManager.cpp index d78c7644a3..494aaf0c2a 100644 --- a/radiantcore/layers/LayerManager.cpp +++ b/radiantcore/layers/LayerManager.cpp @@ -393,6 +393,12 @@ void LayerManager::setParentLayer(int childLayerId, int parentLayerId) throw std::invalid_argument("Cannot assign a layer as parent of itself"); } + // Detect recursions, if any parent layer has this layer in its hierarchy, we should throw + if (layerIsChildOf(parentLayerId, childLayerId)) + { + throw std::invalid_argument("This relationship change would result in a recursion"); + } + if (_layerParentIds.at(childLayerId) != parentLayerId) { _layerParentIds.at(childLayerId) = parentLayerId; @@ -400,6 +406,28 @@ void LayerManager::setParentLayer(int childLayerId, int parentLayerId) } } +bool LayerManager::layerIsChildOf(int candidateLayerId, int parentLayerId) +{ + // Nothing is a parent of the null layer + if (candidateLayerId == NO_PARENT_ID || parentLayerId == NO_PARENT_ID) + { + return false; + } + + // Check the hierarchy of the candidate + for (int immediateParentId = getParentLayer(candidateLayerId); + immediateParentId != NO_PARENT_ID; + immediateParentId = getParentLayer(immediateParentId)) + { + if (immediateParentId == parentLayerId) + { + return true; + } + } + + return false; +} + sigc::signal LayerManager::signal_layersChanged() { return _layersChangedSignal; diff --git a/radiantcore/layers/LayerManager.h b/radiantcore/layers/LayerManager.h index 39516079d6..9ac5079b7b 100644 --- a/radiantcore/layers/LayerManager.h +++ b/radiantcore/layers/LayerManager.h @@ -136,6 +136,9 @@ class LayerManager : // Returns the lowest unused layer ID int getLowestUnusedLayerID(); + + // Returns true if the given candidateLayerId is a child of the given parentLayer + bool layerIsChildOf(int candidateLayerId, int parentLayerId); }; } // namespace scene