Python API: Add link/append pre/post handlers.

The `pre` handler is called after blender internal code is done populating
the link/append context with data to be processed, and before this data
starts being linked from library files.

The `post` handler is called after blender is done linking, and
potentailly appending and/or instantiating, the requested data and all
of their dependencies.

Both handlers are called with a single argument, the link/append
context.

An new RNA sets of wrappers have been added to expose relevant info from
these internal C++ structures.

NOTE: !113658 is very similar (but tied to asset drag & drop), whereas
this PR is more general (these could probably live hand-in-hand / side-
by-side).

Implements #122357

Pull Request: https://projects.blender.org/blender/blender/pulls/128279

-----------------

Some quick py example  code:

```python
import bpy

def my_handler_pre(lapp_context):
    print("About to {}:\n\t".format("link" if "LINK" in lapp_context.options else "append"),
          "\n\t".join("{} '{}', from libs ['{}']".format(item.id_type, item.name,
                                                         "', '".join([l.filepath for l in item.source_libraries]))
                      for item in lapp_context.import_items))

def my_handler_post(lapp_context):
    print("{}:\n\t".format("Linked" if "LINK" in lapp_context.options else "Appended"),
          "\n\t".join("{} '{}', from lib '{}'".format(item.id.id_type, item.id.name, item.source_library.filepath)
                      for item in lapp_context.import_items))

bpy.app.handlers.link_append_pre.append(my_handler_pre)
bpy.app.handlers.link_append_post.append(my_handler_post)
```
This commit is contained in:
Bastien Montagne
2024-10-02 16:44:38 +02:00
committed by Bastien Montagne
parent b46e2e6300
commit 76e7770bc9
12 changed files with 813 additions and 106 deletions

View File

@@ -7,16 +7,169 @@
* \ingroup bke
*/
#include <list>
#include <string>
#include "BLI_bit_vector.hh"
#include "BLI_function_ref.hh"
#include "BLI_map.hh"
#include "BLO_readfile.hh"
struct BlendHandle;
struct ID;
struct Library;
struct LibraryLink_Params;
struct MainLibraryWeakReferenceMap;
struct ReportList;
/* TODO: Rename file to `BKE_blendfile_import.hh`. */
/* TODO: Replace `BlendfileLinkAppend` prefix by `blender::bke::blendfile::import` namespace. */
/* TODO: Move these enums to scoped enum classes. */
/** Actions to apply to an item (i.e. linked ID). */
enum {
LINK_APPEND_ACT_UNSET = 0,
LINK_APPEND_ACT_KEEP_LINKED,
LINK_APPEND_ACT_REUSE_LOCAL,
LINK_APPEND_ACT_MAKE_LOCAL,
LINK_APPEND_ACT_COPY_LOCAL,
};
/** Various status info about an item (i.e. linked ID). */
enum {
/** An indirectly linked ID. */
LINK_APPEND_TAG_INDIRECT = 1 << 0,
/**
* An ID also used as liboverride dependency (either directly, as a liboverride reference, or
* indirectly, as data used by a liboverride reference). It should never be directly made local.
*
* Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY.
*/
LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY = 1 << 1,
/**
* An ID only used as liboverride dependency (either directly or indirectly, see
* #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY for precisions). It should not be considered during
* the 'make local' process, and remain purely linked data.
*
* Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY.
*/
LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY = 1 << 2,
};
/* NOTE: These three structs are currently exposed in header to allow for their usage in RNA.
* Regualr C++ code should not access their content directly.
*
* TODO: Refactor these three structs into classes, and integrated the whole API into them. */
struct BlendfileLinkAppendContext;
struct BlendfileLinkAppendContextItem;
/** A data-block (ID) entry in the `items` list from #BlendfileLinkAppendContext. */
struct BlendfileLinkAppendContextItem {
/**
* Link/Append context owner of this item. Used in RNA API, could be removed once RNA paths are
* functional.
*/
BlendfileLinkAppendContext *lapp_context;
/** Name of the ID (without the heading two-chars IDcode). */
std::string name;
/** All libraries (from #BlendfileLinkAppendContext.libraries) to try to load this ID from. */
blender::BitVector<> libraries;
/** ID type. */
short idcode;
/** Type of action to perform on this item, and general status tag information.
* NOTE: Mostly used by append post-linking processing. */
char action;
char tag;
/** Newly linked ID (nullptr until it has been successfully linked). */
ID *new_id;
/** Library ID from which the #new_id has been linked (nullptr until it has been successfully
* linked). */
Library *source_library;
/** Liboverride of the linked ID (nullptr until it has been successfully created or an existing
* one has been found). */
ID *liboverride_id;
/**
* Whether the item has a matching local ID that was already appended from the same source
* before, and has not been modified. In 'Append & Reuse' case, this local ID _may_ be reused
* instead of making linked data local again.
*/
ID *reusable_local_id;
/** Opaque user data pointer. */
void *userdata;
};
/** A blendfile library entry in the `libraries` vector from #BlendfileLinkAppendContext. */
struct BlendfileLinkAppendContextLibrary {
std::string path; /* Absolute .blend file path. */
BlendHandle *blo_handle; /* Blend file handle, if any. */
bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */
/* The blendfile report associated with the `blo_handle`, if owned. */
BlendFileReadReport bf_reports;
};
/**
* General container for all relevant data for a library/linked-data related operation (linking,
* appending, library relocating, etc.).
*/
struct BlendfileLinkAppendContext {
/** List of library paths to search IDs in. */
blender::Vector<BlendfileLinkAppendContextLibrary> libraries;
/**
* List of all ID to try to link from #libraries. This is a linked list because iterators must
* not be invalidated when adding more items.
*/
std::list<BlendfileLinkAppendContextItem> items;
using items_iterator_t = std::list<BlendfileLinkAppendContextItem>::iterator;
/** Linking/appending parameters. Including `bmain`, `scene`, `viewlayer` and `view3d`. */
LibraryLink_Params *params = nullptr;
/**
* What is the current stage of the link/append process. Used mainly by the RNA wrappers for the
* pre/post handlers currently.
*/
enum class ProcessStage {
/**
* The context data is being filled with data (Libraries and IDs) to process. Nothing has been
* linked yet.
*/
Init = 0,
/** The context data is being used to linked IDs. */
Linking,
/**
* The context data is being used to append IDs (i.e. make local linked ones, or re-use already
* existing local ones).
*/
Appending,
/**
* The context data is being used to instantiate (loose) IDs (i.e. ensure that Collections,
* Objects and/or ObjectData IDs are added to the current scene).
*/
Instantiating,
/**
* All data has been linked or appended. The context state represents the final result of the
* process.
*/
Done,
/* NOTE: For the time being, liboverride step is not considered here (#BKE_blendfile_override).
* Mainly because it is only available through the BPY API currently. */
};
ProcessStage process_stage;
/** Allows to easily find an existing items from an ID pointer. */
blender::Map<ID *, BlendfileLinkAppendContextItem *> new_id_to_item;
/** Runtime info used by append code to manage re-use of already appended matching IDs. */
MainLibraryWeakReferenceMap *library_weak_reference_mapping = nullptr;
/** Embedded blendfile and its size, if needed. */
const void *blendfile_mem = nullptr;
size_t blendfile_memsize = 0;
};
/**
* Allocate and initialize a new context to link/append data-blocks.
@@ -158,6 +311,18 @@ void BKE_blendfile_link_append_context_item_foreach(
BlendfileLinkAppendContextItem *item)> callback_function,
eBlendfileLinkAppendForeachItemFlag flag);
/**
* Called once the link/append process has been fully initialized (all of its data has been set).
*
* NOTE: Currently only used to call the matching handler.
*/
void BKE_blendfile_link_append_context_init_done(BlendfileLinkAppendContext *lapp_context);
/**
* Perform linking operation on all items added to given `lapp_context`.
*/
void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports);
/**
* Perform append operation, using modern ID usage looper to detect which ID should be kept
* linked, made local, duplicated as local, re-used from local etc.
@@ -166,10 +331,6 @@ void BKE_blendfile_link_append_context_item_foreach(
* #BKE_blendfile_link on the same `lapp_context`.
*/
void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports);
/**
* Perform linking operation on all items added to given `lapp_context`.
*/
void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports);
/**
* Instantiate loose data in the scene (e.g. add object to the active collection).
@@ -177,6 +338,13 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
void BKE_blendfile_link_append_instantiate_loose(BlendfileLinkAppendContext *lapp_context,
ReportList *reports);
/**
* Finalize the link/append process.
*
* NOTE: Currently only used to call the matching handler..
*/
void BKE_blendfile_link_append_context_finalize(BlendfileLinkAppendContext *lapp_context);
/**
* Options controlling the behavior of liboverrides creation.
*/

View File

@@ -110,6 +110,8 @@ enum eCbEvent {
BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST,
BKE_CB_EVT_EXTENSION_REPOS_SYNC,
BKE_CB_EVT_EXTENSION_REPOS_FILES_CLEAR,
BKE_CB_EVT_BLENDIMPORT_PRE,
BKE_CB_EVT_BLENDIMPORT_POST,
BKE_CB_EVT_TOT,
};

View File

@@ -61,8 +61,12 @@ static ID *asset_link_id(Main &global_main,
lapp_context, asset_name, id_type, nullptr);
BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, lapp_item, 0);
BKE_blendfile_link_append_context_init_done(lapp_context);
BKE_blendfile_link(lapp_context, nullptr);
BKE_blendfile_link_append_context_finalize(lapp_context);
ID *local_asset = BKE_blendfile_link_append_context_item_newid_get(lapp_context, lapp_item);
BKE_blendfile_link_append_context_free(lapp_context);

View File

@@ -41,6 +41,8 @@ static void copybuffer_append(BlendfileLinkAppendContext *lapp_context,
/* Tag existing IDs in given `bmain_dst` as already existing. */
BKE_main_id_tag_all(bmain, ID_TAG_PRE_EXISTING, true);
BKE_blendfile_link_append_context_init_done(lapp_context);
BKE_blendfile_link(lapp_context, reports);
/* Mark all library linked objects to be updated. */
@@ -53,6 +55,8 @@ static void copybuffer_append(BlendfileLinkAppendContext *lapp_context,
/* Instantiate loose data in the scene (e.g. add object to the active collection). */
BKE_blendfile_link_append_instantiate_loose(lapp_context, reports);
BKE_blendfile_link_append_context_finalize(lapp_context);
/* This must be unset, otherwise these object won't link into other scenes from this blend
* file. */
BKE_main_id_tag_all(bmain, ID_TAG_PRE_EXISTING, false);

View File

@@ -13,8 +13,6 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <list>
#include <string>
#include "CLG_log.h"
@@ -28,11 +26,9 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "BLI_bit_vector.hh"
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_map.hh"
#include "BLI_math_vector.h"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
@@ -40,6 +36,10 @@
#include "BLT_translation.hh"
#include "RNA_access.hh"
#include "RNA_prototypes.hh"
#include "BKE_callbacks.hh"
#include "BKE_grease_pencil_legacy_convert.hh"
#include "BKE_idtype.hh"
#include "BKE_key.hh"
@@ -60,7 +60,6 @@
#include "BKE_blendfile_link_append.hh"
#include "BLO_readfile.hh"
#include "BLO_writefile.hh"
static CLG_LogRef LOG = {"bke.blendfile_link_append"};
@@ -69,69 +68,6 @@ static CLG_LogRef LOG = {"bke.blendfile_link_append"};
/** \name Link/append context implementation and public management API.
* \{ */
struct BlendfileLinkAppendContextItem {
/** Name of the ID (without the heading two-chars IDcode). */
std::string name;
/** All libraries (from #BlendfileLinkAppendContext.libraries) to try to load this ID from. */
blender::BitVector<> libraries;
/** ID type. */
short idcode;
/** Type of action to perform on this item, and general status tag information.
* NOTE: Mostly used by append post-linking processing. */
char action;
char tag;
/** Newly linked ID (nullptr until it has been successfully linked). */
ID *new_id;
/** Library ID from which the #new_id has been linked (nullptr until it has been successfully
* linked). */
Library *source_library;
/** Liboverride of the linked ID (nullptr until it has been successfully created or an existing
* one has been found). */
ID *liboverride_id;
/**
* Whether the item has a matching local ID that was already appended from the same source
* before, and has not been modified. In 'Append & Reuse' case, this local ID _may_ be reused
* instead of making linked data local again.
*/
ID *reusable_local_id;
/** Opaque user data pointer. */
void *userdata;
};
/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */
struct BlendfileLinkAppendContextLibrary {
std::string path; /* Absolute .blend file path. */
BlendHandle *blo_handle; /* Blend file handle, if any. */
bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */
/* The blendfile report associated with the `blo_handle`, if owned. */
BlendFileReadReport bf_reports;
};
struct BlendfileLinkAppendContext {
/** List of library paths to search IDs in. */
blender::Vector<BlendfileLinkAppendContextLibrary> libraries;
/**
* List of all ID to try to link from #libraries. This is a linked list because iterators must
* not be invalidated when adding more items.
*/
std::list<BlendfileLinkAppendContextItem> items;
/** Linking/appending parameters. Including `bmain`, `scene`, `viewlayer` and `view3d`. */
LibraryLink_Params *params = nullptr;
/** Allows to easily find an existing items from an ID pointer. */
blender::Map<ID *, BlendfileLinkAppendContextItem *> new_id_to_item;
/** Runtime info used by append code to manage re-use of already appended matching IDs. */
MainLibraryWeakReferenceMap *library_weak_reference_mapping = nullptr;
/** Embedded blendfile and its size, if needed. */
const void *blendfile_mem = nullptr;
size_t blendfile_memsize = 0;
};
struct BlendfileLinkAppendContextCallBack {
BlendfileLinkAppendContext *lapp_context;
BlendfileLinkAppendContextItem *item;
@@ -155,36 +91,6 @@ struct BlendfileLinkAppendContextCallBack {
bool is_liboverride_dependency_only;
};
/** Actions to apply to an item (i.e. linked ID). */
enum {
LINK_APPEND_ACT_UNSET = 0,
LINK_APPEND_ACT_KEEP_LINKED,
LINK_APPEND_ACT_REUSE_LOCAL,
LINK_APPEND_ACT_MAKE_LOCAL,
LINK_APPEND_ACT_COPY_LOCAL,
};
/** Various status info about an item (i.e. linked ID). */
enum {
/** An indirectly linked ID. */
LINK_APPEND_TAG_INDIRECT = 1 << 0,
/**
* An ID also used as liboverride dependency (either directly, as a liboverride reference, or
* indirectly, as data used by a liboverride reference). It should never be directly made local.
*
* Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY.
*/
LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY = 1 << 1,
/**
* An ID only used as liboverride dependency (either directly or indirectly, see
* #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY for precisions). It should not be considered during
* the 'make local' process, and remain purely linked data.
*
* Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY.
*/
LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY = 1 << 2,
};
static BlendHandle *link_append_context_library_blohandle_ensure(
BlendfileLinkAppendContext &lapp_context,
BlendfileLinkAppendContextLibrary &lib_context,
@@ -225,6 +131,7 @@ BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Pa
{
BlendfileLinkAppendContext *lapp_context = MEM_new<BlendfileLinkAppendContext>(__func__);
lapp_context->params = params;
lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Init;
return lapp_context;
}
@@ -273,6 +180,7 @@ void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *l
BlendHandle *blo_handle)
{
BLI_assert(lapp_context->items.empty());
BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init);
BlendfileLinkAppendContextLibrary lib_context = {};
@@ -293,6 +201,8 @@ BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
{
BlendfileLinkAppendContextItem item = {};
item.lapp_context = lapp_context;
item.name = idname;
item.idcode = idcode;
item.libraries = blender::BitVector<>(lapp_context->libraries.size(), false);
@@ -312,6 +222,8 @@ int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
const uint64_t id_types_filter,
const int library_index)
{
BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init);
int id_num = 0;
int id_code_iter = 0;
short id_code;
@@ -357,10 +269,12 @@ int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
}
void BKE_blendfile_link_append_context_item_library_index_enable(
BlendfileLinkAppendContext * /*lapp_context*/,
BlendfileLinkAppendContext *lapp_context,
BlendfileLinkAppendContextItem *item,
const int library_index)
{
BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init);
UNUSED_VARS_NDEBUG(lapp_context);
item->libraries[library_index].set();
}
@@ -375,9 +289,11 @@ void *BKE_blendfile_link_append_context_item_userdata_get(
return item->userdata;
}
ID *BKE_blendfile_link_append_context_item_newid_get(BlendfileLinkAppendContext * /*lapp_context*/,
ID *BKE_blendfile_link_append_context_item_newid_get(BlendfileLinkAppendContext *lapp_context,
BlendfileLinkAppendContextItem *item)
{
BLI_assert(lapp_context->process_stage != BlendfileLinkAppendContext::ProcessStage::Init);
UNUSED_VARS_NDEBUG(lapp_context);
return item->new_id;
}
@@ -385,6 +301,7 @@ void BKE_blendfile_link_append_context_item_newid_set(BlendfileLinkAppendContext
BlendfileLinkAppendContextItem *item,
ID *new_id)
{
BLI_assert(lapp_context->process_stage != BlendfileLinkAppendContext::ProcessStage::Init);
BLI_assert(item->new_id);
BLI_assert(!item->liboverride_id);
BLI_assert(new_id->lib == item->new_id->lib);
@@ -396,8 +313,10 @@ void BKE_blendfile_link_append_context_item_newid_set(BlendfileLinkAppendContext
}
ID *BKE_blendfile_link_append_context_item_liboverrideid_get(
BlendfileLinkAppendContext * /*lapp_context*/, BlendfileLinkAppendContextItem *item)
BlendfileLinkAppendContext *lapp_context, BlendfileLinkAppendContextItem *item)
{
BLI_assert(lapp_context->process_stage != BlendfileLinkAppendContext::ProcessStage::Init);
UNUSED_VARS_NDEBUG(lapp_context);
return item->liboverride_id;
}
@@ -431,6 +350,28 @@ void BKE_blendfile_link_append_context_item_foreach(
}
}
void BKE_blendfile_link_append_context_init_done(BlendfileLinkAppendContext *lapp_context)
{
BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init);
PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_BlendImportContext, lapp_context);
PointerRNA *pointers[1] = {&ctx_ptr};
BKE_callback_exec(lapp_context->params->bmain, pointers, 1, BKE_CB_EVT_BLENDIMPORT_PRE);
}
void BKE_blendfile_link_append_context_finalize(BlendfileLinkAppendContext *lapp_context)
{
BLI_assert(ELEM(lapp_context->process_stage,
BlendfileLinkAppendContext::ProcessStage::Linking,
BlendfileLinkAppendContext::ProcessStage::Appending,
BlendfileLinkAppendContext::ProcessStage::Instantiating));
lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Done;
PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_BlendImportContext, lapp_context);
PointerRNA *pointers[1] = {&ctx_ptr};
BKE_callback_exec(lapp_context->params->bmain, pointers, 1, BKE_CB_EVT_BLENDIMPORT_POST);
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -1334,6 +1275,9 @@ static void blendfile_append_define_actions(BlendfileLinkAppendContext &lapp_con
void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
{
BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Linking);
lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Appending;
if (lapp_context->items.empty()) {
/* Nothing to append. */
return;
@@ -1537,6 +1481,11 @@ static int foreach_libblock_link_finalize_cb(LibraryIDLinkCallbackData *cb_data)
void BKE_blendfile_link_append_instantiate_loose(BlendfileLinkAppendContext *lapp_context,
ReportList *reports)
{
BLI_assert(ELEM(lapp_context->process_stage,
BlendfileLinkAppendContext::ProcessStage::Linking,
BlendfileLinkAppendContext::ProcessStage::Appending));
lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Instantiating;
if (!lapp_context->params->context.scene) {
return;
}
@@ -1574,6 +1523,9 @@ void BKE_blendfile_link_append_instantiate_loose(BlendfileLinkAppendContext *lap
void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
{
BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init);
lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Linking;
if (lapp_context->items.empty()) {
/* Nothing to be linked. */
return;
@@ -1869,6 +1821,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
BKE_main_id_tag_all(bmain, ID_TAG_PRE_EXISTING, true);
BKE_blendfile_link_append_context_init_done(lapp_context);
/* We do not want any instantiation here! */
BKE_blendfile_link(lapp_context, reports);

View File

@@ -55,6 +55,7 @@ set(DEFSRC
rna_light.cc
rna_lightprobe.cc
rna_linestyle.cc
rna_blendfile_import.cc
rna_main.cc
rna_mask.cc
rna_material.cc

View File

@@ -4827,6 +4827,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_lattice.cc", "rna_lattice_api.cc", RNA_def_lattice},
{"rna_layer.cc", nullptr, RNA_def_view_layer},
{"rna_linestyle.cc", nullptr, RNA_def_linestyle},
{"rna_blendfile_import.cc", nullptr, RNA_def_blendfile_import},
{"rna_main.cc", "rna_main_api.cc", RNA_def_main},
{"rna_fluid.cc", nullptr, RNA_def_fluid},
{"rna_material.cc", "rna_material_api.cc", RNA_def_material},

View File

@@ -0,0 +1,556 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup RNA
*/
#include <cstdlib>
#include "BLO_readfile.hh"
#include "DNA_space_types.h"
#include "BKE_blendfile_link_append.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_enum_types.hh"
#include "rna_internal.hh"
#ifdef RNA_RUNTIME
# include "BLI_bit_span.hh"
# include "BLI_string_utils.hh"
void rna_BlendImportContextLibrary_filepath_get(PointerRNA *ptr, char *value)
{
BlendfileLinkAppendContextLibrary *ctx_lib = static_cast<BlendfileLinkAppendContextLibrary *>(
ptr->data);
const size_t str_len = ctx_lib->path.length();
BLI_strncpy(value, ctx_lib->path.c_str(), str_len + 1);
}
int rna_BlendImportContextLibrary_filepath_len(PointerRNA *ptr)
{
BlendfileLinkAppendContextLibrary *ctx_lib = static_cast<BlendfileLinkAppendContextLibrary *>(
ptr->data);
return int(ctx_lib->path.length());
}
void rna_BlendImportContextItem_name_get(PointerRNA *ptr, char *value)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
const size_t str_len = ctx_item->name.length();
BLI_strncpy(value, ctx_item->name.c_str(), str_len + 1);
}
int rna_BlendImportContextItem_name_len(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return int(ctx_item->name.length());
}
int rna_BlendImportContextItem_id_type_get(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return int(ctx_item->idcode);
}
struct RNABlendImportContextItemLibrariesIterator {
BlendfileLinkAppendContextItem *ctx_item;
blender::bits::BitIterator iter;
int iter_index;
};
void rna_BlendImportContextItem_libraries_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
const blender::BitVector<> &libraries = ctx_item->libraries;
RNABlendImportContextItemLibrariesIterator *libs_iter =
MEM_new<RNABlendImportContextItemLibrariesIterator>(
__func__, RNABlendImportContextItemLibrariesIterator{ctx_item, libraries.begin(), 0});
iter->internal.custom = libs_iter;
while (!(*libs_iter->iter) && libs_iter->iter != libs_iter->ctx_item->libraries.end()) {
libs_iter->iter.operator++();
libs_iter->iter_index++;
}
iter->valid = (libs_iter->iter != libs_iter->ctx_item->libraries.end());
}
void rna_BlendImportContextItem_libraries_next(CollectionPropertyIterator *iter)
{
RNABlendImportContextItemLibrariesIterator *libs_iter =
static_cast<RNABlendImportContextItemLibrariesIterator *>(iter->internal.custom);
do {
libs_iter->iter.operator++();
libs_iter->iter_index++;
} while (!(*libs_iter->iter) && libs_iter->iter != libs_iter->ctx_item->libraries.end());
iter->valid = (libs_iter->iter != libs_iter->ctx_item->libraries.end());
}
void rna_BlendImportContextItem_libraries_end(CollectionPropertyIterator *iter)
{
RNABlendImportContextItemLibrariesIterator *libs_iter =
static_cast<RNABlendImportContextItemLibrariesIterator *>(iter->internal.custom);
iter->valid = false;
iter->internal.custom = nullptr;
MEM_delete(libs_iter);
}
PointerRNA rna_BlendImportContextItem_libraries_get(CollectionPropertyIterator *iter)
{
RNABlendImportContextItemLibrariesIterator *libs_iter =
static_cast<RNABlendImportContextItemLibrariesIterator *>(iter->internal.custom);
BlendfileLinkAppendContextLibrary &ctx_lib =
libs_iter->ctx_item->lapp_context->libraries[libs_iter->iter_index];
return rna_pointer_inherit_refine(&iter->parent, &RNA_BlendImportContextLibrary, &ctx_lib);
}
int rna_BlendImportContextItem_libraries_len(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
/* Count amount of enabled libraries in the item's bitmask. */
int count = 0;
for (const blender::BitRef &bit : ctx_item->libraries) {
if (bit) {
count++;
}
}
return count;
}
int rna_BlendImportContextItem_append_action_get(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return int(ctx_item->action);
}
int rna_BlendImportContextItem_import_info_get(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return int(ctx_item->tag);
}
PointerRNA rna_BlendImportContextItem_id_get(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_ID, ctx_item->new_id);
}
PointerRNA rna_BlendImportContextItem_source_library_get(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_Library, ctx_item->source_library);
}
PointerRNA rna_BlendImportContextItem_library_override_id_get(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_ID, ctx_item->liboverride_id);
}
PointerRNA rna_BlendImportContextItem_reusable_local_id_get(PointerRNA *ptr)
{
BlendfileLinkAppendContextItem *ctx_item = static_cast<BlendfileLinkAppendContextItem *>(
ptr->data);
return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_ID, ctx_item->reusable_local_id);
}
struct RNABlendImportContextItemsIterator {
BlendfileLinkAppendContext *ctx;
BlendfileLinkAppendContext::items_iterator_t iter;
};
void rna_BlendImportContext_import_items_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
BlendfileLinkAppendContext *ctx = static_cast<BlendfileLinkAppendContext *>(ptr->data);
RNABlendImportContextItemsIterator *items_iter = MEM_new<RNABlendImportContextItemsIterator>(
__func__, RNABlendImportContextItemsIterator{ctx, ctx->items.begin()});
iter->internal.custom = items_iter;
iter->valid = (items_iter->iter != items_iter->ctx->items.end());
}
void rna_BlendImportContext_import_items_next(CollectionPropertyIterator *iter)
{
RNABlendImportContextItemsIterator *items_iter =
static_cast<RNABlendImportContextItemsIterator *>(iter->internal.custom);
items_iter->iter++;
iter->valid = (items_iter->iter != items_iter->ctx->items.end());
}
void rna_BlendImportContext_import_items_end(CollectionPropertyIterator *iter)
{
RNABlendImportContextItemsIterator *items_iter =
static_cast<RNABlendImportContextItemsIterator *>(iter->internal.custom);
iter->valid = false;
iter->internal.custom = nullptr;
MEM_delete(items_iter);
}
PointerRNA rna_BlendImportContext_import_items_get(CollectionPropertyIterator *iter)
{
RNABlendImportContextItemsIterator *items_iter =
static_cast<RNABlendImportContextItemsIterator *>(iter->internal.custom);
BlendfileLinkAppendContextItem &ctx_item = *items_iter->iter;
return rna_pointer_inherit_refine(&iter->parent, &RNA_BlendImportContextItem, &ctx_item);
}
int rna_BlendImportContext_import_items_len(PointerRNA *ptr)
{
BlendfileLinkAppendContext *ctx = static_cast<BlendfileLinkAppendContext *>(ptr->data);
return int(ctx->items.size());
}
int rna_BlendImportContext_options_get(PointerRNA *ptr)
{
BlendfileLinkAppendContext *ctx = static_cast<BlendfileLinkAppendContext *>(ptr->data);
return int(ctx->params->flag);
}
int rna_BlendImportContext_process_stage_get(PointerRNA *ptr)
{
BlendfileLinkAppendContext *ctx = static_cast<BlendfileLinkAppendContext *>(ptr->data);
return int(ctx->process_stage);
}
#else /* RNA_RUNTIME */
static void rna_def_blendfile_import_library(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "BlendImportContextLibrary", nullptr);
RNA_def_struct_ui_text(
srna,
"Blendfile Import Context Library",
"Library (blendfile) reference in a BlendImportContext data. Currently only "
"exposed as read-only data for the pre/post blendimport handlers");
RNA_define_verify_sdna(false); /* not in sdna */
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_string_funcs(prop,
"rna_BlendImportContextLibrary_filepath_get",
"rna_BlendImportContextLibrary_filepath_len",
nullptr);
RNA_define_verify_sdna(true); /* not in sdna */
}
static void RNA_def_blendfile_import_libraries(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
RNA_def_property_srna(cprop, "BlendImportContextLibraries");
srna = RNA_def_struct(brna, "BlendImportContextLibraries", nullptr);
RNA_def_struct_ui_text(srna,
"Blendfile Import Context Libraries",
"Collection of source libraries, i.e. blendfile paths");
}
static void rna_def_blendfile_import_item(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "BlendImportContextItem", nullptr);
RNA_def_struct_ui_text(
srna,
"Blendfile Import Context Item",
"An item (representing a data-block) in a BlendImportContext data. Currently only "
"exposed as read-only data for the pre/post linking handlers");
RNA_define_verify_sdna(false); /* not in sdna */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "ID Name", "ID name of the item");
RNA_def_property_string_funcs(
prop, "rna_BlendImportContextItem_name_get", "rna_BlendImportContextItem_name_len", nullptr);
prop = RNA_def_property(srna, "id_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_id_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "ID Type", "ID type of the item");
RNA_def_property_enum_funcs(prop, "rna_BlendImportContextItem_id_type_get", nullptr, nullptr);
prop = RNA_def_property(srna, "source_libraries", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BlendImportContextLibrary");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Source Libraries",
"List of libraries to search and import that ID from. The ID will be "
"imported from the first file in that list that contains it");
RNA_def_property_collection_funcs(prop,
"rna_BlendImportContextItem_libraries_begin",
"rna_BlendImportContextItem_libraries_next",
"rna_BlendImportContextItem_libraries_end",
"rna_BlendImportContextItem_libraries_get",
"rna_BlendImportContextItem_libraries_len",
nullptr,
nullptr,
nullptr);
RNA_def_blendfile_import_libraries(brna, prop);
static const EnumPropertyItem blend_import_item_append_action_items[] = {
{LINK_APPEND_ACT_UNSET, "UNSET", 0, "", "Not yet defined"},
{LINK_APPEND_ACT_KEEP_LINKED, "KEEP_LINKED", 0, "", "ID has been kept linked"},
{LINK_APPEND_ACT_REUSE_LOCAL,
"REUSE_LOCAL",
0,
"",
"An existing matching local ID has been re-used"},
{LINK_APPEND_ACT_MAKE_LOCAL, "MAKE_LOCAL", 0, "", "The newly linked ID has been made local"},
{LINK_APPEND_ACT_COPY_LOCAL,
"COPY_LOCAL",
0,
"",
"The linked ID had other unrelated usages, so it has been duplicated into a local copy"},
{0, nullptr, 0, nullptr, nullptr},
};
prop = RNA_def_property(srna, "append_action", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, blend_import_item_append_action_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Append Action",
"How this item has been handled by the append operation. Only set if "
"the data has been appended");
RNA_def_property_enum_funcs(
prop, "rna_BlendImportContextItem_append_action_get", nullptr, nullptr);
static const EnumPropertyItem blend_import_item_import_info_items[] = {
{LINK_APPEND_TAG_INDIRECT,
"INDIRECT_USAGE",
0,
"",
"That item was added for an indirectly imported ID, as a dependency of another data-block"},
{LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY,
"LIBOVERRIDE_DEPENDENCY",
0,
"",
"That item represents an ID also used as liboverride dependency (either directly, as a "
"liboverride reference, or indirectly, as data used by a liboverride reference). It should "
"never be directly made local. Mutually exclusive with `LIBOVERRIDE_DEPENDENCY_ONLY`"},
{LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY,
"LIBOVERRIDE_DEPENDENCY_ONLY",
0,
"",
"That item represents an ID only used as liboverride dependency (either directly or "
"indirectly, see `LIBOVERRIDE_DEPENDENCY` for precisions). It should not be considered "
"during the 'make local' (append) process, and remain purely linked data. Mutually "
"exclusive with `LIBOVERRIDE_DEPENDENCY`"},
{0, nullptr, 0, nullptr, nullptr},
};
prop = RNA_def_property(srna, "import_info", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, blend_import_item_import_info_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Import Info", "Various status info about an item after it has been imported");
RNA_def_property_enum_funcs(
prop, "rna_BlendImportContextItem_import_info_get", nullptr, nullptr);
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Imported ID",
"The imported ID. None until it has been linked or appended. May be "
"the same as `reusable_local_id` when appended");
RNA_def_property_pointer_funcs(
prop, "rna_BlendImportContextItem_id_get", nullptr, nullptr, nullptr);
prop = RNA_def_property(srna, "source_library", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Library");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Source Library",
"Library ID representing the blendfile from which the ID was imported. "
"None until the ID has been linked or appended");
RNA_def_property_pointer_funcs(
prop, "rna_BlendImportContextItem_source_library_get", nullptr, nullptr, nullptr);
prop = RNA_def_property(srna, "library_override_id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop,
"Library Overridden ID",
"The library override of the linked ID. None until it has been created");
RNA_def_property_pointer_funcs(
prop, "rna_BlendImportContextItem_library_override_id_get", nullptr, nullptr, nullptr);
prop = RNA_def_property(srna, "reusable_local_id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Reusable Local ID",
"The already existing local ID that may be reused in append & reuse "
"case. None until it has been found");
RNA_def_property_pointer_funcs(
prop, "rna_BlendImportContextItem_reusable_local_id_get", nullptr, nullptr, nullptr);
RNA_define_verify_sdna(true); /* not in sdna */
}
static void rna_def_blendfile_import_items(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
RNA_def_property_srna(cprop, "BlendImportContextItems");
srna = RNA_def_struct(brna, "BlendImportContextItems", nullptr);
RNA_def_struct_ui_text(
srna, "Blendfile Import Context Items", "Collection of blendfile import context items");
/* TODO: Add/Remove items _before_ doing link/append (i.e. for 'pre' handlers). */
}
static void rna_def_blendfile_import_context(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "BlendImportContext", nullptr);
RNA_def_struct_ui_text(
srna,
"Blendfile Import Context",
"Contextual data for a blendfile library/linked-data related operation. Currently "
"only exposed as read-only data for the pre/post blendimport handlers");
RNA_define_verify_sdna(false); /* not in sdna */
/* NOTE: Cannot use just `items` here as this is a reserved Python dict method name. */
prop = RNA_def_property(srna, "import_items", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BlendImportContextItem");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_collection_funcs(prop,
"rna_BlendImportContext_import_items_begin",
"rna_BlendImportContext_import_items_next",
"rna_BlendImportContext_import_items_end",
"rna_BlendImportContext_import_items_get",
"rna_BlendImportContext_import_items_len",
nullptr,
nullptr,
nullptr);
rna_def_blendfile_import_items(brna, prop);
static const EnumPropertyItem blend_import_options_items[] = {
{FILE_LINK, "LINK", 0, "", "Only link data, instead of appending it"},
{FILE_RELPATH,
"MAKE_PATHS_RELATIVE",
0,
"",
"Make paths of used library blendfiles relative to current blendfile"},
{BLO_LIBLINK_USE_PLACEHOLDERS,
"USE_PLACEHOLDERS",
0,
"",
"Generate a placeholder (empty ID) if not found in any library files"},
{BLO_LIBLINK_FORCE_INDIRECT,
"FORCE_INDIRECT",
0,
"",
"Force loaded ID to be tagged as indirectly linked (used in reload context only)"},
{BLO_LIBLINK_APPEND_SET_FAKEUSER,
"APPEND_SET_FAKEUSER",
0,
"",
"Set fake user on appended IDs"},
{BLO_LIBLINK_APPEND_RECURSIVE,
"APPEND_RECURSIVE",
0,
"",
"Append (make local) also indirect dependencies of appended IDs coming from other "
"libraries. NOTE: All IDs (including indirectly linked ones) coming from the same initial "
"library are always made local"},
{BLO_LIBLINK_APPEND_LOCAL_ID_REUSE,
"APPEND_LOCAL_ID_REUSE",
0,
"",
"Try to re-use previously appended matching IDs when appending them again, instead of "
"creating local duplicates"},
{BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR,
"APPEND_ASSET_DATA_CLEAR",
0,
"",
"Clear the asset data on append (it is always kept for linked data)"},
{FILE_AUTOSELECT, "SELECT_OBJECTS", 0, "", "Automatically select imported objects"},
{FILE_ACTIVE_COLLECTION,
"USE_ACTIVE_COLLECTION",
0,
"",
"Use the active Collection of the current View Layer to instantiate imported "
"collections and objects"},
{BLO_LIBLINK_OBDATA_INSTANCE,
"OBDATA_INSTANCE",
0,
"",
"Instantiate object data IDs (i.e. create objects for them if needed)"},
{BLO_LIBLINK_COLLECTION_INSTANCE,
"COLLECTION_INSTANCE",
0,
"",
"Instantiate collections as empties, instead of linking them into the current view layer"},
{0, nullptr, 0, nullptr, nullptr},
};
prop = RNA_def_property(srna, "options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, blend_import_options_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "", "Options for this blendfile import operation");
RNA_def_property_enum_funcs(prop, "rna_BlendImportContext_options_get", nullptr, nullptr);
/* NOTE: Only stages currently exposed to handlers are listed here. */
static const EnumPropertyItem blend_import_process_stage_items[] = {
{int(BlendfileLinkAppendContext::ProcessStage::Init),
"INIT",
0,
"",
"Blendfile import context has been initialized and filled with a list of items to import, "
"no data has been linked or appended yet"},
{int(BlendfileLinkAppendContext::ProcessStage::Done),
"DONE",
0,
"",
"All data has been imported and is available in the list of `import_items`"},
{0, nullptr, 0, nullptr, nullptr},
};
prop = RNA_def_property(srna, "process_stage", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, blend_import_process_stage_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "", "Current stage of the import process");
RNA_def_property_enum_funcs(prop, "rna_BlendImportContext_process_stage_get", nullptr, nullptr);
RNA_define_verify_sdna(true); /* not in sdna */
}
void RNA_def_blendfile_import(BlenderRNA *brna)
{
rna_def_blendfile_import_library(brna);
rna_def_blendfile_import_item(brna);
rna_def_blendfile_import_context(brna);
}
#endif /* RNA_RUNTIME */

View File

@@ -166,6 +166,7 @@ void RNA_def_key(BlenderRNA *brna);
void RNA_def_light(BlenderRNA *brna);
void RNA_def_lattice(BlenderRNA *brna);
void RNA_def_linestyle(BlenderRNA *brna);
void RNA_def_blendfile_import(BlenderRNA *brna);
void RNA_def_main(BlenderRNA *brna);
void RNA_def_material(BlenderRNA *brna);
void RNA_def_mesh(BlenderRNA *brna);

View File

@@ -99,6 +99,10 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{"_extension_repos_sync", "on creating or synchronizing the active repository"},
{"_extension_repos_files_clear",
"remove files from the repository directory (uses as a string argument)"},
{"blend_import_pre",
"on linking or appending data (before), get a single `BlendImportContext` parameter"},
{"blend_import_post",
"on linking or appending data (after), get a single `BlendImportContext` parameter"},
/* sets the permanent tag */
#define APP_CB_OTHER_FIELDS 1

View File

@@ -527,6 +527,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject * /*args*/)
}
}
BKE_blendfile_link_append_context_init_done(lapp_context);
BKE_blendfile_link(lapp_context, nullptr);
if (do_append) {
BKE_blendfile_append(lapp_context, nullptr);
@@ -535,6 +537,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject * /*args*/)
BKE_blendfile_override(lapp_context, self->liboverride_flags, nullptr);
}
BKE_blendfile_link_append_context_finalize(lapp_context);
/* If enabled, replace named items in given lists by the final matching new ID pointer. */
#ifdef USE_RNA_DATABLOCKS
idcode_step = 0;

View File

@@ -350,6 +350,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
BKE_blendfile_link_append_context_init_done(lapp_context);
/* XXX We'd need re-entrant locking on Main for this to work... */
// BKE_main_lock(bmain);
@@ -369,6 +371,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* Instantiate loose data in the scene (e.g. add object to the active collection). */
BKE_blendfile_link_append_instantiate_loose(lapp_context, op->reports);
BKE_blendfile_link_append_context_finalize(lapp_context);
BKE_blendfile_link_append_context_free(lapp_context);
/* Important we unset, otherwise these object won't
@@ -543,6 +547,8 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain,
lapp_context, id_name, id_code, nullptr);
BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
BKE_blendfile_link_append_context_init_done(lapp_context);
/* Link datablock. */
BKE_blendfile_link(lapp_context, nullptr);
@@ -552,6 +558,8 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain,
BKE_blendfile_link_append_instantiate_loose(lapp_context, nullptr);
BKE_blendfile_link_append_context_finalize(lapp_context);
/* Get linked datablock and free working data. */
ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);