Fix #125944: Outliner: Child objects missing when linked to other collection

Objects inside `lc.collection->gobject / te_parent->subtree` are not
order according to ob-parent heirarchy. Due to this, some child
object tree elements are iterated before the parent inside
`make_object_parent_hierarchy_collections` while building the hierarchy.
This ignores the case for objects when they are in the different
collection (lets say "Collection2"), see `if(!found)`. To fix this,
store ordered list of object hierarchy in a Vector `ordered_objects`.
This way, the parent element is first added to collection2.
Then while iterating its child, `parent_ob_tree_elements` has more than
one elements (i.e. possible to add child object inside Collection2)

Also resolves #100393
Steps to Reproduce: Just open the .blend from above report

Alternative for !136872

Pull Request: https://projects.blender.org/blender/blender/pulls/136971
This commit is contained in:
Pratik Borhade
2025-06-03 14:11:05 +02:00
committed by Pratik Borhade
parent cf34e9e75f
commit 6fe4496f4c

View File

@@ -16,6 +16,7 @@
#include "BLI_listbase.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "../outliner_intern.hh"
@@ -32,6 +33,14 @@ class ObjectsChildrenBuilder {
SpaceOutliner &outliner_;
ObjectTreeElementsMap object_tree_elements_map_;
/**
* Stores objects such that parents are before children.
*/
Vector<Object *> ordered_objects_;
/**
* Holds objects that were already added to #ordered_objects_, to prevent duplicates.
*/
Set<Object *> objects_in_ordered_objects_;
public:
ObjectsChildrenBuilder(SpaceOutliner &space_outliner);
@@ -42,6 +51,7 @@ class ObjectsChildrenBuilder {
private:
void object_tree_elements_lookup_create_recursive(TreeElement *te_parent);
void make_object_parent_hierarchy_collections();
void add_object_and_parents_in_order(Object *ob);
};
/* -------------------------------------------------------------------- */
@@ -221,7 +231,7 @@ void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeEl
Object *ob = (Object *)tselem->id;
/* Lookup children or add new, empty children vector. */
Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {});
add_object_and_parents_in_order(ob);
tree_elements.append(te);
object_tree_elements_lookup_create_recursive(te);
}
@@ -234,16 +244,17 @@ void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeEl
*/
void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
{
for (ObjectTreeElementsMap::MutableItem item : object_tree_elements_map_.items()) {
Object *child = item.key;
if (child->parent == nullptr) {
/* Ordered list (parent before children) is important. Otherwise, it is easy to miss objects that
* are linked with another collection. For details, see: !136971. */
for (Object *ob : ordered_objects_) {
if (ob->parent == nullptr) {
continue;
}
Vector<TreeElement *> &child_ob_tree_elements = item.value;
Vector<TreeElement *> *parent_ob_tree_elements = object_tree_elements_map_.lookup_ptr(
child->parent);
ob->parent);
Vector<TreeElement *> &child_ob_tree_elements = *object_tree_elements_map_.lookup_ptr(ob);
if (parent_ob_tree_elements == nullptr) {
continue;
}
@@ -279,7 +290,7 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
TreeElement *child_ob_tree_element = AbstractTreeDisplay::add_element(
&outliner_,
&parent_ob_tree_element->subtree,
reinterpret_cast<ID *>(child),
reinterpret_cast<ID *>(ob),
nullptr,
parent_ob_tree_element,
TSE_SOME_ID,
@@ -292,6 +303,16 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
}
}
void ObjectsChildrenBuilder::add_object_and_parents_in_order(Object *ob)
{
if (Object *parent = ob->parent) {
add_object_and_parents_in_order(parent);
}
if (objects_in_ordered_objects_.add(ob)) {
ordered_objects_.append(ob);
}
}
/** \} */
} // namespace blender::ed::outliner