diff --git a/source/blender/editors/object/object_relations.cc b/source/blender/editors/object/object_relations.cc index a658788d8a0..576305feb99 100644 --- a/source/blender/editors/object/object_relations.cc +++ b/source/blender/editors/object/object_relations.cc @@ -37,6 +37,7 @@ #include "BLI_math_vector.h" #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BLI_vector_set.hh" #include "BLT_translation.h" @@ -2568,33 +2569,68 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve return OPERATOR_CANCELLED; } - int potential_root_collections_num = 0; - uint collection_session_uuid = MAIN_ID_SESSION_UUID_UNSET; + blender::VectorSet potential_root_collections; LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - /* Only check for directly linked collections. */ - if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0 || + /* Only check for linked collections from the same library, in the current viewlayer. */ + if (!ID_IS_LINKED(&collection->id) || collection->id.lib != obact->id.lib || !BKE_view_layer_has_collection(view_layer, collection)) { continue; } - if (BKE_collection_has_object_recursive(collection, obact)) { - if (potential_root_collections_num == 0) { - collection_session_uuid = collection->id.session_uuid; + if (!BKE_collection_has_object_recursive(collection, obact)) { + continue; + } + if (potential_root_collections.is_empty()) { + potential_root_collections.add_new(collection); + } + else { + bool has_parents_in_potential_roots = false; + bool is_potential_root = false; + for (auto collection_root_iter : potential_root_collections) { + if (BKE_collection_has_collection(collection_root_iter, collection)) { + BLI_assert_msg(!BKE_collection_has_collection(collection, collection_root_iter), + "Invalid loop in collection hierarchy"); + /* Current potential root is already 'better' (higher up in the collection hierarchy) + * than current collection, nothing else to do. */ + has_parents_in_potential_roots = true; + } + else if (BKE_collection_has_collection(collection, collection_root_iter)) { + BLI_assert_msg(!BKE_collection_has_collection(collection_root_iter, collection), + "Invalid loop in collection hierarchy"); + /* Current potential root is in the current collection's hierarchy, so the later is a + * better candidate as root collection. */ + is_potential_root = true; + potential_root_collections.remove(collection_root_iter); + } + else { + /* Current potential root is not found in current collection's hierarchy, so the later is + * a potential candidate as root collection. */ + is_potential_root = true; + } + } + /* Only add the current collection as potential root if it is not a descendant of any already + * known potential root collections. */ + if (is_potential_root && !has_parents_in_potential_roots) { + potential_root_collections.add_new(collection); } - potential_root_collections_num++; } } - if (potential_root_collections_num <= 1) { - RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_session_uuid)); + if (potential_root_collections.is_empty()) { + RNA_property_int_set(op->ptr, op->type->prop, MAIN_ID_SESSION_UUID_UNSET); + return make_override_library_exec(C, op); + } + if (potential_root_collections.size() == 1) { + Collection *collection_root = potential_root_collections.pop(); + RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_root->id.session_uuid)); return make_override_library_exec(C, op); } BKE_reportf(op->reports, RPT_ERROR, - "Too many potential root collections (%d) for the override hierarchy, " + "Too many potential root collections (%ld) for the override hierarchy, " "please use the Outliner instead", - potential_root_collections_num); + potential_root_collections.size()); return OPERATOR_CANCELLED; }