BKE Collection: Add new function to rebuild parent relationships.

It's not always possible to keep 'by hand' parent relationships valid in
collections hierarchy. Add functions to remake those
(re-using/factorizing code from `readfile.c` `lib_link_collection_data()`
function).

Can't stress again how painful it is to have those kind of backward
relationships in our data structures, those *always* end up being
serious issues to keep in sync... Should only be generated on the fly
when needed, period. :(
This commit is contained in:
Bastien Montagne
2019-05-22 22:51:36 +02:00
parent 5a3c44937f
commit d1f96f9b11
3 changed files with 72 additions and 12 deletions

View File

@@ -163,6 +163,9 @@ bool BKE_collection_find_cycle(struct Collection *new_ancestor, struct Collectio
bool BKE_collection_has_collection(struct Collection *parent, struct Collection *collection);
void BKE_collection_parent_relations_rebuild(struct Collection *collection);
void BKE_main_collections_parent_relations_rebuild(struct Main *bmain);
/* Iteration callbacks. */
typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data);

View File

@@ -1056,6 +1056,72 @@ bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *ch
return true;
}
/**
* Rebuild parent relationships from child ones, for all children of given \a collection.
*
* \note Given collection is assumed to already have valid parents.
*/
void BKE_collection_parent_relations_rebuild(Collection *collection)
{
for (CollectionChild *child = collection->children.first, *child_next = NULL; child;
child = child_next) {
child_next = child->next;
if (child->collection == NULL || BKE_collection_find_cycle(collection, child->collection)) {
BLI_freelinkN(&collection->children, child);
}
else {
CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), __func__);
cparent->collection = collection;
BLI_addtail(&child->collection->parents, cparent);
}
}
}
static void collection_parents_rebuild_recursive(Collection *collection)
{
BKE_collection_parent_relations_rebuild(collection);
collection->id.tag &= ~LIB_TAG_DOIT;
for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) {
collection_parents_rebuild_recursive(child->collection);
}
}
/**
* Rebuild parent relationships from child ones, for all collections in given \a bmain.
*
* \note Uses LIB_TAG_DOIT internally...
*/
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
{
/* Only collections not in bmain (master ones in scenes) have no parent... */
for (Collection *collection = bmain->collections.first; collection != NULL;
collection = collection->id.next) {
BLI_freelistN(&collection->parents);
collection->id.tag |= LIB_TAG_DOIT;
}
/* Scene's master collections will be 'root' parent of most of our collections, so start with
* them. */
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
collection_parents_rebuild_recursive(scene->master_collection);
}
/* We may have parent chains outside of scene's master_collection context? At least, readfile's
* lib_link_collection_data() seems to assume that, so do the same here. */
for (Collection *collection = bmain->collections.first; collection != NULL;
collection = collection->id.next) {
if (collection->id.tag & LIB_TAG_DOIT) {
/* Note: we do not have easy access to 'which collections is root' info in that case, which
* means test for cycles in collection relationships may fail here. I don't think that is an
* issue in practice here, but worth keeping in mind... */
collection_parents_rebuild_recursive(collection);
}
}
}
/********************** Collection index *********************/
static Collection *collection_from_index_recursive(Collection *collection,

View File

@@ -6228,20 +6228,11 @@ static void lib_link_collection_data(FileData *fd, Library *lib, Collection *col
}
}
for (CollectionChild *child = collection->children.first, *child_next = NULL; child;
child = child_next) {
child_next = child->next;
for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) {
child->collection = newlibadr_us(fd, lib, child->collection);
if (child->collection == NULL || BKE_collection_find_cycle(collection, child->collection)) {
BLI_freelinkN(&collection->children, child);
}
else {
CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent");
cparent->collection = collection;
BLI_addtail(&child->collection->parents, cparent);
}
}
BKE_collection_parent_relations_rebuild(collection);
}
static void lib_link_collection(FileData *fd, Main *main)