Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h67
-rw-r--r--source/blender/blenkernel/BKE_screen.h6
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c39
-rw-r--r--source/blender/blenkernel/intern/lib_id_remapper.cc175
-rw-r--r--source/blender/blenkernel/intern/lib_id_remapper_test.cc83
-rw-r--r--source/blender/blenkernel/intern/lib_override.c66
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c66
-rw-r--r--source/blender/editors/include/ED_util.h8
-rw-r--r--source/blender/editors/space_action/space_action.c18
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c68
-rw-r--r--source/blender/editors/space_clip/space_clip.c18
-rw-r--r--source/blender/editors/space_file/space_file.c3
-rw-r--r--source/blender/editors/space_graph/space_graph.c18
-rw-r--r--source/blender/editors/space_image/space_image.c25
-rw-r--r--source/blender/editors/space_nla/space_nla.c16
-rw-r--r--source/blender/editors/space_node/space_node.cc83
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc65
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c16
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc25
-rw-r--r--source/blender/editors/space_text/space_text.c15
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c77
-rw-r--r--source/blender/editors/util/ed_util.c21
-rw-r--r--source/blender/windowmanager/WM_api.h3
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c32
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
26 files changed, 713 insertions, 304 deletions
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index d8842dbce7f..cc970342fbb 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -38,6 +38,9 @@
extern "C" {
#endif
+struct ID;
+struct IDRemapper;
+
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
/* Also IDRemap->flag. */
@@ -98,6 +101,19 @@ enum {
};
/**
+ * Replace all references in given Main using the given \a mappings
+ *
+ * \note Is preferred over BKE_libblock_remap_locked due to performance.
+ */
+void BKE_libblock_remap_multiple_locked(struct Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags);
+
+void BKE_libblock_remap_multiple(struct Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags);
+
+/**
* Replace all references in given Main to \a old_id by \a new_id
* (if \a new_id is NULL, it unlinks \a old_id).
*
@@ -146,12 +162,61 @@ void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, int remap_f
ATTR_NONNULL();
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
-typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
+typedef void (*BKE_library_remap_editor_id_reference_cb)(const struct IDRemapper *mappings);
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
void BKE_library_callback_remap_editor_id_reference_set(
BKE_library_remap_editor_id_reference_cb func);
+/* IDRemapper */
+struct IDRemapper;
+typedef enum IDRemapperApplyResult {
+ /** No remapping rules available for the source. */
+ ID_REMAP_RESULT_SOURCE_UNAVAILABLE,
+ /** Source isn't mappable (e.g. NULL). */
+ ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE,
+ /** Source has been remapped to a new pointer. */
+ ID_REMAP_RESULT_SOURCE_REMAPPED,
+ /** Source has been set to NULL. */
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED,
+} IDRemapperApplyResult;
+
+typedef enum IDRemapperApplyOptions {
+ ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),
+ ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),
+
+ ID_REMAP_APPLY_DEFAULT = 0,
+} IDRemapperApplyOptions;
+
+typedef void (*IDRemapperIterFunction)(struct ID *old_id, struct ID *new_id, void *user_data);
+
+/**
+ * Create a new ID Remapper.
+ *
+ * An ID remapper stores multiple remapping rules.
+ */
+struct IDRemapper *BKE_id_remapper_create(void);
+
+void BKE_id_remapper_clear(struct IDRemapper *id_remapper);
+bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper);
+/** Free the given ID Remapper. */
+void BKE_id_remapper_free(struct IDRemapper *id_remapper);
+/** Add a new remapping. */
+void BKE_id_remapper_add(struct IDRemapper *id_remapper, struct ID *old_id, struct ID *new_id);
+
+/**
+ * Apply a remapping.
+ *
+ * Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
+ */
+IDRemapperApplyResult BKE_id_remapper_apply(const struct IDRemapper *id_remapper,
+ struct ID **r_id_ptr,
+ IDRemapperApplyOptions options);
+bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter);
+void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
+ IDRemapperIterFunction func,
+ void *user_data);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 63f6fca2a9d..c85ae04a492 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -38,6 +38,7 @@ struct BlendLibReader;
struct BlendWriter;
struct Header;
struct ID;
+struct IDRemapper;
struct LibraryForeachIDData;
struct ListBase;
struct Menu;
@@ -117,10 +118,7 @@ typedef struct SpaceType {
bContextDataCallback context;
/* Used when we want to replace an ID by another (or NULL). */
- void (*id_remap)(struct ScrArea *area,
- struct SpaceLink *sl,
- struct ID *old_id,
- struct ID *new_id);
+ void (*id_remap)(struct ScrArea *area, struct SpaceLink *sl, const struct IDRemapper *mappings);
int (*space_subtype_get)(struct ScrArea *area);
void (*space_subtype_set)(struct ScrArea *area, int value);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 41ca8084849..6d6579f49f6 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -179,6 +179,7 @@ set(SRC
intern/lib_id.c
intern/lib_id_delete.c
intern/lib_id_eval.c
+ intern/lib_id_remapper.cc
intern/lib_override.c
intern/lib_query.c
intern/lib_remap.c
@@ -823,6 +824,7 @@ if(WITH_GTESTS)
intern/idprop_serialize_test.cc
intern/lattice_deform_test.cc
intern/layer_test.cc
+ intern/lib_id_remapper_test.cc
intern/lib_id_test.cc
intern/lib_remap_test.cc
intern/tracking_test.cc
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 6d2e89187f7..f4dd67cac28 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -154,7 +154,10 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
}
if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, id, NULL);
+ remap_editor_id_reference_cb(remapper);
+ BKE_id_remapper_free(remapper);
}
}
@@ -292,32 +295,40 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* Note that we go forward here, since we want to check dependencies before users
* (e.g. meshes before objects).
* Avoids to have to loop twice. */
+ struct IDRemapper *remapper = BKE_id_remapper_create();
for (i = 0; i < base_count; i++) {
ListBase *lb = lbarray[i];
ID *id, *id_next;
+ BKE_id_remapper_clear(remapper);
for (id = lb->first; id; id = id_next) {
id_next = id->next;
/* NOTE: in case we delete a library, we also delete all its datablocks! */
if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
id->tag |= tag;
-
- /* Will tag 'never NULL' users of this ID too.
- * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
- * (and proxy!) links, this can lead to nasty crashing here in second,
- * actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(bmain,
- id,
- NULL,
- (ID_REMAP_FLAG_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
+ BKE_id_remapper_add(remapper, id, NULL);
}
}
+
+ if (BKE_id_remapper_is_empty(remapper)) {
+ continue;
+ }
+
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
+ * (and proxy!) links, this can lead to nasty crashing here in second,
+ * actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_multiple_locked(bmain,
+ remapper,
+ (ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
}
+ BKE_id_remapper_free(remapper);
}
+
BKE_main_unlock(bmain);
/* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones,
diff --git a/source/blender/blenkernel/intern/lib_id_remapper.cc b/source/blender/blenkernel/intern/lib_id_remapper.cc
new file mode 100644
index 00000000000..c1734c9826a
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_id_remapper.cc
@@ -0,0 +1,175 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 by Blender Foundation.
+ */
+
+#include "DNA_ID.h"
+
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_map.hh"
+
+using IDTypeFilter = uint64_t;
+
+namespace blender::bke::id::remapper {
+struct IDRemapper {
+ private:
+ Map<ID *, ID *> mappings;
+ IDTypeFilter source_types = 0;
+
+ public:
+ void clear()
+ {
+ mappings.clear();
+ source_types = 0;
+ }
+
+ bool is_empty() const
+ {
+ return mappings.is_empty();
+ }
+
+ void add(ID *old_id, ID *new_id)
+ {
+ BLI_assert(old_id != nullptr);
+ BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
+ mappings.add(old_id, new_id);
+ source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
+ }
+
+ bool contains_mappings_for_any(IDTypeFilter filter) const
+ {
+ return (source_types & filter) != 0;
+ }
+
+ IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options) const
+ {
+ BLI_assert(r_id_ptr != nullptr);
+ if (*r_id_ptr == nullptr) {
+ return ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE;
+ }
+
+ if (!mappings.contains(*r_id_ptr)) {
+ return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
+ }
+
+ if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
+ id_us_min(*r_id_ptr);
+ }
+
+ *r_id_ptr = mappings.lookup(*r_id_ptr);
+ if (*r_id_ptr == nullptr) {
+ return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
+ }
+
+ if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
+ id_us_plus(*r_id_ptr);
+ }
+
+ if (options & ID_REMAP_APPLY_ENSURE_REAL) {
+ id_us_ensure_real(*r_id_ptr);
+ }
+ return ID_REMAP_RESULT_SOURCE_REMAPPED;
+ }
+
+ void iter(IDRemapperIterFunction func, void *user_data) const
+ {
+ for (auto item : mappings.items()) {
+ func(item.key, item.value, user_data);
+ }
+ }
+};
+
+} // namespace blender::bke::id::remapper
+
+/** \brief wrap CPP IDRemapper to a C handle. */
+static IDRemapper *wrap(blender::bke::id::remapper::IDRemapper *remapper)
+{
+ return static_cast<IDRemapper *>(static_cast<void *>(remapper));
+}
+
+/** \brief wrap C handle to a CPP IDRemapper. */
+static blender::bke::id::remapper::IDRemapper *unwrap(IDRemapper *remapper)
+{
+ return static_cast<blender::bke::id::remapper::IDRemapper *>(static_cast<void *>(remapper));
+}
+
+/** \brief wrap C handle to a CPP IDRemapper. */
+static const blender::bke::id::remapper::IDRemapper *unwrap(const IDRemapper *remapper)
+{
+ return static_cast<const blender::bke::id::remapper::IDRemapper *>(
+ static_cast<const void *>(remapper));
+}
+
+extern "C" {
+
+IDRemapper *BKE_id_remapper_create(void)
+{
+ blender::bke::id::remapper::IDRemapper *remapper =
+ MEM_new<blender::bke::id::remapper::IDRemapper>(__func__);
+ return wrap(remapper);
+}
+
+void BKE_id_remapper_free(IDRemapper *id_remapper)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ MEM_delete<blender::bke::id::remapper::IDRemapper>(remapper);
+}
+
+void BKE_id_remapper_clear(struct IDRemapper *id_remapper)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->clear();
+}
+
+bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->is_empty();
+}
+
+void BKE_id_remapper_add(IDRemapper *id_remapper, ID *old_id, ID *new_id)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->add(old_id, new_id);
+}
+
+bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->contains_mappings_for_any(type_filter);
+}
+
+IDRemapperApplyResult BKE_id_remapper_apply(const IDRemapper *id_remapper,
+ ID **r_id_ptr,
+ const IDRemapperApplyOptions options)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->apply(r_id_ptr, options);
+}
+
+void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
+ IDRemapperIterFunction func,
+ void *user_data)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->iter(func, user_data);
+}
+}
diff --git a/source/blender/blenkernel/intern/lib_id_remapper_test.cc b/source/blender/blenkernel/intern/lib_id_remapper_test.cc
new file mode 100644
index 00000000000..594f64dac73
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_id_remapper_test.cc
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 by Blender Foundation.
+ */
+
+#include "testing/testing.h"
+
+#include "BKE_lib_remap.h"
+
+#include "BLI_string.h"
+
+#include "DNA_ID.h"
+
+namespace blender::bke::id::remapper::tests {
+
+TEST(lib_id_remapper, unavailable)
+{
+ ID id1;
+ ID *idp = &id1;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNAVAILABLE);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, not_mappable)
+{
+ ID *idp = nullptr;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, mapped)
+{
+ ID id1;
+ ID id2;
+ ID *idp = &id1;
+ BLI_strncpy(id1.name, "OB1", sizeof(id1.name));
+ BLI_strncpy(id2.name, "OB2", sizeof(id2.name));
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, &id1, &id2);
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_REMAPPED);
+ EXPECT_EQ(idp, &id2);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, unassigned)
+{
+ ID id1;
+ ID *idp = &id1;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, &id1, nullptr);
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNASSIGNED);
+ EXPECT_EQ(idp, nullptr);
+
+ BKE_id_remapper_free(remapper);
+}
+
+} // namespace blender::bke::id::remapper::tests
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 38ce8ea88b9..bc897e9075b 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -1121,6 +1121,45 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor
}
}
+static void lib_override_library_remap(Main *bmain,
+ const ID *id_root_reference,
+ GHash *linkedref_to_old_override)
+{
+ ID *id;
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+
+ if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ ID *id_override_new = id->newid;
+ ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ if (id_override_old == NULL) {
+ continue;
+ }
+
+ BKE_id_remapper_add(remapper, id_override_old, id_override_new);
+ /* Remap no-main override IDs we just created too. */
+ GHashIterator linkedref_to_old_override_iter;
+ GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
+ ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
+ if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
+ continue;
+ }
+
+ BKE_libblock_relink_ex(bmain,
+ id_override_old_iter,
+ id_override_old,
+ id_override_new,
+ ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Remap all IDs to use the new override. */
+ BKE_libblock_remap_multiple(bmain, remapper, 0);
+ BKE_id_remapper_free(remapper);
+}
+
static bool lib_override_library_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1312,32 +1351,9 @@ static bool lib_override_library_resync(Main *bmain,
}
FOREACH_MAIN_LISTBASE_END;
- /* We need to remap old to new override usages in a separate loop, after all new overrides have
+ /* We remap old to new override usages in a separate loop, after all new overrides have
* been added to Main. */
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
- ID *id_override_new = id->newid;
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
-
- if (id_override_old != NULL) {
- /* Remap all IDs to use the new override. */
- BKE_libblock_remap(bmain, id_override_old, id_override_new, 0);
- /* Remap no-main override IDs we just created too. */
- GHashIterator linkedref_to_old_override_iter;
- GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
- ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
- if (id_override_old_iter->tag & LIB_TAG_NO_MAIN) {
- BKE_libblock_relink_ex(bmain,
- id_override_old_iter,
- id_override_old,
- id_override_new,
- ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- }
- }
- }
- }
- }
- FOREACH_MAIN_ID_END;
+ lib_override_library_remap(bmain, id_root_reference, linkedref_to_old_override);
BKE_main_collection_sync(bmain);
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index ec97ca83703..c3ccedb9608 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -510,11 +510,18 @@ static void libblock_remap_data(
#endif
}
-void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+typedef struct LibblockRemapMultipleUserData {
+ Main *bmain;
+ short remap_flags;
+} LibBlockRemapMultipleUserData;
+
+static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_data)
{
+ LibBlockRemapMultipleUserData *data = user_data;
+ Main *bmain = data->bmain;
+ const short remap_flags = data->remap_flags;
+
IDRemap id_remap_data;
- ID *old_id = old_idv;
- ID *new_id = new_idv;
int skipped_direct, skipped_refcounted;
BLI_assert(old_id != NULL);
@@ -527,13 +534,6 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
free_notifier_reference_cb(old_id);
}
- /* We assume editors do not hold references to their IDs... This is false in some cases
- * (Image is especially tricky here),
- * editors' code is to handle refcount (id->us) itself then. */
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(old_id, new_id);
- }
-
skipped_direct = id_remap_data.skipped_direct;
skipped_refcounted = id_remap_data.skipped_refcounted;
@@ -606,6 +606,41 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
DEG_relations_tag_update(bmain);
}
+void BKE_libblock_remap_multiple_locked(Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags)
+{
+ if (BKE_id_remapper_is_empty(mappings)) {
+ /* Early exit nothing to do. */
+ return;
+ }
+
+ LibBlockRemapMultipleUserData user_data;
+ user_data.bmain = bmain;
+ user_data.remap_flags = remap_flags;
+ BKE_id_remapper_iter(mappings, libblock_remap_foreach_idpair_cb, &user_data);
+
+ /* We assume editors do not hold references to their IDs... This is false in some cases
+ * (Image is especially tricky here),
+ * editors' code is to handle refcount (id->us) itself then. */
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(mappings);
+ }
+
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
+}
+
+void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+{
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ BKE_id_remapper_add(remapper, old_id, new_id);
+ BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags);
+ BKE_id_remapper_free(remapper);
+}
+
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
BKE_main_lock(bmain);
@@ -615,6 +650,17 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
BKE_main_unlock(bmain);
}
+void BKE_libblock_remap_multiple(Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags)
+{
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_multiple_locked(bmain, mappings, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
void BKE_libblock_unlink(Main *bmain,
void *idv,
const bool do_flag_never_null,
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 6bcddfa631a..4e794838b2f 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -33,6 +33,7 @@ extern "C" {
struct GPUBatch;
struct Main;
struct bContext;
+struct IDRemapper;
/* ed_util.c */
@@ -60,10 +61,13 @@ bool ED_editors_flush_edits(struct Main *bmain);
*
* \param new_id: may be NULL to unlink \a old_id.
*/
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ struct ID *old_id,
+ struct ID *new_id);
void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
- struct ID *old_id,
- struct ID *new_id);
+ const struct IDRemapper *mappings);
void ED_operatortypes_edutils(void);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 4463856f40a..ba96ac52f1f 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_nla.h"
#include "BKE_screen.h"
@@ -814,20 +815,15 @@ static void action_refresh(const bContext *C, ScrArea *area)
/* XXX re-sizing y-extents of tot should go here? */
}
-static void action_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void action_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceAction *sact = (SpaceAction *)slink;
- if ((ID *)sact->action == old_id) {
- sact->action = (bAction *)new_id;
- }
-
- if ((ID *)sact->ads.filter_grp == old_id) {
- sact->ads.filter_grp = (Collection *)new_id;
- }
- if ((ID *)sact->ads.source == old_id) {
- sact->ads.source = new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sact->action, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sact->ads.filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, &sact->ads.source, ID_REMAP_APPLY_DEFAULT);
}
/**
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 007a9105c76..cf1e7788ff8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_gpencil_modifier.h" /* Types for registering panels. */
+#include "BKE_lib_remap.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
@@ -860,54 +861,53 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void buttons_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceProperties *sbuts = (SpaceProperties *)slink;
- if (sbuts->pinid == old_id) {
- sbuts->pinid = new_id;
- if (new_id == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
+ if (BKE_id_remapper_apply(mappings, &sbuts->pinid, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
}
if (sbuts->path) {
ButsContextPath *path = sbuts->path;
+ for (int i = 0; i < path->len; i++) {
+ switch (BKE_id_remapper_apply(mappings, &path->ptr[i].owner_id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED: {
+ if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ break;
+ }
+ case ID_REMAP_RESULT_SOURCE_REMAPPED: {
+ RNA_id_pointer_create(path->ptr[i].owner_id, &path->ptr[i]);
+ /* There is no easy way to check/make path downwards valid, just nullify it.
+ * Next redraw will rebuild this anyway. */
+ i++;
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ break;
+ }
- int i;
- for (i = 0; i < path->len; i++) {
- if (path->ptr[i].owner_id == old_id) {
- break;
- }
- }
-
- if (i == path->len) {
- /* pass */
- }
- else if (new_id == NULL) {
- if (i == 0) {
- MEM_SAFE_FREE(sbuts->path);
- }
- else {
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE: {
+ /* Nothing to do. */
+ break;
+ }
}
}
- else {
- RNA_id_pointer_create(new_id, &path->ptr[i]);
- /* There is no easy way to check/make path downwards valid, just nullify it.
- * Next redraw will rebuild this anyway. */
- i++;
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
- }
}
if (sbuts->texuser) {
ButsContextTexture *ct = sbuts->texuser;
- if ((ID *)ct->texture == old_id) {
- ct->texture = (Tex *)new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&ct->texture, ID_REMAP_APPLY_DEFAULT);
BLI_freelistN(&ct->users);
ct->user = NULL;
}
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index b6dbda79a2d..da1d2dea653 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_movieclip.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
@@ -1317,23 +1318,18 @@ static void clip_properties_region_listener(const wmRegionListenerParams *params
/********************* registration ********************/
-static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void clip_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceClip *sclip = (SpaceClip *)slink;
- if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_MC | FILTER_ID_MSK)) {
return;
}
- if ((ID *)sclip->clip == old_id) {
- sclip->clip = (MovieClip *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)sclip->mask_info.mask == old_id) {
- sclip->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->clip, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
void ED_spacetype_clip(void)
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 97a5f173ffd..470128f61bd 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -33,6 +33,7 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_screen.h"
@@ -989,7 +990,7 @@ static int /*eContextResult*/ file_context(const bContext *C,
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id))
+static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper *UNUSED(mappings))
{
SpaceFile *sfile = (SpaceFile *)sl;
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 40c95d4f382..7d5e8836490 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -36,6 +36,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -796,18 +797,17 @@ static void graph_refresh(const bContext *C, ScrArea *area)
graph_refresh_fcurve_colors(C);
}
-static void graph_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void graph_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceGraph *sgraph = (SpaceGraph *)slink;
-
- if (sgraph->ads) {
- if ((ID *)sgraph->ads->filter_grp == old_id) {
- sgraph->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)sgraph->ads->source == old_id) {
- sgraph->ads->source = new_id;
- }
+ if (!sgraph->ads) {
+ return;
}
+
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->source, ID_REMAP_APPLY_DEFAULT);
}
static int graph_space_subtype_get(ScrArea *area)
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 52cb36b1b8f..eb5b6104a79 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -983,29 +984,19 @@ static void image_header_region_listener(const wmRegionListenerParams *params)
}
}
-static void image_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void image_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceImage *simg = (SpaceImage *)slink;
- if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_IM | FILTER_ID_GD | FILTER_ID_MSK)) {
return;
}
- if ((ID *)simg->image == old_id) {
- simg->image = (Image *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)simg->gpd == old_id) {
- simg->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
-
- if ((ID *)simg->mask_info.mask == old_id) {
- simg->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&simg->image, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
/**
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 0771153c5f5..962b5151661 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -577,18 +578,17 @@ static void nla_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void nla_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceNla *snla = (SpaceNla *)slink;
- if (snla->ads) {
- if ((ID *)snla->ads->filter_grp == old_id) {
- snla->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)snla->ads->source == old_id) {
- snla->ads->source = new_id;
- }
+ if (snla->ads == NULL) {
+ return;
}
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT);
}
void ED_spacetype_nla(void)
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index f794a8ce294..8f465ffbf80 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -896,71 +897,63 @@ static void node_widgets()
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
}
-static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void node_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceNode *snode = (SpaceNode *)slink;
- if (snode->id == old_id) {
+ if (ELEM(BKE_id_remapper_apply(mappings, &snode->id, ID_REMAP_APPLY_DEFAULT),
+ ID_REMAP_RESULT_SOURCE_REMAPPED,
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED)) {
/* nasty DNA logic for SpaceNode:
* ideally should be handled by editor code, but would be bad level call
*/
BLI_freelistN(&snode->treepath);
/* XXX Untested in case new_id != nullptr... */
- snode->id = new_id;
snode->from = nullptr;
snode->nodetree = nullptr;
snode->edittree = nullptr;
}
- else if (GS(old_id->name) == ID_OB) {
- if (snode->from == old_id) {
- if (new_id == nullptr) {
- snode->flag &= ~SNODE_PIN;
- }
- snode->from = new_id;
- }
+ if (BKE_id_remapper_apply(mappings, &snode->from, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ snode->flag &= ~SNODE_PIN;
}
- else if (GS(old_id->name) == ID_GD) {
- if ((ID *)snode->gpd == old_id) {
- snode->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&snode->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT);
+
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_NT)) {
+ return;
}
- else if (GS(old_id->name) == ID_NT) {
- bNodeTreePath *path, *path_next;
- for (path = (bNodeTreePath *)snode->treepath.first; path; path = path->next) {
- if ((ID *)path->nodetree == old_id) {
- path->nodetree = (bNodeTree *)new_id;
- id_us_ensure_real(new_id);
- }
- if (path == snode->treepath.first) {
- /* first nodetree in path is same as snode->nodetree */
- snode->nodetree = path->nodetree;
- }
- if (path->nodetree == nullptr) {
- break;
- }
+ bNodeTreePath *path, *path_next;
+ for (path = (bNodeTreePath *)snode->treepath.first; path; path = path->next) {
+ BKE_id_remapper_apply(mappings, (ID **)&path->nodetree, ID_REMAP_APPLY_ENSURE_REAL);
+ if (path == snode->treepath.first) {
+ /* first nodetree in path is same as snode->nodetree */
+ snode->nodetree = path->nodetree;
+ }
+ if (path->nodetree == nullptr) {
+ break;
}
+ }
- /* remaining path entries are invalid, remove */
- for (; path; path = path_next) {
- path_next = path->next;
+ /* remaining path entries are invalid, remove */
+ for (; path; path = path_next) {
+ path_next = path->next;
- BLI_remlink(&snode->treepath, path);
- MEM_freeN(path);
- }
+ BLI_remlink(&snode->treepath, path);
+ MEM_freeN(path);
+ }
- /* edittree is just the last in the path,
- * set this directly since the path may have been shortened above */
- if (snode->treepath.last) {
- path = (bNodeTreePath *)snode->treepath.last;
- snode->edittree = path->nodetree;
- }
- else {
- snode->edittree = nullptr;
- }
+ /* edittree is just the last in the path,
+ * set this directly since the path may have been shortened above */
+ if (snode->treepath.last) {
+ path = (bNodeTreePath *)snode->treepath.last;
+ snode->edittree = path->nodetree;
+ }
+ else {
+ snode->edittree = nullptr;
}
}
diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc
index bb4e57a79da..0fb17fa3f47 100644
--- a/source/blender/editors/space_outliner/space_outliner.cc
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_outliner_treehash.h"
#include "BKE_screen.h"
@@ -405,45 +406,49 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)space_outliner_new;
}
-static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)slink;
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(old_id)) {
- return; /* ID type is not used by outliner. */
- }
+ BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT);
- if (space_outliner->search_tse.id == old_id) {
- space_outliner->search_tse.id = new_id;
+ if (!space_outliner->treestore) {
+ return;
}
- if (space_outliner->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(space_outliner->treestore, &iter);
- while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
- if (tselem->id == old_id) {
- tselem->id = new_id;
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+ bool unassigned = false;
+
+ BLI_mempool_iternew(space_outliner->treestore, &iter);
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ switch (BKE_id_remapper_apply(mappings, &tselem->id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_REMAPPED:
changed = true;
- }
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED:
+ changed = true;
+ unassigned = true;
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE:
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ break;
}
+ }
- /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
- * So runtime data might not have been created yet. */
- if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- space_outliner->storeflag |= SO_TREESTORE_REBUILD;
-
- if (new_id == nullptr) {
- /* Redraw is needed when removing data for multiple outlines show the same data.
- * without this, the stale data won't get fully flushed when this outliner
- * is not the active outliner the user is interacting with. See T85976. */
- ED_area_tag_redraw(area);
- }
+ /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
+ * So runtime data might not have been created yet. */
+ if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ space_outliner->storeflag |= SO_TREESTORE_REBUILD;
+
+ if (unassigned) {
+ /* Redraw is needed when removing data for multiple outlines show the same data.
+ * without this, the stale data won't get fully flushed when this outliner
+ * is not the active outliner the user is interacting with. See T85976. */
+ ED_area_tag_redraw(area);
}
}
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index b93f421ff5c..b294fdf4820 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "BKE_sequencer_offscreen.h"
@@ -988,19 +989,12 @@ static void sequencer_buttons_region_listener(const wmRegionListenerParams *para
}
}
-static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void sequencer_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceSeq *sseq = (SpaceSeq *)slink;
-
- if (!ELEM(GS(old_id->name), ID_GD)) {
- return;
- }
-
- if ((ID *)sseq->gpd == old_id) {
- sseq->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sseq->gpd, ID_REMAP_APPLY_DEFAULT);
}
/* ************************************* */
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 02f7f1d71c4..18f383d45fb 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -18,6 +18,7 @@
#include "BLI_listbase.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -171,21 +172,23 @@ static void spreadsheet_keymap(wmKeyConfig *keyconf)
WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
}
-static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void spreadsheet_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const IDRemapper *mappings)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
- if ((ID *)object_context->object == old_id) {
- if (new_id && GS(new_id->name) == ID_OB) {
- object_context->object = (Object *)new_id;
- }
- else {
- object_context->object = nullptr;
- }
- }
+ if (context->type != SPREADSHEET_CONTEXT_OBJECT) {
+ continue;
}
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+
+ if (object_context->object != nullptr && GS(object_context->object->id.name) != ID_OB) {
+ object_context->object = nullptr;
+ continue;
+ }
+
+ BKE_id_remapper_apply(mappings, ((ID **)&object_context->object), ID_REMAP_APPLY_DEFAULT);
}
}
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index f449ce50ae3..7339d8248c8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -401,18 +402,12 @@ static void text_properties_region_draw(const bContext *C, ARegion *region)
}
}
-static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void text_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceText *stext = (SpaceText *)slink;
-
- if (!ELEM(GS(old_id->name), ID_TXT)) {
- return;
- }
-
- if ((ID *)stext->text == old_id) {
- stext->text = (Text *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
}
/********************* registration ********************/
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 8822ea6af3b..0a5bebac8a8 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -48,6 +48,7 @@
#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_layer.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
@@ -1813,50 +1814,54 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const struct IDRemapper *mappings)
{
- View3D *v3d;
- ARegion *region;
- bool is_local = false;
-
- if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
- return;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* Otherwise, bonename may remain valid...
+ * We could be smart and check this, too? */
+ v3d->ob_center_bone[0] = '\0';
}
+}
- for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
- if ((ID *)v3d->camera == old_id) {
- v3d->camera = (Object *)new_id;
- if (!new_id) {
- /* 3D view might be inactive, in that case needs to use slink->regionbase */
- ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
- &slink->regionbase;
- for (region = regionbase->first; region; region = region->next) {
- if (region->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
- region->regiondata;
- if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
- rv3d->persp = RV3D_PERSP;
- }
- }
+static void view3d_id_remap_v3d(ScrArea *area,
+ SpaceLink *slink,
+ View3D *v3d,
+ const struct IDRemapper *mappings,
+ const bool is_local)
+{
+ ARegion *region;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->camera, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* 3D view might be inactive, in that case needs to use slink->regionbase */
+ ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
+ &slink->regionbase;
+ for (region = regionbase->first; region; region = region->next) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
+ region->regiondata;
+ if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
+ rv3d->persp = RV3D_PERSP;
}
}
}
+ }
+}
- /* Values in local-view aren't used, see: T52663 */
- if (is_local == false) {
- if ((ID *)v3d->ob_center == old_id) {
- v3d->ob_center = (Object *)new_id;
- /* Otherwise, bonename may remain valid...
- * We could be smart and check this, too? */
- if (new_id == NULL) {
- v3d->ob_center_bone[0] = '\0';
- }
- }
- }
+static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
+{
- if (is_local) {
- break;
- }
+ if (!BKE_id_remapper_has_mapping_for(
+ mappings, FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_MC)) {
+ return;
+ }
+
+ View3D *view3d = (View3D *)slink;
+ view3d_id_remap_v3d(area, slink, view3d, mappings, false);
+ view3d_id_remap_v3d_ob_centers(view3d, mappings);
+ if (view3d->localvd != NULL) {
+ /* Object centers in local-view aren't used, see: T52663 */
+ view3d_id_remap_v3d(area, slink, view3d->localvd, mappings, true);
}
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 882f140c063..0320a2a9a1a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -35,6 +35,7 @@
#include "BKE_collection.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_multires.h"
@@ -434,11 +435,27 @@ void unpack_menu(bContext *C,
UI_popup_menu_end(C, pup);
}
-void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
+void ED_spacedata_id_remap(struct ScrArea *area,
+ struct SpaceLink *sl,
+ const struct IDRemapper *mappings)
+{
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
+ if (st && st->id_remap) {
+ st->id_remap(area, sl, mappings);
+ }
+}
+
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ ID *old_id,
+ ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
- st->id_remap(area, sl, old_id, new_id);
+ struct IDRemapper *mappings = BKE_id_remapper_create();
+ BKE_id_remapper_add(mappings, old_id, new_id);
+ st->id_remap(area, sl, mappings);
+ BKE_id_remapper_free(mappings);
}
}
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 9e4d8e733a6..ff3e1b7474c 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -47,6 +47,7 @@ struct GHashIterator;
struct GPUViewport;
struct ID;
struct IDProperty;
+struct IDRemapper;
struct ImBuf;
struct ImageFormatData;
struct Main;
@@ -471,7 +472,7 @@ void WM_main_add_notifier(unsigned int type, void *reference);
* Clear notifiers by reference, Used so listeners don't act on freed data.
*/
void WM_main_remove_notifier_reference(const void *reference);
-void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id);
+void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings);
/* reports */
/**
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 28d8413fe0b..3e30c06ade2 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -51,6 +51,7 @@
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -312,28 +313,39 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
-void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
+static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_data))
+{
+ ED_assetlist_storage_id_remap(old_id, new_id);
+}
+
+static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
+{
+ struct wmMsgBus *mbus = user_data;
+ if (new_id != NULL) {
+ WM_msg_id_update(mbus, old_id, new_id);
+ }
+ else {
+ WM_msg_id_remove(mbus, old_id);
+ }
+}
+
+void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
{
Main *bmain = G_MAIN;
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
- ED_spacedata_id_remap(area, sl, old_id, new_id);
+ ED_spacedata_id_remap(area, sl, mappings);
}
}
}
- ED_assetlist_storage_id_remap(old_id, new_id);
+
+ BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, NULL);
wmWindowManager *wm = bmain->wm.first;
if (wm && wm->message_bus) {
- struct wmMsgBus *mbus = wm->message_bus;
- if (new_id != NULL) {
- WM_msg_id_update(mbus, old_id, new_id);
- }
- else {
- WM_msg_id_remove(mbus, old_id);
- }
+ BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus);
}
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 957ec7d800d..6caac79c4d5 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -252,7 +252,7 @@ void WM_init(bContext *C, int argc, const char **argv)
BKE_region_callback_free_gizmomap_set(wm_gizmomap_remove);
BKE_region_callback_refresh_tag_gizmomap_set(WM_gizmomap_tag_refresh);
BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference);
- BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap);
+ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap_single);
DEG_editors_set_update_cb(ED_render_id_flush_update, ED_render_scene_update);
ED_spacetypes_init();