diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_files_link.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_files_link.c | 1543 |
1 files changed, 807 insertions, 736 deletions
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 56dfe4a327d..14c032e6ffa 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -70,7 +70,6 @@ #include "RNA_access.h" #include "RNA_define.h" - #include "WM_api.h" #include "WM_types.h" @@ -80,198 +79,210 @@ static bool wm_link_append_poll(bContext *C) { - if (WM_operator_winactive(C)) { - /* linking changes active object which is pretty useful in general, - * but which totally confuses edit mode (i.e. it becoming not so obvious - * to leave from edit mode and invalid tools in toolbar might be displayed) - * so disable link/append when in edit mode (sergey) */ - if (CTX_data_edit_object(C)) { - return 0; - } - - return 1; - } - - return 0; + if (WM_operator_winactive(C)) { + /* linking changes active object which is pretty useful in general, + * but which totally confuses edit mode (i.e. it becoming not so obvious + * to leave from edit mode and invalid tools in toolbar might be displayed) + * so disable link/append when in edit mode (sergey) */ + if (CTX_data_edit_object(C)) { + return 0; + } + + return 1; + } + + return 0; } static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (!RNA_struct_property_is_set(op->ptr, "filepath")) { - if (G.lib[0] != '\0') { - RNA_string_set(op->ptr, "filepath", G.lib); - } - else if (G.relbase_valid) { - char path[FILE_MAX]; - BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); - BLI_parent_dir(path); - RNA_string_set(op->ptr, "filepath", path); - } - } - - WM_event_add_fileselect(C, op); - return OPERATOR_RUNNING_MODAL; + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + if (G.lib[0] != '\0') { + RNA_string_set(op->ptr, "filepath", G.lib); + } + else if (G.relbase_valid) { + char path[FILE_MAX]; + BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); + BLI_parent_dir(path); + RNA_string_set(op->ptr, "filepath", path); + } + } + + WM_event_add_fileselect(C, op); + return OPERATOR_RUNNING_MODAL; } static short wm_link_append_flag(wmOperator *op) { - PropertyRNA *prop; - short flag = 0; - - if (RNA_boolean_get(op->ptr, "autoselect")) { - flag |= FILE_AUTOSELECT; - } - if (RNA_boolean_get(op->ptr, "active_collection")) { - flag |= FILE_ACTIVE_COLLECTION; - } - if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop)) { - flag |= FILE_RELPATH; - } - if (RNA_boolean_get(op->ptr, "link")) { - flag |= FILE_LINK; - } - if (RNA_boolean_get(op->ptr, "instance_collections")) { - flag |= FILE_GROUP_INSTANCE; - } - - return flag; + PropertyRNA *prop; + short flag = 0; + + if (RNA_boolean_get(op->ptr, "autoselect")) { + flag |= FILE_AUTOSELECT; + } + if (RNA_boolean_get(op->ptr, "active_collection")) { + flag |= FILE_ACTIVE_COLLECTION; + } + if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && + RNA_property_boolean_get(op->ptr, prop)) { + flag |= FILE_RELPATH; + } + if (RNA_boolean_get(op->ptr, "link")) { + flag |= FILE_LINK; + } + if (RNA_boolean_get(op->ptr, "instance_collections")) { + flag |= FILE_GROUP_INSTANCE; + } + + return flag; } typedef struct WMLinkAppendDataItem { - char *name; - BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */ - short idcode; + char *name; + BLI_bitmap + *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */ + short idcode; - ID *new_id; - void *customdata; + ID *new_id; + void *customdata; } WMLinkAppendDataItem; typedef struct WMLinkAppendData { - LinkNodePair libraries; - LinkNodePair items; - int num_libraries; - int num_items; - int flag; /* Combines eFileSel_Params_Flag from DNA_space_types.h and BLO_LibLinkFlags from BLO_readfile.h */ - - /* Internal 'private' data */ - MemArena *memarena; + LinkNodePair libraries; + LinkNodePair items; + int num_libraries; + int num_items; + int flag; /* Combines eFileSel_Params_Flag from DNA_space_types.h and BLO_LibLinkFlags from BLO_readfile.h */ + + /* Internal 'private' data */ + MemArena *memarena; } WMLinkAppendData; static WMLinkAppendData *wm_link_append_data_new(const int flag) { - MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data)); + MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data)); - lapp_data->flag = flag; - lapp_data->memarena = ma; + lapp_data->flag = flag; + lapp_data->memarena = ma; - return lapp_data; + return lapp_data; } static void wm_link_append_data_free(WMLinkAppendData *lapp_data) { - BLI_memarena_free(lapp_data->memarena); + BLI_memarena_free(lapp_data->memarena); } /* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) { - size_t len = strlen(libname) + 1; - char *libpath = BLI_memarena_alloc(lapp_data->memarena, len); + size_t len = strlen(libname) + 1; + char *libpath = BLI_memarena_alloc(lapp_data->memarena, len); - BLI_strncpy(libpath, libname, len); - BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena); - lapp_data->num_libraries++; + BLI_strncpy(libpath, libname, len); + BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena); + lapp_data->num_libraries++; } -static WMLinkAppendDataItem *wm_link_append_data_item_add( - WMLinkAppendData *lapp_data, const char *idname, const short idcode, void *customdata) +static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data, + const char *idname, + const short idcode, + void *customdata) { - WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item)); - size_t len = strlen(idname) + 1; + WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item)); + size_t len = strlen(idname) + 1; - item->name = BLI_memarena_alloc(lapp_data->memarena, len); - BLI_strncpy(item->name, idname, len); - item->idcode = idcode; - item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries); + item->name = BLI_memarena_alloc(lapp_data->memarena, len); + BLI_strncpy(item->name, idname, len); + item->idcode = idcode; + item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries); - item->new_id = NULL; - item->customdata = customdata; + item->new_id = NULL; + item->customdata = customdata; - BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena); - lapp_data->num_items++; + BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena); + lapp_data->num_items++; - return item; + return item; } -static void wm_link_do( - WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, - Scene *scene, ViewLayer *view_layer, const View3D *v3d) +static void wm_link_do(WMLinkAppendData *lapp_data, + ReportList *reports, + Main *bmain, + Scene *scene, + ViewLayer *view_layer, + const View3D *v3d) { - Main *mainl; - BlendHandle *bh; - Library *lib; - - const int flag = lapp_data->flag; - - LinkNode *liblink, *itemlink; - int lib_idx, item_idx; - - BLI_assert(lapp_data->num_items && lapp_data->num_libraries); - - for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) { - char *libname = liblink->link; - - if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { - bh = BLO_blendhandle_from_memory(datatoc_startup_blend, datatoc_startup_blend_size); - } - else { - bh = BLO_blendhandle_from_file(libname, reports); - } - - if (bh == NULL) { - /* Unlikely since we just browsed it, but possible - * Error reports will have been made by BLO_blendhandle_from_file() */ - continue; - } - - /* here appending/linking starts */ - mainl = BLO_library_link_begin(bmain, &bh, libname); - lib = mainl->curlib; - BLI_assert(lib); - UNUSED_VARS_NDEBUG(lib); - - if (mainl->versionfile < 250) { - BKE_reportf(reports, RPT_WARNING, - "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will " - "be done! You may want to re-save your lib file with current Blender", - mainl->versionfile, mainl->subversionfile); - } - - /* For each lib file, we try to link all items belonging to that lib, - * and tag those successful to not try to load them again with the other libs. */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *new_id; - - if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { - continue; - } - - new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag); - - if (new_id) { - /* If the link is successful, clear item's libs 'todo' flags. - * This avoids trying to link same item with other libraries to come. */ - BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries); - item->new_id = new_id; - } - } - - BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer, v3d); - BLO_blendhandle_close(bh); - } + Main *mainl; + BlendHandle *bh; + Library *lib; + + const int flag = lapp_data->flag; + + LinkNode *liblink, *itemlink; + int lib_idx, item_idx; + + BLI_assert(lapp_data->num_items && lapp_data->num_libraries); + + for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; + lib_idx++, liblink = liblink->next) { + char *libname = liblink->link; + + if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { + bh = BLO_blendhandle_from_memory(datatoc_startup_blend, datatoc_startup_blend_size); + } + else { + bh = BLO_blendhandle_from_file(libname, reports); + } + + if (bh == NULL) { + /* Unlikely since we just browsed it, but possible + * Error reports will have been made by BLO_blendhandle_from_file() */ + continue; + } + + /* here appending/linking starts */ + mainl = BLO_library_link_begin(bmain, &bh, libname); + lib = mainl->curlib; + BLI_assert(lib); + UNUSED_VARS_NDEBUG(lib); + + if (mainl->versionfile < 250) { + BKE_reportf(reports, + RPT_WARNING, + "Linking or appending from a very old .blend file format (%d.%d), no animation " + "conversion will " + "be done! You may want to re-save your lib file with current Blender", + mainl->versionfile, + mainl->subversionfile); + } + + /* For each lib file, we try to link all items belonging to that lib, + * and tag those successful to not try to load them again with the other libs. */ + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *new_id; + + if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { + continue; + } + + new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag); + + if (new_id) { + /* If the link is successful, clear item's libs 'todo' flags. + * This avoids trying to link same item with other libraries to come. */ + BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries); + item->new_id = new_id; + } + } + + BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer, v3d); + BLO_blendhandle_close(bh); + } } /** @@ -279,295 +290,327 @@ static void wm_link_do( * * \param reports: Optionally report an error when an item can't be appended/linked. */ -static bool wm_link_append_item_poll( - ReportList *reports, const char *path, const char *group, const char *name, const bool do_append) +static bool wm_link_append_item_poll(ReportList *reports, + const char *path, + const char *group, + const char *name, + const bool do_append) { - short idcode; - - if (!group || !name) { - printf("skipping %s\n", path); - return false; - } - - idcode = BKE_idcode_from_name(group); - - /* XXX For now, we do a nasty exception for workspace, forbid linking them. - * Not nice, ultimately should be solved! */ - if (!BKE_idcode_is_linkable(idcode) && (do_append || idcode != ID_WS)) { - if (reports) { - if (do_append) { - BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't append data-block '%s' of type '%s'", name, group); - } - else { - BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't link data-block '%s' of type '%s'", name, group); - } - } - return false; - } - - return true; + short idcode; + + if (!group || !name) { + printf("skipping %s\n", path); + return false; + } + + idcode = BKE_idcode_from_name(group); + + /* XXX For now, we do a nasty exception for workspace, forbid linking them. + * Not nice, ultimately should be solved! */ + if (!BKE_idcode_is_linkable(idcode) && (do_append || idcode != ID_WS)) { + if (reports) { + if (do_append) { + BKE_reportf(reports, + RPT_ERROR_INVALID_INPUT, + "Can't append data-block '%s' of type '%s'", + name, + group); + } + else { + BKE_reportf(reports, + RPT_ERROR_INVALID_INPUT, + "Can't link data-block '%s' of type '%s'", + name, + group); + } + } + return false; + } + + return true; } static int wm_link_append_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - PropertyRNA *prop; - WMLinkAppendData *lapp_data; - char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX]; - char *group, *name; - int totfiles = 0; - - RNA_string_get(op->ptr, "filename", relname); - RNA_string_get(op->ptr, "directory", root); - - BLI_join_dirfile(path, sizeof(path), root, relname); - - /* test if we have a valid data */ - if (!BLO_library_path_explode(path, libname, &group, &name)) { - BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path); - return OPERATOR_CANCELLED; - } - else if (!group) { - BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); - return OPERATOR_CANCELLED; - } - else if (BLI_path_cmp(BKE_main_blendfile_path(bmain), libname) == 0) { - BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path); - return OPERATOR_CANCELLED; - } - - /* check if something is indicated for append/link */ - prop = RNA_struct_find_property(op->ptr, "files"); - if (prop) { - totfiles = RNA_property_collection_length(op->ptr, prop); - if (totfiles == 0) { - if (!name) { - BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); - return OPERATOR_CANCELLED; - } - } - } - else if (!name) { - BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); - return OPERATOR_CANCELLED; - } - - short flag = wm_link_append_flag(op); - const bool do_append = (flag & FILE_LINK) == 0; - - /* sanity checks for flag */ - if (scene && scene->id.lib) { - BKE_reportf(op->reports, RPT_WARNING, - "Scene '%s' is linked, instantiation of objects & groups is disabled", scene->id.name + 2); - flag &= ~FILE_GROUP_INSTANCE; - scene = NULL; - } - - /* We need to add nothing from BLO_LibLinkFlags to flag here. */ - - /* from here down, no error returns */ - - if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) { - BKE_view_layer_base_deselect_all(view_layer); - } - - /* tag everything, all untagged data can be made local - * its also generally useful to know what is new - * - * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); - - /* We define our working data... - * Note that here, each item 'uses' one library, and only one. */ - lapp_data = wm_link_append_data_new(flag); - if (totfiles != 0) { - GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); - int lib_idx = 0; - - RNA_BEGIN (op->ptr, itemptr, "files") - { - RNA_string_get(&itemptr, "name", relname); - - BLI_join_dirfile(path, sizeof(path), root, relname); - - if (BLO_library_path_explode(path, libname, &group, &name)) { - if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) { - continue; - } - - if (!BLI_ghash_haskey(libraries, libname)) { - BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx)); - lib_idx++; - wm_link_append_data_library_add(lapp_data, libname); - } - } - } - RNA_END; - - RNA_BEGIN (op->ptr, itemptr, "files") - { - RNA_string_get(&itemptr, "name", relname); - - BLI_join_dirfile(path, sizeof(path), root, relname); - - if (BLO_library_path_explode(path, libname, &group, &name)) { - WMLinkAppendDataItem *item; - - if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) { - continue; - } - - lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname)); - - item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, lib_idx); - } - } - RNA_END; - - BLI_ghash_free(libraries, MEM_freeN, NULL); - } - else { - WMLinkAppendDataItem *item; - - wm_link_append_data_library_add(lapp_data, libname); - item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); - } - - if (lapp_data->num_items == 0) { - /* Early out in case there is nothing to link. */ - wm_link_append_data_free(lapp_data); - return OPERATOR_CANCELLED; - } - - /* XXX We'd need re-entrant locking on Main for this to work... */ - /* BKE_main_lock(bmain); */ - - wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); - - /* BKE_main_unlock(bmain); */ - - /* mark all library linked objects to be updated */ - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + PropertyRNA *prop; + WMLinkAppendData *lapp_data; + char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX]; + char *group, *name; + int totfiles = 0; + + RNA_string_get(op->ptr, "filename", relname); + RNA_string_get(op->ptr, "directory", root); + + BLI_join_dirfile(path, sizeof(path), root, relname); + + /* test if we have a valid data */ + if (!BLO_library_path_explode(path, libname, &group, &name)) { + BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path); + return OPERATOR_CANCELLED; + } + else if (!group) { + BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); + return OPERATOR_CANCELLED; + } + else if (BLI_path_cmp(BKE_main_blendfile_path(bmain), libname) == 0) { + BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path); + return OPERATOR_CANCELLED; + } + + /* check if something is indicated for append/link */ + prop = RNA_struct_find_property(op->ptr, "files"); + if (prop) { + totfiles = RNA_property_collection_length(op->ptr, prop); + if (totfiles == 0) { + if (!name) { + BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); + return OPERATOR_CANCELLED; + } + } + } + else if (!name) { + BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); + return OPERATOR_CANCELLED; + } + + short flag = wm_link_append_flag(op); + const bool do_append = (flag & FILE_LINK) == 0; + + /* sanity checks for flag */ + if (scene && scene->id.lib) { + BKE_reportf(op->reports, + RPT_WARNING, + "Scene '%s' is linked, instantiation of objects & groups is disabled", + scene->id.name + 2); + flag &= ~FILE_GROUP_INSTANCE; + scene = NULL; + } + + /* We need to add nothing from BLO_LibLinkFlags to flag here. */ + + /* from here down, no error returns */ + + if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) { + BKE_view_layer_base_deselect_all(view_layer); + } + + /* tag everything, all untagged data can be made local + * its also generally useful to know what is new + * + * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* We define our working data... + * Note that here, each item 'uses' one library, and only one. */ + lapp_data = wm_link_append_data_new(flag); + if (totfiles != 0) { + GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); + int lib_idx = 0; + + RNA_BEGIN (op->ptr, itemptr, "files") { + RNA_string_get(&itemptr, "name", relname); + + BLI_join_dirfile(path, sizeof(path), root, relname); + + if (BLO_library_path_explode(path, libname, &group, &name)) { + if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) { + continue; + } + + if (!BLI_ghash_haskey(libraries, libname)) { + BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx)); + lib_idx++; + wm_link_append_data_library_add(lapp_data, libname); + } + } + } + RNA_END; + + RNA_BEGIN (op->ptr, itemptr, "files") { + RNA_string_get(&itemptr, "name", relname); + + BLI_join_dirfile(path, sizeof(path), root, relname); + + if (BLO_library_path_explode(path, libname, &group, &name)) { + WMLinkAppendDataItem *item; + + if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) { + continue; + } + + lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname)); + + item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL); + BLI_BITMAP_ENABLE(item->libraries, lib_idx); + } + } + RNA_END; + + BLI_ghash_free(libraries, MEM_freeN, NULL); + } + else { + WMLinkAppendDataItem *item; + + wm_link_append_data_library_add(lapp_data, libname); + item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL); + BLI_BITMAP_ENABLE(item->libraries, 0); + } + + if (lapp_data->num_items == 0) { + /* Early out in case there is nothing to link. */ + wm_link_append_data_free(lapp_data); + return OPERATOR_CANCELLED; + } + + /* XXX We'd need re-entrant locking on Main for this to work... */ + /* BKE_main_lock(bmain); */ + + wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + + /* BKE_main_unlock(bmain); */ + + /* mark all library linked objects to be updated */ + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* append, rather than linking */ + if (do_append) { + const bool set_fake = RNA_boolean_get(op->ptr, "set_fake"); + const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive"); + + if (use_recursive) { + BKE_library_make_local(bmain, NULL, NULL, true, set_fake); + } + else { + LinkNode *itemlink; + GSet *done_libraries = BLI_gset_new_ex( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__, lapp_data->num_libraries); + + for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { + ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id; - /* append, rather than linking */ - if (do_append) { - const bool set_fake = RNA_boolean_get(op->ptr, "set_fake"); - const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive"); - - if (use_recursive) { - BKE_library_make_local(bmain, NULL, NULL, true, set_fake); - } - else { - LinkNode *itemlink; - GSet *done_libraries = BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, - __func__, lapp_data->num_libraries); + if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) { + BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake); + BLI_gset_insert(done_libraries, new_id->lib); + } + } + + BLI_gset_free(done_libraries, NULL); + } + } - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id; - - if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) { - BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake); - BLI_gset_insert(done_libraries, new_id->lib); - } - } - - BLI_gset_free(done_libraries, NULL); - } - } - - wm_link_append_data_free(lapp_data); + wm_link_append_data_free(lapp_data); - /* important we unset, otherwise these object wont - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + /* important we unset, otherwise these object wont + * link into other scenes from this blend file */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - /* TODO(sergey): Use proper flag for tagging here. */ + /* TODO(sergey): Use proper flag for tagging here. */ - /* TODO (dalai): Temporary solution! - * Ideally we only need to tag the new objects themselves, not the scene. This way we'll avoid flush of - * collection properties to all objects and limit update to the particular object only. - * But afraid first we need to change collection evaluation in DEG according to depsgraph manifesto. - */ - DEG_id_tag_update(&scene->id, 0); + /* TODO (dalai): Temporary solution! + * Ideally we only need to tag the new objects themselves, not the scene. This way we'll avoid flush of + * collection properties to all objects and limit update to the particular object only. + * But afraid first we need to change collection evaluation in DEG according to depsgraph manifesto. + */ + DEG_id_tag_update(&scene->id, 0); - /* recreate dependency graph to include new objects */ - DEG_relations_tag_update(bmain); + /* recreate dependency graph to include new objects */ + DEG_relations_tag_update(bmain); - /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ - BLI_strncpy(G.lib, root, FILE_MAX); + /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ + BLI_strncpy(G.lib, root, FILE_MAX); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link) { - PropertyRNA *prop; - - /* better not save _any_ settings for this operator */ - /* properties */ - prop = RNA_def_boolean(ot->srna, "link", is_link, - "Link", "Link the objects or data-blocks rather than appending"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_boolean(ot->srna, "autoselect", true, - "Select", "Select new objects"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "active_collection", true, - "Active Collection", "Put new objects on the active collection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "instance_collections", is_link, - "Instance Collections", "Create instances for collections, rather than adding them directly to the scene"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* better not save _any_ settings for this operator */ + /* properties */ + prop = RNA_def_boolean( + ot->srna, "link", is_link, "Link", "Link the objects or data-blocks rather than appending"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "autoselect", true, "Select", "Select new objects"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, + "active_collection", + true, + "Active Collection", + "Put new objects on the active collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, + "instance_collections", + is_link, + "Instance Collections", + "Create instances for collections, rather than adding them directly to the scene"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } void WM_OT_link(wmOperatorType *ot) { - ot->name = "Link from Library"; - ot->idname = "WM_OT_link"; - ot->description = "Link from a Library .blend file"; - - ot->invoke = wm_link_append_invoke; - ot->exec = wm_link_append_exec; - ot->poll = wm_link_append_poll; - - ot->flag |= OPTYPE_UNDO; - - WM_operator_properties_filesel( - ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES, - FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); - - wm_link_append_properties_common(ot, true); + ot->name = "Link from Library"; + ot->idname = "WM_OT_link"; + ot->description = "Link from a Library .blend file"; + + ot->invoke = wm_link_append_invoke; + ot->exec = wm_link_append_exec; + ot->poll = wm_link_append_poll; + + ot->flag |= OPTYPE_UNDO; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, + FILE_LOADLIB, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | + WM_FILESEL_RELPATH | WM_FILESEL_FILES, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + wm_link_append_properties_common(ot, true); } void WM_OT_append(wmOperatorType *ot) { - ot->name = "Append from Library"; - ot->idname = "WM_OT_append"; - ot->description = "Append from a Library .blend file"; - - ot->invoke = wm_link_append_invoke; - ot->exec = wm_link_append_exec; - ot->poll = wm_link_append_poll; - - ot->flag |= OPTYPE_UNDO; - - WM_operator_properties_filesel( - ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES, - FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); - - wm_link_append_properties_common(ot, false); - RNA_def_boolean(ot->srna, "set_fake", false, "Fake User", - "Set Fake User for appended items (except Objects and Groups)"); - RNA_def_boolean(ot->srna, "use_recursive", true, "Localize All", - "Localize all appended data, including those indirectly linked from other libraries"); + ot->name = "Append from Library"; + ot->idname = "WM_OT_append"; + ot->description = "Append from a Library .blend file"; + + ot->invoke = wm_link_append_invoke; + ot->exec = wm_link_append_exec; + ot->poll = wm_link_append_poll; + + ot->flag |= OPTYPE_UNDO; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, + FILE_LOADLIB, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | + WM_FILESEL_FILES, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + wm_link_append_properties_common(ot, false); + RNA_def_boolean(ot->srna, + "set_fake", + false, + "Fake User", + "Set Fake User for appended items (except Objects and Groups)"); + RNA_def_boolean( + ot->srna, + "use_recursive", + true, + "Localize All", + "Localize all appended data, including those indirectly linked from other libraries"); } /** \name Reload/relocate libraries. @@ -576,415 +619,443 @@ void WM_OT_append(wmOperatorType *ot) static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Library *lib; - char lib_name[MAX_NAME]; + Library *lib; + char lib_name[MAX_NAME]; - RNA_string_get(op->ptr, "library", lib_name); - lib = (Library *)BKE_libblock_find_name(CTX_data_main(C), ID_LI, lib_name); + RNA_string_get(op->ptr, "library", lib_name); + lib = (Library *)BKE_libblock_find_name(CTX_data_main(C), ID_LI, lib_name); - if (lib) { - if (lib->parent) { - BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, - "Cannot relocate indirectly linked library '%s'", lib->filepath); - return OPERATOR_CANCELLED; - } - RNA_string_set(op->ptr, "filepath", lib->filepath); + if (lib) { + if (lib->parent) { + BKE_reportf(op->reports, + RPT_ERROR_INVALID_INPUT, + "Cannot relocate indirectly linked library '%s'", + lib->filepath); + return OPERATOR_CANCELLED; + } + RNA_string_set(op->ptr, "filepath", lib->filepath); - WM_event_add_fileselect(C, op); + WM_event_add_fileselect(C, op); - return OPERATOR_RUNNING_MODAL; - } + return OPERATOR_RUNNING_MODAL; + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } -static void lib_relocate_do( - Main *bmain, - Library *library, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload) +static void lib_relocate_do(Main *bmain, + Library *library, + WMLinkAppendData *lapp_data, + ReportList *reports, + const bool do_reload) { - ListBase *lbarray[MAX_LIBARRAY]; - int lba_idx; + ListBase *lbarray[MAX_LIBARRAY]; + int lba_idx; - LinkNode *itemlink; - int item_idx; + LinkNode *itemlink; + int item_idx; - /* Remove all IDs to be reloaded from Main. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id = lbarray[lba_idx]->first; - const short idcode = id ? GS(id->name) : 0; + /* Remove all IDs to be reloaded from Main. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id = lbarray[lba_idx]->first; + const short idcode = id ? GS(id->name) : 0; - if (!id || !BKE_idcode_is_linkable(idcode)) { - /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */ - continue; - } + if (!id || !BKE_idcode_is_linkable(idcode)) { + /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */ + continue; + } - for (; id; id = id->next) { - if (id->lib == library) { - WMLinkAppendDataItem *item; + for (; id; id = id->next) { + if (id->lib == library) { + WMLinkAppendDataItem *item; - /* We remove it from current Main, and add it to items to link... */ - /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ - BLI_remlink(lbarray[lba_idx], id); - item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); - BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries); + /* We remove it from current Main, and add it to items to link... */ + /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ + BLI_remlink(lbarray[lba_idx], id); + item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); + BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries); #ifdef PRINT_DEBUG - printf("\tdatablock to seek for: %s\n", id->name); + printf("\tdatablock to seek for: %s\n", id->name); #endif - } - } - } - - if (lapp_data->num_items == 0) { - /* Early out in case there is nothing to do. */ - return; - } - - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); - - /* We do not want any instantiation here! */ - wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL); - - BKE_main_lock(bmain); - - /* We add back old id to bmain. - * We need to do this in a first, separated loop, otherwise some of those may not be handled by - * ID remapping, which means they would still reference old data to be deleted... */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - BLI_assert(old_id); - BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); - } - - /* Note that in reload case, we also want to replace indirect usages. */ - const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | - (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - ID *new_id = item->new_id; - - BLI_assert(old_id); - if (do_reload) { - /* Since we asked for placeholders in case of missing IDs, we expect to always get a valid one. */ - BLI_assert(new_id); - } - if (new_id) { + } + } + } + + if (lapp_data->num_items == 0) { + /* Early out in case there is nothing to do. */ + return; + } + + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* We do not want any instantiation here! */ + wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL); + + BKE_main_lock(bmain); + + /* We add back old id to bmain. + * We need to do this in a first, separated loop, otherwise some of those may not be handled by + * ID remapping, which means they would still reference old data to be deleted... */ + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *old_id = item->customdata; + + BLI_assert(old_id); + BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); + } + + /* Note that in reload case, we also want to replace indirect usages. */ + const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | + ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | + (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *old_id = item->customdata; + ID *new_id = item->new_id; + + BLI_assert(old_id); + if (do_reload) { + /* Since we asked for placeholders in case of missing IDs, we expect to always get a valid one. */ + BLI_assert(new_id); + } + if (new_id) { #ifdef PRINT_DEBUG - printf("before remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); + printf("before remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); #endif - BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); + BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); - if (old_id->flag & LIB_FAKEUSER) { - id_fake_user_clear(old_id); - id_fake_user_set(new_id); - } + if (old_id->flag & LIB_FAKEUSER) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } #ifdef PRINT_DEBUG - printf("after remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); + printf("after remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); #endif - /* In some cases, new_id might become direct link, remove parent of library in this case. */ - if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { - if (do_reload) { - BLI_assert(0); /* Should not happen in 'pure' reload case... */ - } - new_id->lib->parent = NULL; - } - } - - if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { - /* Note that this *should* not happen - but better be safe than sorry in this area, at least until we are - * 100% sure this cannot ever happen. - * Also, we can safely assume names were unique so far, so just replacing '.' by '~' should work, - * but this does not totally rules out the possibility of name collision. */ - size_t len = strlen(old_id->name); - size_t dot_pos; - bool has_num = false; - - for (dot_pos = len; dot_pos--;) { - char c = old_id->name[dot_pos]; - if (c == '.') { - break; - } - else if (c < '0' || c > '9') { - has_num = false; - break; - } - has_num = true; - } - - if (has_num) { - old_id->name[dot_pos] = '~'; - } - else { - len = MIN2(len, MAX_ID_NAME - 7); - BLI_strncpy(&old_id->name[len], "~000", 7); - } - - id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id); - - BKE_reportf(reports, RPT_WARNING, - "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " - "old one (%d remaining users) had to be kept and was renamed to '%s'", - new_id->name, old_id->us, old_id->name); - } - } - - BKE_main_unlock(bmain); - - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - if (old_id->us == 0) { - BKE_id_free(bmain, old_id); - } - } - - /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable (shape keys e.g.), - * so we need another loop here to clear old ones if possible. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id, *id_next; - for (id = lbarray[lba_idx]->first; id; id = id_next) { - id_next = id->next; - /* XXX That check may be a bit to generic/permissive? */ - if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { - BKE_id_free(bmain, id); - } - } - } - - /* Get rid of no more used libraries... */ - BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id; - for (id = lbarray[lba_idx]->first; id; id = id->next) { - if (id->lib) { - id->lib->id.tag &= ~LIB_TAG_DOIT; - } - } - } - Library *lib, *lib_next; - for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { - lib_next = lib->id.next; - if (lib->id.tag & LIB_TAG_DOIT) { - id_us_clear_real(&lib->id); - if (lib->id.us == 0) { - BKE_id_free(bmain, (ID *)lib); - } - } - } - - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); - - /* important we unset, otherwise these object wont - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* recreate dependency graph to include new objects */ - DEG_relations_tag_update(bmain); + /* In some cases, new_id might become direct link, remove parent of library in this case. */ + if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { + if (do_reload) { + BLI_assert(0); /* Should not happen in 'pure' reload case... */ + } + new_id->lib->parent = NULL; + } + } + + if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { + /* Note that this *should* not happen - but better be safe than sorry in this area, at least until we are + * 100% sure this cannot ever happen. + * Also, we can safely assume names were unique so far, so just replacing '.' by '~' should work, + * but this does not totally rules out the possibility of name collision. */ + size_t len = strlen(old_id->name); + size_t dot_pos; + bool has_num = false; + + for (dot_pos = len; dot_pos--;) { + char c = old_id->name[dot_pos]; + if (c == '.') { + break; + } + else if (c < '0' || c > '9') { + has_num = false; + break; + } + has_num = true; + } + + if (has_num) { + old_id->name[dot_pos] = '~'; + } + else { + len = MIN2(len, MAX_ID_NAME - 7); + BLI_strncpy(&old_id->name[len], "~000", 7); + } + + id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id); + + BKE_reportf( + reports, + RPT_WARNING, + "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " + "old one (%d remaining users) had to be kept and was renamed to '%s'", + new_id->name, + old_id->us, + old_id->name); + } + } + + BKE_main_unlock(bmain); + + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *old_id = item->customdata; + + if (old_id->us == 0) { + BKE_id_free(bmain, old_id); + } + } + + /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable (shape keys e.g.), + * so we need another loop here to clear old ones if possible. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id, *id_next; + for (id = lbarray[lba_idx]->first; id; id = id_next) { + id_next = id->next; + /* XXX That check may be a bit to generic/permissive? */ + if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { + BKE_id_free(bmain, id); + } + } + } + + /* Get rid of no more used libraries... */ + BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id; + for (id = lbarray[lba_idx]->first; id; id = id->next) { + if (id->lib) { + id->lib->id.tag &= ~LIB_TAG_DOIT; + } + } + } + Library *lib, *lib_next; + for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { + lib_next = lib->id.next; + if (lib->id.tag & LIB_TAG_DOIT) { + id_us_clear_real(&lib->id); + if (lib->id.us == 0) { + BKE_id_free(bmain, (ID *)lib); + } + } + } + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* important we unset, otherwise these object wont + * link into other scenes from this blend file */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* recreate dependency graph to include new objects */ + DEG_relations_tag_update(bmain); } void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) { - if (!BLO_has_bfile_extension(lib->filepath)) { - BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath); - return; - } + if (!BLO_has_bfile_extension(lib->filepath)) { + BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath); + return; + } - if (!BLI_exists(lib->filepath)) { - BKE_reportf(reports, RPT_ERROR, - "Trying to reload library '%s' from invalid path '%s'", lib->id.name, lib->filepath); - return; - } + if (!BLI_exists(lib->filepath)) { + BKE_reportf(reports, + RPT_ERROR, + "Trying to reload library '%s' from invalid path '%s'", + lib->id.name, + lib->filepath); + return; + } - WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT); + WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | + BLO_LIBLINK_FORCE_INDIRECT); - wm_link_append_data_library_add(lapp_data, lib->filepath); + wm_link_append_data_library_add(lapp_data, lib->filepath); - lib_relocate_do(CTX_data_main(C), lib, lapp_data, reports, true); + lib_relocate_do(CTX_data_main(C), lib, lapp_data, reports, true); - wm_link_append_data_free(lapp_data); + wm_link_append_data_free(lapp_data); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, NULL); } static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) { - Library *lib; - char lib_name[MAX_NAME]; - - RNA_string_get(op->ptr, "library", lib_name); - lib = (Library *)BKE_libblock_find_name(CTX_data_main(C), ID_LI, lib_name); - - if (lib) { - Main *bmain = CTX_data_main(C); - PropertyRNA *prop; - WMLinkAppendData *lapp_data; - - char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; - short flag = 0; - - if (RNA_boolean_get(op->ptr, "relative_path")) { - flag |= FILE_RELPATH; - } - - if (lib->parent && !do_reload) { - BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, - "Cannot relocate indirectly linked library '%s'", lib->filepath); - return OPERATOR_CANCELLED; - } - - RNA_string_get(op->ptr, "directory", root); - RNA_string_get(op->ptr, "filename", libname); - - if (!BLO_has_bfile_extension(libname)) { - BKE_report(op->reports, RPT_ERROR, "Not a library"); - return OPERATOR_CANCELLED; - } - - BLI_join_dirfile(path, sizeof(path), root, libname); - - if (!BLI_exists(path)) { - BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, - "Trying to reload or relocate library '%s' to invalid path '%s'", lib->id.name, path); - return OPERATOR_CANCELLED; - } - - if (BLI_path_cmp(lib->filepath, path) == 0) { + Library *lib; + char lib_name[MAX_NAME]; + + RNA_string_get(op->ptr, "library", lib_name); + lib = (Library *)BKE_libblock_find_name(CTX_data_main(C), ID_LI, lib_name); + + if (lib) { + Main *bmain = CTX_data_main(C); + PropertyRNA *prop; + WMLinkAppendData *lapp_data; + + char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; + short flag = 0; + + if (RNA_boolean_get(op->ptr, "relative_path")) { + flag |= FILE_RELPATH; + } + + if (lib->parent && !do_reload) { + BKE_reportf(op->reports, + RPT_ERROR_INVALID_INPUT, + "Cannot relocate indirectly linked library '%s'", + lib->filepath); + return OPERATOR_CANCELLED; + } + + RNA_string_get(op->ptr, "directory", root); + RNA_string_get(op->ptr, "filename", libname); + + if (!BLO_has_bfile_extension(libname)) { + BKE_report(op->reports, RPT_ERROR, "Not a library"); + return OPERATOR_CANCELLED; + } + + BLI_join_dirfile(path, sizeof(path), root, libname); + + if (!BLI_exists(path)) { + BKE_reportf(op->reports, + RPT_ERROR_INVALID_INPUT, + "Trying to reload or relocate library '%s' to invalid path '%s'", + lib->id.name, + path); + return OPERATOR_CANCELLED; + } + + if (BLI_path_cmp(lib->filepath, path) == 0) { #ifdef PRINT_DEBUG - printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us); + printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us); #endif - do_reload = true; + do_reload = true; - lapp_data = wm_link_append_data_new(flag); - wm_link_append_data_library_add(lapp_data, path); - } - else { - int totfiles = 0; + lapp_data = wm_link_append_data_new(flag); + wm_link_append_data_library_add(lapp_data, path); + } + else { + int totfiles = 0; #ifdef PRINT_DEBUG - printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname); + printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname); #endif - /* Check if something is indicated for relocate. */ - prop = RNA_struct_find_property(op->ptr, "files"); - if (prop) { - totfiles = RNA_property_collection_length(op->ptr, prop); - if (totfiles == 0) { - if (!libname[0]) { - BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); - return OPERATOR_CANCELLED; - } - } - } + /* Check if something is indicated for relocate. */ + prop = RNA_struct_find_property(op->ptr, "files"); + if (prop) { + totfiles = RNA_property_collection_length(op->ptr, prop); + if (totfiles == 0) { + if (!libname[0]) { + BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); + return OPERATOR_CANCELLED; + } + } + } - lapp_data = wm_link_append_data_new(flag); + lapp_data = wm_link_append_data_new(flag); - if (totfiles) { - RNA_BEGIN (op->ptr, itemptr, "files") - { - RNA_string_get(&itemptr, "name", relname); + if (totfiles) { + RNA_BEGIN (op->ptr, itemptr, "files") { + RNA_string_get(&itemptr, "name", relname); - BLI_join_dirfile(path, sizeof(path), root, relname); + BLI_join_dirfile(path, sizeof(path), root, relname); - if (BLI_path_cmp(path, lib->filepath) == 0 || !BLO_has_bfile_extension(relname)) { - continue; - } + if (BLI_path_cmp(path, lib->filepath) == 0 || !BLO_has_bfile_extension(relname)) { + continue; + } #ifdef PRINT_DEBUG - printf("\t candidate new lib to reload datablocks from: %s\n", path); + printf("\t candidate new lib to reload datablocks from: %s\n", path); #endif - wm_link_append_data_library_add(lapp_data, path); - } - RNA_END; - } - else { + wm_link_append_data_library_add(lapp_data, path); + } + RNA_END; + } + else { #ifdef PRINT_DEBUG - printf("\t candidate new lib to reload datablocks from: %s\n", path); + printf("\t candidate new lib to reload datablocks from: %s\n", path); #endif - wm_link_append_data_library_add(lapp_data, path); - } - } + wm_link_append_data_library_add(lapp_data, path); + } + } - if (do_reload) { - lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; - } + if (do_reload) { + lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; + } - lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload); + lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload); - wm_link_append_data_free(lapp_data); + wm_link_append_data_free(lapp_data); - /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ - BLI_strncpy(G.lib, root, FILE_MAX); + /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ + BLI_strncpy(G.lib, root, FILE_MAX); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } static int wm_lib_relocate_exec(bContext *C, wmOperator *op) { - return wm_lib_relocate_exec_do(C, op, false); + return wm_lib_relocate_exec_do(C, op, false); } void WM_OT_lib_relocate(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - ot->name = "Relocate Library"; - ot->idname = "WM_OT_lib_relocate"; - ot->description = "Relocate the given library to one or several others"; + ot->name = "Relocate Library"; + ot->idname = "WM_OT_lib_relocate"; + ot->description = "Relocate the given library to one or several others"; - ot->invoke = wm_lib_relocate_invoke; - ot->exec = wm_lib_relocate_exec; + ot->invoke = wm_lib_relocate_invoke; + ot->exec = wm_lib_relocate_exec; - ot->flag |= OPTYPE_UNDO; + ot->flag |= OPTYPE_UNDO; - prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate"); - RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate"); + RNA_def_property_flag(prop, PROP_HIDDEN); - WM_operator_properties_filesel( - ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES | WM_FILESEL_RELPATH, - FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | + WM_FILESEL_FILES | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); } static int wm_lib_reload_exec(bContext *C, wmOperator *op) { - return wm_lib_relocate_exec_do(C, op, true); + return wm_lib_relocate_exec_do(C, op, true); } void WM_OT_lib_reload(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - ot->name = "Reload Library"; - ot->idname = "WM_OT_lib_reload"; - ot->description = "Reload the given library"; + ot->name = "Reload Library"; + ot->idname = "WM_OT_lib_reload"; + ot->description = "Reload the given library"; - ot->exec = wm_lib_reload_exec; + ot->exec = wm_lib_reload_exec; - ot->flag |= OPTYPE_UNDO; + ot->flag |= OPTYPE_UNDO; - prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload"); - RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload"); + RNA_def_property_flag(prop, PROP_HIDDEN); - WM_operator_properties_filesel( - ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH, - FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | + WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); } /** \} */ |