LibOverride: Add 'delete and use linked data' operation.

This will re-link all usages of a library override data-block
(including all of its override dependencies) to its reference linked
IDs, and delete those liboverrides.

As usual, it is available in the ID sub-menu of the outliner context
right-click menu.

Part of T76555.
This commit is contained in:
Bastien Montagne 2020-08-20 12:35:16 +02:00
parent 59180ff153
commit 4aa04b6490
Notes: blender-bot 2023-02-14 04:31:04 +01:00
Referenced by issue #76555, Library Overrides: Usability issues/paper-cuts
3 changed files with 98 additions and 0 deletions

View File

@ -81,6 +81,7 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct ID *id_root);
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find(
struct IDOverrideLibrary *override, const char *rna_path);

View File

@ -784,6 +784,50 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
return success;
}
/**
* Advanced 'smart' function to delete library overrides (including their existing override
* hierarchy) and remap their usages to their linked reference IDs.
*
* \note All IDs tagged with `LIB_TAG_DOIT` will be deleted.
*
* \param id_root The root liboverride ID to resync from.
*/
void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
/* Tag all collections and objects, as well as other IDs using them. */
id_root->tag |= LIB_TAG_DOIT;
/* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag
* linked reference ones to be overridden again. */
BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_DOIT) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
ID *id_override_reference = id->override_library->reference;
/* Remap the whole local IDs to use the linked data. */
BKE_libblock_remap(bmain, id, id_override_reference, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
FOREACH_MAIN_ID_END;
/* Delete the override IDs. */
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_DOIT) {
BKE_id_delete(bmain, id);
}
}
FOREACH_MAIN_ID_END;
/* Should not actually be needed here... */
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure(
IDOverrideLibrary *override)
{

View File

@ -860,6 +860,38 @@ static void id_override_library_resync_fn(bContext *C,
}
}
static void id_override_library_delete_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
Main *bmain = CTX_data_main(C);
id_root->tag |= LIB_TAG_DOIT;
/* Tag all linked parents in tree hierarchy to be also overridden. */
while ((te = te->parent) != NULL) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) {
break;
}
te->store_elem->id->tag |= LIB_TAG_DOIT;
}
BKE_lib_override_library_delete(bmain, id_root);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
}
static void id_fake_user_set_fn(bContext *UNUSED(C),
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@ -1641,6 +1673,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
OUTLINER_IDOP_REMAP,
@ -1693,6 +1726,12 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Resync Library Override Hierarchy",
"Rebuild this local override from its linked reference, as well as its hierarchy of "
"dependencies"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY,
"OVERRIDE_LIBRARY_DELETE_HIERARCHY",
0,
"Delete Library Override Hierarchy",
"Delete this local override (including its hierarchy of override dependencies) and relink "
"its usages to the linked data-blocks"},
{0, "", 0, NULL, NULL},
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
@ -1725,6 +1764,8 @@ static bool outliner_id_operation_item_poll(bContext *C,
return true;
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY:
return true;
case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY:
return true;
case OUTLINER_IDOP_SINGLE:
if (!space_outliner || ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
return true;
@ -1919,6 +1960,18 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: {
/* make local */
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_delete_fn,
&(OutlinerLibOverrideData){.do_hierarchy = true});
ED_undo_push(C, "Delete Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_SINGLE: {
/* make single user */
switch (idlevel) {