Fix T95037: Allow making local IDs that are not used by anything.

Some IDs (like text ones) can be linked and only kept around thanks to
editors, allow making such IDs local in `BKE_lib_id_make_local_generic`.

Also refactor logic checking whether ID should be made directly local or
copied into its own util function, so that we can remain sure all
special-cases 'make local' code still uses the same logic here.
This commit is contained in:
Bastien Montagne 2022-01-24 17:38:36 +01:00
parent a2301b1d91
commit 2e9b8689e4
Notes: blender-bot 2023-02-14 02:27:56 +01:00
Referenced by issue #95037, click to make local has no effect on linked text in scripting workspace
4 changed files with 59 additions and 69 deletions

View File

@ -382,6 +382,16 @@ enum {
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
};
/**
* Helper to decide whether given `id` can be directly made local, or needs to be copied.
* `r_force_local` and `r_force_copy` cannot be true together. But both can be false, in case no
* action should be performed.
*
* \note low-level helper to de-duplicate logic between `BKE_lib_id_make_local_generic` and the
* specific corner-cases implementations needed for objects and brushes.
*/
void BKE_lib_id_make_local_generic_action_define(
struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy);
/**
* Generic 'make local' function, works for most of data-block types.
*/

View File

@ -149,16 +149,9 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
Brush *brush = (Brush *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
BLI_assert(force_copy == false || force_copy != force_local);
bool is_local = false, is_lib = false;
/* - only lib users: do nothing (unless force_local is set)
* - only local users: set flag
* - mixed: make copy
*/
bool force_local, force_copy;
BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
if (brush->clone.image) {
/* Special case: ima always local immediately. Clone image should only have one user anyway. */
@ -171,18 +164,6 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
BLI_assert(brush->clone.image->id.lib == NULL && brush->clone.image->id.newid == NULL);
}
if (!force_local && !force_copy) {
BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
if (lib_local || is_local) {
if (!is_lib) {
force_local = true;
}
else {
force_copy = true;
}
}
}
if (force_local) {
BKE_lib_id_clear_library_data(bmain, &brush->id, flags);
BKE_lib_id_expand_local(bmain, &brush->id, flags);

View File

@ -454,37 +454,56 @@ static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id,
}
}
void BKE_lib_id_make_local_generic_action_define(
struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy)
{
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
BLI_assert(force_copy == false || force_copy != force_local);
if (force_local || force_copy) {
/* Already set by caller code, nothig to do here. */
*r_force_local = force_local;
*r_force_copy = force_copy;
return;
}
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
bool is_local = false, is_lib = false;
/* - no user (neither lib nor local): make local (happens e.g. with UI-used only data).
* - only lib users: do nothing (unless force_local is set)
* - only local users: make local
* - mixed: make copy
* In case we make a whole lib's content local,
* we always want to localize, and we skip remapping (done later).
*/
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
if (!lib_local && !is_local && !is_lib) {
force_local = true;
}
else if (lib_local || is_local) {
if (!is_lib) {
force_local = true;
}
else {
force_copy = true;
}
}
*r_force_local = force_local;
*r_force_copy = force_copy;
}
void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
{
if (!ID_IS_LINKED(id)) {
return;
}
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
BLI_assert(force_copy == false || force_copy != force_local);
bool is_local = false, is_lib = false;
/* - only lib users: do nothing (unless force_local is set)
* - only local users: set flag
* - mixed: make copy
* In case we make a whole lib's content local,
* we always want to localize, and we skip remapping (done later).
*/
if (!force_copy && !force_local) {
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
if (lib_local || is_local) {
if (!is_lib) {
force_local = true;
}
else {
force_copy = true;
}
}
}
bool force_local, force_copy;
BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
if (force_local) {
BKE_lib_id_clear_library_data(bmain, id, flags);
@ -516,6 +535,7 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
}
}
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}

View File

@ -333,30 +333,9 @@ static void object_make_local(Main *bmain, ID *id, const int flags)
Object *ob = (Object *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
const bool clear_proxy = (flags & LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING) == 0;
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
BLI_assert(force_copy == false || force_copy != force_local);
bool is_local = false, is_lib = false;
/* - only lib users: do nothing (unless force_local is set)
* - only local users: set flag
* - mixed: make copy
* In case we make a whole lib's content local,
* we always want to localize, and we skip remapping (done later).
*/
if (!force_local && !force_copy) {
BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
if (lib_local || is_local) {
if (!is_lib) {
force_local = true;
}
else {
force_copy = true;
}
}
}
bool force_local, force_copy;
BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
if (force_local) {
BKE_lib_id_clear_library_data(bmain, &ob->id, flags);