Blender V5.0
wm_files_link.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cctype>
12#include <cerrno>
13#include <cfloat>
14#include <cstring>
15
16#include "CLG_log.h"
17
18#include "DNA_ID.h"
19#include "DNA_scene_types.h"
20#include "DNA_screen_types.h"
22
23#include "BLI_fileops.h"
24#include "BLI_map.hh"
25#include "BLI_path_utils.hh"
26#include "BLI_string.h"
27
28#include "BLO_readfile.hh"
29
30#include "BKE_armature.hh"
31#include "BKE_blendfile.hh"
33#include "BKE_context.hh"
34#include "BKE_global.hh"
35#include "BKE_key.hh"
36#include "BKE_layer.hh"
37#include "BKE_lib_id.hh"
38#include "BKE_lib_override.hh"
39#include "BKE_lib_query.hh"
40#include "BKE_lib_remap.hh"
41#include "BKE_library.hh"
42#include "BKE_main.hh"
43#include "BKE_material.hh"
44#include "BKE_object.hh"
45#include "BKE_report.hh"
46#include "BKE_rigidbody.h"
47#include "BKE_scene.hh"
48
49#include "BKE_idtype.hh"
50
51#include "DEG_depsgraph.hh"
53
55
56#include "ED_datafiles.h"
57#include "ED_screen.hh"
58
59#include "RNA_access.hh"
60#include "RNA_define.hh"
61
62#include "WM_api.hh"
63#include "WM_types.hh"
64
65#include "wm_files.hh"
66
67static CLG_LogRef LOG = {"blend.link"};
68
69/* -------------------------------------------------------------------- */
72
74{
76 /* NOTE(@sergey): Linking changes active object which is pretty useful in general,
77 * but which totally confuses edit mode (i.e. it becoming not so obvious
78 * to leave from edit mode and invalid tools in toolbar might be displayed)
79 * so disable link/append when in edit mode. */
81 return false;
82 }
83
84 return true;
85 }
86
87 return false;
88}
89
91 wmOperator *op,
92 const wmEvent * /*event*/)
93{
94 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
95 const char *blendfile_path = BKE_main_blendfile_path_from_global();
96 if (G.filepath_last_library[0] != '\0') {
97 RNA_string_set(op->ptr, "filepath", G.filepath_last_library);
98 }
99 else if (blendfile_path[0] != '\0') {
100 char dirpath[FILE_MAX];
101 BLI_path_split_dir_part(blendfile_path, dirpath, sizeof(dirpath));
102 RNA_string_set(op->ptr, "filepath", dirpath);
103 }
104 }
105
108}
109
111{
112 /* NOTE: most options exposed here should also be available in the Python API
113 * unless there are good reasons to have them only exposed to the operator.
114 * see `bpy_lib_load`. */
115 PropertyRNA *prop;
116 int flag = 0;
117
118 if (RNA_boolean_get(op->ptr, "autoselect")) {
120 }
121 if (RNA_boolean_get(op->ptr, "active_collection")) {
123 }
124 if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) &&
125 RNA_property_boolean_get(op->ptr, prop))
126 {
128 }
129 if (RNA_boolean_get(op->ptr, "link")) {
130 flag |= FILE_LINK;
131 }
132 else {
133 if (RNA_boolean_get(op->ptr, "use_recursive")) {
135 }
136 if (RNA_boolean_get(op->ptr, "set_fake")) {
138 }
139 if (RNA_boolean_get(op->ptr, "do_reuse_local_id")) {
141 }
142 if (RNA_boolean_get(op->ptr, "clear_asset_data")) {
144 }
145 }
146 if (RNA_boolean_get(op->ptr, "instance_collections")) {
148 }
149 if (RNA_boolean_get(op->ptr, "instance_object_data")) {
151 }
152
153 return flag;
154}
155
162 const char *filepath,
163 const char *group,
164 const char *name,
165 const bool do_append)
166{
167 short idcode;
168
169 if (!group || !name) {
170 CLOG_WARN(&LOG, "Skipping %s", filepath);
171 return false;
172 }
173
174 idcode = BKE_idtype_idcode_from_name(group);
175
176 if (!BKE_idtype_idcode_is_linkable(idcode) ||
177 (!do_append && BKE_idtype_idcode_is_only_appendable(idcode)))
178 {
179 if (reports) {
180 if (do_append) {
181 BKE_reportf(reports,
183 "Cannot append data-block '%s' of type '%s'",
184 name,
185 group);
186 }
187 else {
188 BKE_reportf(reports,
190 "Cannot link data-block '%s' of type '%s'",
191 name,
192 group);
193 }
194 }
195 return false;
196 }
197
198 return true;
199}
200
202{
203 Main *bmain = CTX_data_main(C);
204 const char *blendfile_path = BKE_main_blendfile_path(bmain);
205 Scene *scene = CTX_data_scene(C);
206 ViewLayer *view_layer = CTX_data_view_layer(C);
207 PropertyRNA *prop;
208 BlendfileLinkAppendContext *lapp_context;
209 char filepath[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA],
210 relname[FILE_MAX];
211 char *group, *name;
212 int totfiles = 0;
213
214 RNA_string_get(op->ptr, "filename", relname);
215 RNA_string_get(op->ptr, "directory", root);
216 if (BLI_path_is_rel(root)) {
217 BLI_path_abs(root, blendfile_path);
218 }
219
220 BLI_path_join(filepath, sizeof(filepath), root, relname);
221
222 /* Test if we have a valid data. */
223 const bool is_librarypath_valid = BKE_blendfile_library_path_explode(
224 filepath, libname, &group, &name);
225
226 {
227 if (blendfile_path[0] != '\0') {
228 /* NOTE: Need to also check `filepath`, as typically `libname` is an empty string here
229 * (when trying to append from current file from the file-browser e.g.). */
230 if (BLI_path_cmp(blendfile_path, filepath) == 0 ||
231 BLI_path_cmp(blendfile_path, libname) == 0)
232 {
233 BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", filepath);
234 return OPERATOR_CANCELLED;
235 }
236 }
237 }
238
239 if (!group) {
240 BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", filepath);
241 return OPERATOR_CANCELLED;
242 }
243 if (!is_librarypath_valid) {
244 BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", filepath);
245 return OPERATOR_CANCELLED;
246 }
247
248 /* Check if something is indicated for append/link. */
249 prop = RNA_struct_find_property(op->ptr, "files");
250 if (prop) {
251 totfiles = RNA_property_collection_length(op->ptr, prop);
252 if (totfiles == 0) {
253 if (!name) {
254 BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", filepath);
255 return OPERATOR_CANCELLED;
256 }
257 }
258 }
259 else if (!name) {
260 BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", filepath);
261 return OPERATOR_CANCELLED;
262 }
263
264 int flag = wm_link_append_flag(op);
265 const bool do_append = (flag & FILE_LINK) == 0;
266
267 /* From here down, no error returns. */
268
269 if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) {
270 BKE_view_layer_base_deselect_all(scene, view_layer);
271 }
272
273 /* Sanity checks for flag. */
274 if (scene && scene->id.lib) {
277 "Scene '%s' is linked, instantiation of objects is disabled",
278 scene->id.name + 2);
280 scene = nullptr;
281 }
282
283 /* Tag everything, all untagged data can be made local
284 * its also generally useful to know what is new.
285 *
286 * Take extra care `BKE_main_id_flag_all(bmain, ID_TAG_PRE_EXISTING, false)` is called after! */
288
289 /* We define our working data...
290 * Note that here, each item 'uses' one library, and only one. */
291 LibraryLink_Params lapp_params;
293 &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C));
294
295 lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
298
299 if (totfiles != 0) {
301 int lib_idx = 0;
302
303 RNA_BEGIN (op->ptr, itemptr, "files") {
304 RNA_string_get(&itemptr, "name", relname);
305
306 BLI_path_join(filepath, sizeof(filepath), root, relname);
307
308 if (BKE_blendfile_library_path_explode(filepath, libname, &group, &name)) {
309 if (!wm_link_append_item_poll(nullptr, filepath, group, name, do_append)) {
310 continue;
311 }
312
313 if (libraries.add(libname, lib_idx)) {
314 lib_idx++;
315 BKE_blendfile_link_append_context_library_add(lapp_context, libname, nullptr);
316 }
317 }
318 }
319 RNA_END;
320
321 RNA_BEGIN (op->ptr, itemptr, "files") {
322 RNA_string_get(&itemptr, "name", relname);
323
324 BLI_path_join(filepath, sizeof(filepath), root, relname);
325
326 if (BKE_blendfile_library_path_explode(filepath, libname, &group, &name)) {
328
329 if (!wm_link_append_item_poll(op->reports, filepath, group, name, do_append)) {
330 continue;
331 }
332
333 lib_idx = libraries.lookup(libname);
334
336 lapp_context, name, BKE_idtype_idcode_from_name(group), nullptr);
338 }
339 }
340 RNA_END;
341 }
342 else {
344
345 BKE_blendfile_link_append_context_library_add(lapp_context, libname, nullptr);
347 lapp_context, name, BKE_idtype_idcode_from_name(group), nullptr);
349 }
350
352 /* Early out in case there is nothing to link. */
354 /* Clear pre existing tag. */
356 return OPERATOR_CANCELLED;
357 }
358
360
361 /* XXX We'd need re-entrant locking on Main for this to work... */
362 // BKE_main_lock(bmain);
363
364 BKE_blendfile_link(lapp_context, op->reports);
365
366 // BKE_main_unlock(bmain);
367
368 /* Mark all library linked objects to be updated. */
371
372 /* Append, rather than linking. */
373 if (do_append) {
374 BKE_blendfile_append(lapp_context, op->reports);
375 }
376
377 /* Instantiate loose data in the scene (e.g. add object to the active collection). */
379
381
383
384 /* Important we unset, otherwise these object won't
385 * link into other scenes from this blend file. */
387
388 /* TODO(sergey): Use proper flag for tagging here. */
389
390 /* TODO(dalai): Temporary solution!
391 * Ideally we only need to tag the new objects themselves, not the scene.
392 * This way we'll avoid flush of collection properties
393 * to all objects and limit update to the particular object only.
394 * But afraid first we need to change collection evaluation in DEG
395 * according to depsgraph manifesto. */
396 if (scene) {
397 DEG_id_tag_update(&scene->id, 0);
398 }
399
400 /* Recreate dependency graph to include new objects. */
402
403 /* TODO: align `G.filepath_last_library` with other directory storage
404 * (like last opened image, etc). */
405 STRNCPY(G.filepath_last_library, root);
406
408
409 return OPERATOR_FINISHED;
410}
411
413 const bool is_link,
414 const bool is_relocate)
415{
416 PropertyRNA *prop;
417
418 /* Better not save _any_ settings for this operator. */
419
420 /* Properties. */
421 prop = RNA_def_boolean(ot->srna,
422 "link",
423 is_link || is_relocate,
424 "Link",
425 "Link the objects or data-blocks rather than appending");
427
428 prop = RNA_def_boolean(
429 ot->srna,
430 "do_reuse_local_id",
431 false,
432 "Re-Use Local Data",
433 "Try to re-use previously matching appended data-blocks instead of appending a new copy");
435 prop = RNA_def_boolean(ot->srna,
436 "clear_asset_data",
437 false,
438 "Clear Asset Data",
439 "Don't add asset meta-data or tags from the original data-block");
441
442 prop = RNA_def_boolean(ot->srna, "autoselect", true, "Select", "Select new objects");
444
445 prop = RNA_def_boolean(ot->srna,
446 "active_collection",
447 !is_relocate,
448 "Active Collection",
449 "Put new objects on the active collection");
451
452 /* NOTE: do not force instancing when relocating, as direct data (the selected ID) status should
453 * not change on that regard, and other dependencies would be indirectly linked and therefore
454 * should not require any enforced instancing when linked. */
455 prop = RNA_def_boolean(
456 ot->srna,
457 "instance_collections",
458 is_link && !is_relocate,
459 "Instance Collections",
460 "Create instances for collections, rather than adding them directly to the scene");
462
463 prop = RNA_def_boolean(
464 ot->srna,
465 "instance_object_data",
466 !is_relocate,
467 "Instance Object Data",
468 "Create instances for object data which are not referenced by any objects");
470}
471
473{
474 ot->name = "Link";
475 ot->idname = "WM_OT_link";
476 ot->description = "Link from a Library .blend file";
477
478 ot->invoke = wm_link_append_invoke;
479 ot->exec = wm_link_append_exec;
480 ot->poll = wm_link_append_poll;
481
482 ot->flag = OPTYPE_UNDO;
483
492
494}
495
497{
498 ot->name = "Append";
499 ot->idname = "WM_OT_append";
500 ot->description = "Append from a Library .blend file";
501
502 ot->invoke = wm_link_append_invoke;
503 ot->exec = wm_link_append_exec;
504 ot->poll = wm_link_append_poll;
505
506 ot->flag = OPTYPE_UNDO;
507
516
518 RNA_def_boolean(ot->srna,
519 "set_fake",
520 false,
521 "Fake User",
522 "Set \"Fake User\" for appended items (except objects and collections)");
524 ot->srna,
525 "use_recursive",
526 true,
527 "Localize All",
528 "Localize all appended data, including those indirectly linked from other libraries");
529}
530
532{
533 Main *bmain = CTX_data_main(C);
534 const char *blendfile_path = BKE_main_blendfile_path(bmain);
535 Scene *scene = CTX_data_scene(C);
536 ViewLayer *view_layer = CTX_data_view_layer(C);
537 BlendfileLinkAppendContext *lapp_context;
538 char filepath[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA],
539 relname[FILE_MAX];
540 char *group, *name;
541
542 RNA_string_get(op->ptr, "filename", relname);
543 RNA_string_get(op->ptr, "directory", root);
544 if (BLI_path_is_rel(root)) {
545 BLI_path_abs(root, blendfile_path);
546 }
547
548 BLI_path_join(filepath, sizeof(filepath), root, relname);
549
550 /* Test if we have a valid data. */
551 const bool is_librarypath_valid = BKE_blendfile_library_path_explode(
552 filepath, libname, &group, &name);
553
554 {
555 if (blendfile_path[0] != '\0') {
556 /* NOTE: Need to also check `filepath`, as typically `libname` is an empty string here
557 * (when trying to append from current file from the file-browser e.g.). */
558 if (BLI_path_cmp(blendfile_path, filepath) == 0 ||
559 BLI_path_cmp(blendfile_path, libname) == 0)
560 {
561 BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", filepath);
562 return OPERATOR_CANCELLED;
563 }
564 }
565 }
566
567 if (!is_librarypath_valid) {
568 BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", filepath);
569 return OPERATOR_CANCELLED;
570 }
571 if (!group || !name) {
572 BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", filepath);
573 return OPERATOR_CANCELLED;
574 }
575
576 int flag = wm_link_append_flag(op);
578
579 const short id_type_code = BKE_idtype_idcode_from_name(group);
580
581 const int tmp_id_session_uid = RNA_int_get(op->ptr, "id_session_uid");
582 const uint id_session_uid = *reinterpret_cast<const uint *>(&tmp_id_session_uid);
583 /* NOTE: Creating a full ID map for a single lookup is not worth it. */
584 ID *linked_id = BKE_libblock_find_session_uid(bmain, id_session_uid);
585
586 {
587 const char *linked_id_name = BKE_id_name(*linked_id);
588
589 if (!linked_id || !ID_IS_LINKED(linked_id)) {
590 BKE_reportf(op->reports, RPT_ERROR, "No valid existing linked ID given to relocate");
591 return OPERATOR_CANCELLED;
592 }
593 if (GS(linked_id->name) != id_type_code) {
595 RPT_ERROR,
596 "Selected ID '%s' is a %s, cannot be used to relocate existing linked ID '%s' "
597 "which is a %s",
598 name,
599 group,
600 linked_id_name,
601 BKE_idtype_idcode_to_name(GS(linked_id->name)));
602 return OPERATOR_CANCELLED;
603 }
604 if (STREQ(linked_id_name, name) && STREQ(linked_id->lib->runtime->filepath_abs, libname)) {
606 RPT_ERROR,
607 "Selected ID '%s' seems to be the same as the relocated ID '%s', use 'Reload' "
608 "operation instead",
609 name,
610 linked_id_name);
611 return OPERATOR_CANCELLED;
612 }
613 }
614
615 /* From here down, no error returns. */
616
617 if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) {
618 BKE_view_layer_base_deselect_all(scene, view_layer);
619 }
620
621 /* Never enforce instantiation of anything when relocating. */
623
624 /* Tag everything, its generally useful to know what is new.
625 *
626 * Take extra care `BKE_main_id_flag_all(bmain, ID_TAG_PRE_EXISTING, false)` is called after! */
628
629 /* We define our working data...
630 * Note that here, each item 'uses' one library, and only one. */
631 LibraryLink_Params lapp_params;
633 &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C));
634
635 lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
638
639 BKE_blendfile_link_append_context_library_add(lapp_context, libname, nullptr);
641 lapp_context, name, id_type_code, linked_id);
643
645
646 BKE_blendfile_id_relocate(*lapp_context, op->reports);
647
649
651
652 /* TODO(sergey): Use proper flag for tagging here. */
653
654 /* TODO(dalai): Temporary solution!
655 * Ideally we only need to tag the new objects themselves, not the scene.
656 * This way we'll avoid flush of collection properties
657 * to all objects and limit update to the particular object only.
658 * But afraid first we need to change collection evaluation in DEG
659 * according to depsgraph manifesto. */
660 if (scene) {
661 DEG_id_tag_update(&scene->id, 0);
662 }
663
664 /* Recreate dependency graph to include new objects. */
666
667 /* TODO: align `G.filepath_last_library` with other directory storage
668 * (like last opened image, etc). */
669 STRNCPY(G.filepath_last_library, root);
670
672
673 return OPERATOR_FINISHED;
674}
675
677{
678 ot->name = "Relocate Linked ID";
679 ot->idname = "WM_OT_id_linked_relocate";
680 ot->description =
681 "Relocate a linked ID, i.e. select another ID to link, and remap its local usages to that "
682 "newly linked data-block). Currently only designed as an internal operator, not directly "
683 "exposed to the user";
684
685 ot->invoke = wm_link_append_invoke;
687 ot->poll = wm_link_append_poll;
688
690
691 PropertyRNA *prop = RNA_def_int(ot->srna,
692 "id_session_uid",
694 0,
695 INT_MAX,
696 "Linked ID Session UID",
697 "Unique runtime identifier for the linked ID to relocate",
698 0,
699 INT_MAX);
701
710
712}
713
715
716/* -------------------------------------------------------------------- */
720
722 Scene *scene,
723 ViewLayer *view_layer,
724 View3D *v3d,
725 const char *filepath,
726 const short id_code,
727 const char *id_name,
728 const int flag)
729{
731 BLI_path_cmp(BKE_main_blendfile_path(bmain), filepath) != 0,
732 "Calling code should ensure it does not attempt to link/append from current blendfile");
733
734 const bool do_pack = (flag & BLO_LIBLINK_PACK) != 0;
735 const bool do_append = (flag & FILE_LINK) == 0;
736 /* Tag everything so we can make local only the new datablock. */
738
739 /* Define working data, with just the one item we want to link. */
740 LibraryLink_Params lapp_params;
741 BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d);
742
746
747 BKE_blendfile_link_append_context_library_add(lapp_context, filepath, nullptr);
749 lapp_context, id_name, id_code, nullptr);
751
753
754 /* Link datablock. */
755 BKE_blendfile_link(lapp_context, nullptr);
756
757 if (do_pack) {
758 BKE_blendfile_link_pack(lapp_context, nullptr);
759 }
760 else if (do_append) {
761 BKE_blendfile_append(lapp_context, nullptr);
762 }
763
764 BKE_blendfile_link_append_instantiate_loose(lapp_context, nullptr);
765
767
768 /* Get linked datablock and free working data. */
770
772
774
775 return id;
776}
777
779 Scene *scene,
780 ViewLayer *view_layer,
781 View3D *v3d,
782 const char *filepath,
783 const short id_code,
784 const char *id_name,
785 int flag)
786{
787 flag |= FILE_LINK;
789 bmain, scene, view_layer, v3d, filepath, id_code, id_name, flag);
790}
791
793 Scene *scene,
794 ViewLayer *view_layer,
795 View3D *v3d,
796 const char *filepath,
797 const short id_code,
798 const char *id_name,
799 int flag)
800{
801 BLI_assert((flag & FILE_LINK) == 0);
803 bmain, scene, view_layer, v3d, filepath, id_code, id_name, flag);
804}
805
807
808/* -------------------------------------------------------------------- */
811
813 wmOperator *op,
814 const wmEvent * /*event*/)
815{
816 Library *lib;
817 char lib_name[MAX_NAME];
818
819 RNA_string_get(op->ptr, "library", lib_name);
821
822 if (lib) {
823 if (lib->runtime->parent) {
826 "Cannot relocate indirectly linked library '%s'",
827 lib->runtime->filepath_abs);
828 return OPERATOR_CANCELLED;
829 }
830 RNA_string_set(op->ptr, "filepath", lib->runtime->filepath_abs);
831
833
835 }
836
837 return OPERATOR_CANCELLED;
838}
839
841{
842 if (!BKE_blendfile_extension_check(lib->runtime->filepath_abs)) {
844 reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->runtime->filepath_abs);
845 return;
846 }
847
848 if (!BLI_exists(lib->runtime->filepath_abs)) {
849 BKE_reportf(reports,
850 RPT_ERROR,
851 "Trying to reload library '%s' from invalid path '%s'",
852 lib->id.name,
853 lib->runtime->filepath_abs);
854 return;
855 }
856
857 Main *bmain = CTX_data_main(C);
858 LibraryLink_Params lapp_params;
860 &lapp_params,
861 bmain,
863 0,
866 nullptr);
867
869
870 BKE_blendfile_link_append_context_library_add(lapp_context, lib->runtime->filepath_abs, nullptr);
871
872 BKE_blendfile_library_relocate(lapp_context, reports, lib, true);
873
875
877
880
881 /* Important we unset, otherwise these object won't link into other scenes from this blend file.
882 */
884
885 /* Recreate dependency graph to include new IDs. */
887
889}
890
892{
893 Main *bmain = CTX_data_main(C);
894 const char *blendfile_path = BKE_main_blendfile_path(bmain);
895 char lib_name[MAX_NAME];
896
897 RNA_string_get(op->ptr, "library", lib_name);
898 Library *lib = (Library *)BKE_libblock_find_name(bmain, ID_LI, lib_name);
899 if (lib == nullptr) {
900 return OPERATOR_CANCELLED;
901 }
902
903 PropertyRNA *prop;
904 BlendfileLinkAppendContext *lapp_context;
905
906 char filepath[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
907
908 if (lib->runtime->parent && !do_reload) {
911 "Cannot relocate indirectly linked library '%s'",
912 lib->runtime->filepath_abs);
913 return OPERATOR_CANCELLED;
914 }
915
916 RNA_string_get(op->ptr, "filename", libname);
917 RNA_string_get(op->ptr, "directory", root);
918 if (BLI_path_is_rel(root)) {
919 BLI_path_abs(root, blendfile_path);
920 }
921
922 if (!BKE_blendfile_extension_check(libname)) {
923 BKE_report(op->reports, RPT_ERROR, "Not a library");
924 return OPERATOR_CANCELLED;
925 }
926
927 BLI_path_join(filepath, sizeof(filepath), root, libname);
928
929 if (!BLI_exists(filepath)) {
932 "Trying to reload or relocate library '%s' to invalid path '%s'",
933 lib->id.name,
934 filepath);
935 return OPERATOR_CANCELLED;
936 }
937
938 {
939 if ((blendfile_path[0] != '\0') && (BLI_path_cmp(blendfile_path, filepath) == 0)) {
942 "Cannot relocate library '%s' to current blend file '%s'",
943 lib->id.name,
944 filepath);
945 return OPERATOR_CANCELLED;
946 }
947 }
948
949 int flag = FILE_LINK;
950 if (RNA_boolean_get(op->ptr, "relative_path")) {
952 }
954 if (do_reload) {
956 }
957
958 LibraryLink_Params lapp_params;
960 &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), nullptr);
961
962 if (BLI_path_cmp(lib->runtime->filepath_abs, filepath) == 0) {
963 CLOG_DEBUG(&LOG, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us);
964
965 do_reload = true;
966
967 lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
968 BKE_blendfile_link_append_context_library_add(lapp_context, filepath, nullptr);
969 }
970 else {
971 int totfiles = 0;
972
974 &LOG, "We are supposed to relocate '%s' lib to new '%s' one", lib->filepath, libname);
975
976 /* Check if something is indicated for relocate. */
977 prop = RNA_struct_find_property(op->ptr, "files");
978 if (prop) {
979 totfiles = RNA_property_collection_length(op->ptr, prop);
980 if (totfiles == 0) {
981 if (!libname[0]) {
982 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
983 return OPERATOR_CANCELLED;
984 }
985 }
986 }
987
988 lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
989
990 if (totfiles) {
991 RNA_BEGIN (op->ptr, itemptr, "files") {
992 RNA_string_get(&itemptr, "name", relname);
993
994 BLI_path_join(filepath, sizeof(filepath), root, relname);
995
996 if (BLI_path_cmp(filepath, lib->runtime->filepath_abs) == 0 ||
998 {
999 continue;
1000 }
1001
1002 CLOG_DEBUG(&LOG, "\tCandidate new lib to reload data-blocks from: %s", filepath);
1003 BKE_blendfile_link_append_context_library_add(lapp_context, filepath, nullptr);
1004 }
1005 RNA_END;
1006 }
1007 else {
1008 CLOG_DEBUG(&LOG, "\tCandidate new lib to reload data-blocks from: %s", filepath);
1009 BKE_blendfile_link_append_context_library_add(lapp_context, filepath, nullptr);
1010 }
1011 }
1012
1013 BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload);
1014
1016
1018
1019 /* TODO: align `G.filepath_last_library` with other directory storage
1020 * (like last opened image, etc). */
1021 STRNCPY(G.filepath_last_library, root);
1022
1025
1026 /* Important we unset, otherwise these object won't link into other scenes from this blend
1027 * file.
1028 */
1030
1031 /* Recreate dependency graph to include new IDs. */
1033
1035
1036 return OPERATOR_FINISHED;
1037}
1038
1040{
1041 return wm_lib_relocate_exec_do(C, op, false);
1042}
1043
1045{
1046 PropertyRNA *prop;
1047
1048 ot->name = "Relocate Library";
1049 ot->idname = "WM_OT_lib_relocate";
1050 ot->description = "Relocate the given library to one or several others";
1051
1052 ot->invoke = wm_lib_relocate_invoke;
1053 ot->exec = wm_lib_relocate_exec;
1054
1055 ot->flag = OPTYPE_UNDO;
1056
1057 prop = RNA_def_string(ot->srna, "library", nullptr, MAX_NAME, "Library", "Library to relocate");
1059
1068}
1069
1071{
1072 return wm_lib_relocate_exec_do(C, op, true);
1073}
1074
1076{
1077 PropertyRNA *prop;
1078
1079 ot->name = "Reload Library";
1080 ot->idname = "WM_OT_lib_reload";
1081 ot->description = "Reload the given library";
1082
1083 ot->exec = wm_lib_reload_exec;
1084
1085 ot->flag = OPTYPE_UNDO;
1086
1087 prop = RNA_def_string(ot->srna, "library", nullptr, MAX_NAME, "Library", "Library to reload");
1089
1098}
1099
bool BKE_blendfile_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition blendfile.cc:92
bool BKE_blendfile_extension_check(const char *str)
Definition blendfile.cc:86
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:164
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:197
short BKE_idtype_idcode_from_name(const char *idtype_name)
Definition idtype.cc:185
bool BKE_idtype_idcode_is_only_appendable(short idcode)
Definition idtype.cc:204
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
ID * BKE_libblock_find_session_uid(Main *bmain, short type, uint32_t session_uid)
Definition lib_id.cc:1728
ID * BKE_libblock_find_name(Main *bmain, short type, const char *name, const std::optional< Library * > lib=std::nullopt) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition lib_id.cc:1710
#define MAIN_ID_SESSION_UID_UNSET
void BKE_main_lib_objects_recalc_all(Main *bmain)
Definition lib_id.cc:1290
const char * BKE_id_name(const ID &id)
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1224
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:892
General operations, lookup, etc. for materials.
General operations, lookup, etc. for blender objects.
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR_INVALID_INPUT
Definition BKE_report.hh:40
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
API for Blender-side Rigid Body stuff.
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:360
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_join(...)
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
#define FILE_MAXDIR
#define BLI_path_cmp
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned int uint
#define STREQ(a, b)
external readfile function prototypes.
@ BLO_LIBLINK_APPEND_RECURSIVE
@ BLO_LIBLINK_USE_PLACEHOLDERS
@ BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR
@ BLO_LIBLINK_OBDATA_INSTANCE
@ BLO_LIBLINK_APPEND_SET_FAKEUSER
@ BLO_LIBLINK_FORCE_INDIRECT
@ BLO_LIBLINK_PACK
@ BLO_LIBLINK_APPEND_LOCAL_ID_REUSE
@ BLO_LIBLINK_COLLECTION_INSTANCE
void BLO_library_link_params_init_with_context(LibraryLink_Params *params, Main *bmain, int flag, int id_tag_extra, Scene *scene, ViewLayer *view_layer, const View3D *v3d)
Definition readfile.cc:5116
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
ID and Library types, which are fundamental for SDNA.
@ ID_TAG_PRE_EXISTING
Definition DNA_ID.h:926
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
@ ID_LI
#define MAX_NAME
Definition DNA_defs.h:50
@ FILE_SORT_DEFAULT
@ FILE_LOADLIB
@ FILE_BLENDER
@ FILE_TYPE_BLENDER
@ FILE_TYPE_FOLDER
@ FILE_TYPE_BLENDERLIB
@ FILE_DEFAULTDISPLAY
@ FILE_ACTIVE_COLLECTION
@ FILE_RELPATH
@ FILE_AUTOSELECT
@ FILE_LINK
#define FILE_MAX_LIBEXTRA
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
int datatoc_startup_blend_size
const char datatoc_startup_blend[]
void IMB_colormanagement_check_file_config(Main *bmain)
#define RNA_BEGIN(sptr, itemptr, propname)
#define RNA_END
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
@ WM_FILESEL_FILES
Definition WM_api.hh:1125
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1122
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1121
@ WM_FILESEL_SHOW_PROPS
Definition WM_api.hh:1127
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ WM_FILESEL_FILENAME
Definition WM_api.hh:1123
@ FILE_OPENFILE
Definition WM_api.hh:1133
#define NC_WINDOW
Definition WM_types.hh:375
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
#define GS(x)
#define LOG(level)
Definition log.h:97
#define G(x, y, z)
const char * name
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_int_get(PointerRNA *ptr, const char *name)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
Definition DNA_ID.h:414
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:579
struct ReportList * reports
struct PointerRNA * ptr
static DynamicLibrary lib
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
bool WM_operator_winactive(bContext *C)
uint8_t flag
Definition wm_window.cc:145