1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2007 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup wm
22 *
23 * Functions for dealing with append/link operators and helpers.
24 */
25
26 #include <ctype.h>
27 #include <errno.h>
28 #include <float.h>
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_ID.h"
36 #include "DNA_key_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_windowmanager_types.h"
40
41 #include "BLI_bitmap.h"
42 #include "BLI_blenlib.h"
43 #include "BLI_ghash.h"
44 #include "BLI_linklist.h"
45 #include "BLI_math.h"
46 #include "BLI_memarena.h"
47 #include "BLI_utildefines.h"
48
49 #include "BLO_readfile.h"
50
51 #include "BKE_context.h"
52 #include "BKE_global.h"
53 #include "BKE_key.h"
54 #include "BKE_layer.h"
55 #include "BKE_lib_id.h"
56 #include "BKE_lib_override.h"
57 #include "BKE_lib_remap.h"
58 #include "BKE_main.h"
59 #include "BKE_report.h"
60
61 #include "BKE_idtype.h"
62
63 #include "DEG_depsgraph.h"
64 #include "DEG_depsgraph_build.h"
65
66 #include "IMB_colormanagement.h"
67
68 #include "ED_datafiles.h"
69 #include "ED_screen.h"
70
71 #include "RNA_access.h"
72 #include "RNA_define.h"
73
74 #include "WM_api.h"
75 #include "WM_types.h"
76
77 #include "wm_files.h"
78
79 /* -------------------------------------------------------------------- */
80 /** \name Link/Append Operator
81 * \{ */
82
wm_link_append_poll(bContext * C)83 static bool wm_link_append_poll(bContext *C)
84 {
85 if (WM_operator_winactive(C)) {
86 /* linking changes active object which is pretty useful in general,
87 * but which totally confuses edit mode (i.e. it becoming not so obvious
88 * to leave from edit mode and invalid tools in toolbar might be displayed)
89 * so disable link/append when in edit mode (sergey) */
90 if (CTX_data_edit_object(C)) {
91 return 0;
92 }
93
94 return 1;
95 }
96
97 return 0;
98 }
99
wm_link_append_invoke(bContext * C,wmOperator * op,const wmEvent * UNUSED (event))100 static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
101 {
102 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
103 if (G.lib[0] != '\0') {
104 RNA_string_set(op->ptr, "filepath", G.lib);
105 }
106 else if (G.relbase_valid) {
107 char path[FILE_MAX];
108 BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
109 BLI_path_parent_dir(path);
110 RNA_string_set(op->ptr, "filepath", path);
111 }
112 }
113
114 WM_event_add_fileselect(C, op);
115 return OPERATOR_RUNNING_MODAL;
116 }
117
wm_link_append_flag(wmOperator * op)118 static short wm_link_append_flag(wmOperator *op)
119 {
120 PropertyRNA *prop;
121 short flag = 0;
122
123 if (RNA_boolean_get(op->ptr, "autoselect")) {
124 flag |= FILE_AUTOSELECT;
125 }
126 if (RNA_boolean_get(op->ptr, "active_collection")) {
127 flag |= FILE_ACTIVE_COLLECTION;
128 }
129 if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) &&
130 RNA_property_boolean_get(op->ptr, prop)) {
131 flag |= FILE_RELPATH;
132 }
133 if (RNA_boolean_get(op->ptr, "link")) {
134 flag |= FILE_LINK;
135 }
136 if (RNA_boolean_get(op->ptr, "instance_collections")) {
137 flag |= FILE_COLLECTION_INSTANCE;
138 }
139 if (RNA_boolean_get(op->ptr, "instance_object_data")) {
140 flag |= FILE_OBDATA_INSTANCE;
141 }
142
143 return flag;
144 }
145
146 typedef struct WMLinkAppendDataItem {
147 char *name;
148 BLI_bitmap
149 *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
150 short idcode;
151
152 ID *new_id;
153 void *customdata;
154 } WMLinkAppendDataItem;
155
156 typedef struct WMLinkAppendData {
157 LinkNodePair libraries;
158 LinkNodePair items;
159 int num_libraries;
160 int num_items;
161 /**
162 * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h
163 */
164 int flag;
165
166 /* Internal 'private' data */
167 MemArena *memarena;
168 } WMLinkAppendData;
169
wm_link_append_data_new(const int flag)170 static WMLinkAppendData *wm_link_append_data_new(const int flag)
171 {
172 MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
173 WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
174
175 lapp_data->flag = flag;
176 lapp_data->memarena = ma;
177
178 return lapp_data;
179 }
180
wm_link_append_data_free(WMLinkAppendData * lapp_data)181 static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
182 {
183 BLI_memarena_free(lapp_data->memarena);
184 }
185
186 /* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
187
wm_link_append_data_library_add(WMLinkAppendData * lapp_data,const char * libname)188 static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
189 {
190 size_t len = strlen(libname) + 1;
191 char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
192
193 BLI_strncpy(libpath, libname, len);
194 BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
195 lapp_data->num_libraries++;
196 }
197
wm_link_append_data_item_add(WMLinkAppendData * lapp_data,const char * idname,const short idcode,void * customdata)198 static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data,
199 const char *idname,
200 const short idcode,
201 void *customdata)
202 {
203 WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
204 size_t len = strlen(idname) + 1;
205
206 item->name = BLI_memarena_alloc(lapp_data->memarena, len);
207 BLI_strncpy(item->name, idname, len);
208 item->idcode = idcode;
209 item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
210
211 item->new_id = NULL;
212 item->customdata = customdata;
213
214 BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
215 lapp_data->num_items++;
216
217 return item;
218 }
219
wm_link_do(WMLinkAppendData * lapp_data,ReportList * reports,Main * bmain,Scene * scene,ViewLayer * view_layer,const View3D * v3d)220 static void wm_link_do(WMLinkAppendData *lapp_data,
221 ReportList *reports,
222 Main *bmain,
223 Scene *scene,
224 ViewLayer *view_layer,
225 const View3D *v3d)
226 {
227 Main *mainl;
228 BlendHandle *bh;
229 Library *lib;
230
231 const int flag = lapp_data->flag;
232
233 LinkNode *liblink, *itemlink;
234 int lib_idx, item_idx;
235
236 BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
237
238 for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink;
239 lib_idx++, liblink = liblink->next) {
240 char *libname = liblink->link;
241
242 if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
243 bh = BLO_blendhandle_from_memory(datatoc_startup_blend, datatoc_startup_blend_size);
244 }
245 else {
246 bh = BLO_blendhandle_from_file(libname, reports);
247 }
248
249 if (bh == NULL) {
250 /* Unlikely since we just browsed it, but possible
251 * Error reports will have been made by BLO_blendhandle_from_file() */
252 continue;
253 }
254
255 /* here appending/linking starts */
256 struct LibraryLink_Params liblink_params;
257 BLO_library_link_params_init_with_context(
258 &liblink_params, bmain, flag, scene, view_layer, v3d);
259
260 mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
261 lib = mainl->curlib;
262 BLI_assert(lib);
263 UNUSED_VARS_NDEBUG(lib);
264
265 if (mainl->versionfile < 250) {
266 BKE_reportf(reports,
267 RPT_WARNING,
268 "Linking or appending from a very old .blend file format (%d.%d), no animation "
269 "conversion will "
270 "be done! You may want to re-save your lib file with current Blender",
271 mainl->versionfile,
272 mainl->subversionfile);
273 }
274
275 /* For each lib file, we try to link all items belonging to that lib,
276 * and tag those successful to not try to load them again with the other libs. */
277 for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
278 item_idx++, itemlink = itemlink->next) {
279 WMLinkAppendDataItem *item = itemlink->link;
280 ID *new_id;
281
282 if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
283 continue;
284 }
285
286 new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params);
287
288 if (new_id) {
289 /* If the link is successful, clear item's libs 'todo' flags.
290 * This avoids trying to link same item with other libraries to come. */
291 BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries);
292 item->new_id = new_id;
293 }
294 }
295
296 BLO_library_link_end(mainl, &bh, &liblink_params);
297 BLO_blendhandle_close(bh);
298 }
299 }
300
301 /**
302 * Check if an item defined by \a name and \a group can be appended/linked.
303 *
304 * \param reports: Optionally report an error when an item can't be appended/linked.
305 */
wm_link_append_item_poll(ReportList * reports,const char * path,const char * group,const char * name,const bool do_append)306 static bool wm_link_append_item_poll(ReportList *reports,
307 const char *path,
308 const char *group,
309 const char *name,
310 const bool do_append)
311 {
312 short idcode;
313
314 if (!group || !name) {
315 printf("skipping %s\n", path);
316 return false;
317 }
318
319 idcode = BKE_idtype_idcode_from_name(group);
320
321 /* XXX For now, we do a nasty exception for workspace, forbid linking them.
322 * Not nice, ultimately should be solved! */
323 if (!BKE_idtype_idcode_is_linkable(idcode) && (do_append || idcode != ID_WS)) {
324 if (reports) {
325 if (do_append) {
326 BKE_reportf(reports,
327 RPT_ERROR_INVALID_INPUT,
328 "Can't append data-block '%s' of type '%s'",
329 name,
330 group);
331 }
332 else {
333 BKE_reportf(reports,
334 RPT_ERROR_INVALID_INPUT,
335 "Can't link data-block '%s' of type '%s'",
336 name,
337 group);
338 }
339 }
340 return false;
341 }
342
343 return true;
344 }
345
wm_link_append_exec(bContext * C,wmOperator * op)346 static int wm_link_append_exec(bContext *C, wmOperator *op)
347 {
348 Main *bmain = CTX_data_main(C);
349 Scene *scene = CTX_data_scene(C);
350 ViewLayer *view_layer = CTX_data_view_layer(C);
351 PropertyRNA *prop;
352 WMLinkAppendData *lapp_data;
353 char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
354 char *group, *name;
355 int totfiles = 0;
356
357 RNA_string_get(op->ptr, "filename", relname);
358 RNA_string_get(op->ptr, "directory", root);
359
360 BLI_join_dirfile(path, sizeof(path), root, relname);
361
362 /* test if we have a valid data */
363 if (!BLO_library_path_explode(path, libname, &group, &name)) {
364 BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path);
365 return OPERATOR_CANCELLED;
366 }
367 if (!group) {
368 BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
369 return OPERATOR_CANCELLED;
370 }
371 if (BLI_path_cmp(BKE_main_blendfile_path(bmain), libname) == 0) {
372 BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
373 return OPERATOR_CANCELLED;
374 }
375
376 /* check if something is indicated for append/link */
377 prop = RNA_struct_find_property(op->ptr, "files");
378 if (prop) {
379 totfiles = RNA_property_collection_length(op->ptr, prop);
380 if (totfiles == 0) {
381 if (!name) {
382 BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
383 return OPERATOR_CANCELLED;
384 }
385 }
386 }
387 else if (!name) {
388 BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
389 return OPERATOR_CANCELLED;
390 }
391
392 short flag = wm_link_append_flag(op);
393 const bool do_append = (flag & FILE_LINK) == 0;
394
395 /* sanity checks for flag */
396 if (scene && scene->id.lib) {
397 BKE_reportf(op->reports,
398 RPT_WARNING,
399 "Scene '%s' is linked, instantiation of objects is disabled",
400 scene->id.name + 2);
401 flag &= ~(FILE_COLLECTION_INSTANCE | FILE_OBDATA_INSTANCE);
402 scene = NULL;
403 }
404
405 /* We need to add nothing from #eBLOLibLinkFlags to flag here. */
406
407 /* from here down, no error returns */
408
409 if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) {
410 BKE_view_layer_base_deselect_all(view_layer);
411 }
412
413 /* tag everything, all untagged data can be made local
414 * its also generally useful to know what is new
415 *
416 * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
417 BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
418
419 /* We define our working data...
420 * Note that here, each item 'uses' one library, and only one. */
421 lapp_data = wm_link_append_data_new(flag);
422 if (totfiles != 0) {
423 GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
424 int lib_idx = 0;
425
426 RNA_BEGIN (op->ptr, itemptr, "files") {
427 RNA_string_get(&itemptr, "name", relname);
428
429 BLI_join_dirfile(path, sizeof(path), root, relname);
430
431 if (BLO_library_path_explode(path, libname, &group, &name)) {
432 if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) {
433 continue;
434 }
435
436 if (!BLI_ghash_haskey(libraries, libname)) {
437 BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx));
438 lib_idx++;
439 wm_link_append_data_library_add(lapp_data, libname);
440 }
441 }
442 }
443 RNA_END;
444
445 RNA_BEGIN (op->ptr, itemptr, "files") {
446 RNA_string_get(&itemptr, "name", relname);
447
448 BLI_join_dirfile(path, sizeof(path), root, relname);
449
450 if (BLO_library_path_explode(path, libname, &group, &name)) {
451 WMLinkAppendDataItem *item;
452
453 if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) {
454 continue;
455 }
456
457 lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname));
458
459 item = wm_link_append_data_item_add(
460 lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
461 BLI_BITMAP_ENABLE(item->libraries, lib_idx);
462 }
463 }
464 RNA_END;
465
466 BLI_ghash_free(libraries, MEM_freeN, NULL);
467 }
468 else {
469 WMLinkAppendDataItem *item;
470
471 wm_link_append_data_library_add(lapp_data, libname);
472 item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
473 BLI_BITMAP_ENABLE(item->libraries, 0);
474 }
475
476 if (lapp_data->num_items == 0) {
477 /* Early out in case there is nothing to link. */
478 wm_link_append_data_free(lapp_data);
479 /* Clear pre existing tag. */
480 BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
481 return OPERATOR_CANCELLED;
482 }
483
484 /* XXX We'd need re-entrant locking on Main for this to work... */
485 /* BKE_main_lock(bmain); */
486
487 wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C));
488
489 /* BKE_main_unlock(bmain); */
490
491 /* mark all library linked objects to be updated */
492 BKE_main_lib_objects_recalc_all(bmain);
493 IMB_colormanagement_check_file_config(bmain);
494
495 /* append, rather than linking */
496 if (do_append) {
497 const bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
498 const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive");
499
500 if (use_recursive) {
501 BKE_library_make_local(bmain, NULL, NULL, true, set_fake);
502 }
503 else {
504 LinkNode *itemlink;
505 GSet *done_libraries = BLI_gset_new_ex(
506 BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__, lapp_data->num_libraries);
507
508 for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
509 ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id;
510
511 if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) {
512 BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake);
513 BLI_gset_insert(done_libraries, new_id->lib);
514 }
515 }
516
517 BLI_gset_free(done_libraries, NULL);
518 }
519 }
520
521 wm_link_append_data_free(lapp_data);
522
523 /* important we unset, otherwise these object wont
524 * link into other scenes from this blend file */
525 BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
526
527 /* TODO(sergey): Use proper flag for tagging here. */
528
529 /* TODO(dalai): Temporary solution!
530 * Ideally we only need to tag the new objects themselves, not the scene.
531 * This way we'll avoid flush of collection properties
532 * to all objects and limit update to the particular object only.
533 * But afraid first we need to change collection evaluation in DEG
534 * according to depsgraph manifesto. */
535 DEG_id_tag_update(&scene->id, 0);
536
537 /* recreate dependency graph to include new objects */
538 DEG_relations_tag_update(bmain);
539
540 /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
541 BLI_strncpy(G.lib, root, FILE_MAX);
542
543 WM_event_add_notifier(C, NC_WINDOW, NULL);
544
545 return OPERATOR_FINISHED;
546 }
547
wm_link_append_properties_common(wmOperatorType * ot,bool is_link)548 static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
549 {
550 PropertyRNA *prop;
551
552 /* better not save _any_ settings for this operator */
553 /* properties */
554 prop = RNA_def_boolean(
555 ot->srna, "link", is_link, "Link", "Link the objects or data-blocks rather than appending");
556 RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
557 prop = RNA_def_boolean(ot->srna, "autoselect", true, "Select", "Select new objects");
558 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
559 prop = RNA_def_boolean(ot->srna,
560 "active_collection",
561 true,
562 "Active Collection",
563 "Put new objects on the active collection");
564 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
565 prop = RNA_def_boolean(
566 ot->srna,
567 "instance_collections",
568 is_link,
569 "Instance Collections",
570 "Create instances for collections, rather than adding them directly to the scene");
571 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
572
573 prop = RNA_def_boolean(
574 ot->srna,
575 "instance_object_data",
576 true,
577 "Instance Object Data",
578 "Create instances for object data which are not referenced by any objects");
579 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
580 }
581
WM_OT_link(wmOperatorType * ot)582 void WM_OT_link(wmOperatorType *ot)
583 {
584 ot->name = "Link";
585 ot->idname = "WM_OT_link";
586 ot->description = "Link from a Library .blend file";
587
588 ot->invoke = wm_link_append_invoke;
589 ot->exec = wm_link_append_exec;
590 ot->poll = wm_link_append_poll;
591
592 ot->flag |= OPTYPE_UNDO;
593
594 WM_operator_properties_filesel(ot,
595 FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
596 FILE_LOADLIB,
597 FILE_OPENFILE,
598 WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
599 WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
600 FILE_DEFAULTDISPLAY,
601 FILE_SORT_ALPHA);
602
603 wm_link_append_properties_common(ot, true);
604 }
605
WM_OT_append(wmOperatorType * ot)606 void WM_OT_append(wmOperatorType *ot)
607 {
608 ot->name = "Append";
609 ot->idname = "WM_OT_append";
610 ot->description = "Append from a Library .blend file";
611
612 ot->invoke = wm_link_append_invoke;
613 ot->exec = wm_link_append_exec;
614 ot->poll = wm_link_append_poll;
615
616 ot->flag |= OPTYPE_UNDO;
617
618 WM_operator_properties_filesel(ot,
619 FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
620 FILE_LOADLIB,
621 FILE_OPENFILE,
622 WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
623 WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
624 FILE_DEFAULTDISPLAY,
625 FILE_SORT_ALPHA);
626
627 wm_link_append_properties_common(ot, false);
628 RNA_def_boolean(ot->srna,
629 "set_fake",
630 false,
631 "Fake User",
632 "Set Fake User for appended items (except Objects and Groups)");
633 RNA_def_boolean(
634 ot->srna,
635 "use_recursive",
636 true,
637 "Localize All",
638 "Localize all appended data, including those indirectly linked from other libraries");
639 }
640
641 /** \} */
642
643 /* -------------------------------------------------------------------- */
644 /** \name Append Single Data-Block & Return it
645 *
646 * Used for appending workspace from startup files.
647 * \{ */
648
WM_file_append_datablock(Main * bmain,Scene * scene,ViewLayer * view_layer,View3D * v3d,const char * filepath,const short id_code,const char * id_name)649 ID *WM_file_append_datablock(Main *bmain,
650 Scene *scene,
651 ViewLayer *view_layer,
652 View3D *v3d,
653 const char *filepath,
654 const short id_code,
655 const char *id_name)
656 {
657 /* Tag everything so we can make local only the new datablock. */
658 BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
659
660 /* Define working data, with just the one item we want to append. */
661 WMLinkAppendData *lapp_data = wm_link_append_data_new(0);
662
663 wm_link_append_data_library_add(lapp_data, filepath);
664 WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL);
665 BLI_BITMAP_ENABLE(item->libraries, 0);
666
667 /* Link datablock. */
668 wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
669
670 /* Get linked datablock and free working data. */
671 ID *id = item->new_id;
672 wm_link_append_data_free(lapp_data);
673
674 /* Make datablock local. */
675 BKE_library_make_local(bmain, NULL, NULL, true, false);
676
677 /* Clear pre existing tag. */
678 BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
679
680 return id;
681 }
682
683 /** \} */
684
685 /* -------------------------------------------------------------------- */
686 /** \name Library Relocate Operator & Library Reload API
687 * \{ */
688
wm_lib_relocate_invoke(bContext * C,wmOperator * op,const wmEvent * UNUSED (event))689 static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
690 {
691 Library *lib;
692 char lib_name[MAX_NAME];
693
694 RNA_string_get(op->ptr, "library", lib_name);
695 lib = (Library *)BKE_libblock_find_name(CTX_data_main(C), ID_LI, lib_name);
696
697 if (lib) {
698 if (lib->parent) {
699 BKE_reportf(op->reports,
700 RPT_ERROR_INVALID_INPUT,
701 "Cannot relocate indirectly linked library '%s'",
702 lib->filepath_abs);
703 return OPERATOR_CANCELLED;
704 }
705 RNA_string_set(op->ptr, "filepath", lib->filepath_abs);
706
707 WM_event_add_fileselect(C, op);
708
709 return OPERATOR_RUNNING_MODAL;
710 }
711
712 return OPERATOR_CANCELLED;
713 }
714
lib_relocate_do_remap(Main * bmain,ID * old_id,ID * new_id,ReportList * reports,const bool do_reload,const short remap_flags)715 static void lib_relocate_do_remap(Main *bmain,
716 ID *old_id,
717 ID *new_id,
718 ReportList *reports,
719 const bool do_reload,
720 const short remap_flags)
721 {
722 BLI_assert(old_id);
723 if (do_reload) {
724 /* Since we asked for placeholders in case of missing IDs,
725 * we expect to always get a valid one. */
726 BLI_assert(new_id);
727 }
728 if (new_id) {
729 #ifdef PRINT_DEBUG
730 printf("before remap of %s, old_id users: %d, new_id users: %d\n",
731 old_id->name,
732 old_id->us,
733 new_id->us);
734 #endif
735 BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
736
737 if (old_id->flag & LIB_FAKEUSER) {
738 id_fake_user_clear(old_id);
739 id_fake_user_set(new_id);
740 }
741
742 #ifdef PRINT_DEBUG
743 printf("after remap of %s, old_id users: %d, new_id users: %d\n",
744 old_id->name,
745 old_id->us,
746 new_id->us);
747 #endif
748
749 /* In some cases, new_id might become direct link, remove parent of library in this case. */
750 if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
751 if (do_reload) {
752 BLI_assert(0); /* Should not happen in 'pure' reload case... */
753 }
754 new_id->lib->parent = NULL;
755 }
756 }
757
758 if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
759 /* Note that this *should* not happen - but better be safe than sorry in this area,
760 * at least until we are 100% sure this cannot ever happen.
761 * Also, we can safely assume names were unique so far,
762 * so just replacing '.' by '~' should work,
763 * but this does not totally rules out the possibility of name collision. */
764 size_t len = strlen(old_id->name);
765 size_t dot_pos;
766 bool has_num = false;
767
768 for (dot_pos = len; dot_pos--;) {
769 char c = old_id->name[dot_pos];
770 if (c == '.') {
771 break;
772 }
773 if (c < '0' || c > '9') {
774 has_num = false;
775 break;
776 }
777 has_num = true;
778 }
779
780 if (has_num) {
781 old_id->name[dot_pos] = '~';
782 }
783 else {
784 len = MIN2(len, MAX_ID_NAME - 7);
785 BLI_strncpy(&old_id->name[len], "~000", 7);
786 }
787
788 id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
789
790 BKE_reportf(
791 reports,
792 RPT_WARNING,
793 "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
794 "old one (%d remaining users) had to be kept and was renamed to '%s'",
795 new_id->name,
796 old_id->us,
797 old_id->name);
798 }
799 }
800
lib_relocate_do(Main * bmain,Library * library,WMLinkAppendData * lapp_data,ReportList * reports,const bool do_reload)801 static void lib_relocate_do(Main *bmain,
802 Library *library,
803 WMLinkAppendData *lapp_data,
804 ReportList *reports,
805 const bool do_reload)
806 {
807 ListBase *lbarray[MAX_LIBARRAY];
808 int lba_idx;
809
810 LinkNode *itemlink;
811 int item_idx;
812
813 /* Remove all IDs to be reloaded from Main. */
814 lba_idx = set_listbasepointers(bmain, lbarray);
815 while (lba_idx--) {
816 ID *id = lbarray[lba_idx]->first;
817 const short idcode = id ? GS(id->name) : 0;
818
819 if (!id || !BKE_idtype_idcode_is_linkable(idcode)) {
820 /* No need to reload non-linkable datatypes,
821 * those will get relinked with their 'users ID'. */
822 continue;
823 }
824
825 for (; id; id = id->next) {
826 if (id->lib == library) {
827 WMLinkAppendDataItem *item;
828
829 /* We remove it from current Main, and add it to items to link... */
830 /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
831 BLI_remlink(lbarray[lba_idx], id);
832 /* Usual special code for ShapeKeys snowflakes... */
833 Key *old_key = BKE_key_from_id(id);
834 if (old_key != NULL) {
835 BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
836 }
837
838 item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
839 BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries);
840
841 #ifdef PRINT_DEBUG
842 printf("\tdatablock to seek for: %s\n", id->name);
843 #endif
844 }
845 }
846 }
847
848 if (lapp_data->num_items == 0) {
849 /* Early out in case there is nothing to do. */
850 return;
851 }
852
853 BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
854
855 /* We do not want any instantiation here! */
856 wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL);
857
858 BKE_main_lock(bmain);
859
860 /* We add back old id to bmain.
861 * We need to do this in a first, separated loop, otherwise some of those may not be handled by
862 * ID remapping, which means they would still reference old data to be deleted... */
863 for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
864 item_idx++, itemlink = itemlink->next) {
865 WMLinkAppendDataItem *item = itemlink->link;
866 ID *old_id = item->customdata;
867
868 BLI_assert(old_id);
869 BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
870
871 /* Usual special code for ShapeKeys snowflakes... */
872 Key *old_key = BKE_key_from_id(old_id);
873 if (old_key != NULL) {
874 BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
875 }
876 }
877
878 /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking
879 * code is wrong, we need to redo it here after adding them back to main. */
880 BKE_main_id_refcount_recompute(bmain, false);
881
882 /* Note that in reload case, we also want to replace indirect usages. */
883 const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
884 ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
885 (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
886 for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
887 item_idx++, itemlink = itemlink->next) {
888 WMLinkAppendDataItem *item = itemlink->link;
889 ID *old_id = item->customdata;
890 ID *new_id = item->new_id;
891
892 lib_relocate_do_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
893 if (new_id == NULL) {
894 continue;
895 }
896 /* Usual special code for ShapeKeys snowflakes... */
897 Key **old_key_p = BKE_key_from_id_p(old_id);
898 if (old_key_p == NULL) {
899 continue;
900 }
901 Key *old_key = *old_key_p;
902 Key *new_key = BKE_key_from_id(new_id);
903 if (old_key != NULL) {
904 *old_key_p = NULL;
905 id_us_min(&old_key->id);
906 lib_relocate_do_remap(bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
907 *old_key_p = old_key;
908 id_us_plus_no_lib(&old_key->id);
909 }
910 }
911
912 BKE_main_unlock(bmain);
913
914 for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
915 item_idx++, itemlink = itemlink->next) {
916 WMLinkAppendDataItem *item = itemlink->link;
917 ID *old_id = item->customdata;
918
919 if (old_id->us == 0) {
920 BKE_id_free(bmain, old_id);
921 }
922 }
923
924 /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable
925 * (shape keys e.g.), so we need another loop here to clear old ones if possible. */
926 lba_idx = set_listbasepointers(bmain, lbarray);
927 while (lba_idx--) {
928 ID *id, *id_next;
929 for (id = lbarray[lba_idx]->first; id; id = id_next) {
930 id_next = id->next;
931 /* XXX That check may be a bit to generic/permissive? */
932 if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
933 BKE_id_free(bmain, id);
934 }
935 }
936 }
937
938 /* Get rid of no more used libraries... */
939 BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
940 lba_idx = set_listbasepointers(bmain, lbarray);
941 while (lba_idx--) {
942 ID *id;
943 for (id = lbarray[lba_idx]->first; id; id = id->next) {
944 if (id->lib) {
945 id->lib->id.tag &= ~LIB_TAG_DOIT;
946 }
947 }
948 }
949 Library *lib, *lib_next;
950 for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
951 lib_next = lib->id.next;
952 if (lib->id.tag & LIB_TAG_DOIT) {
953 id_us_clear_real(&lib->id);
954 if (lib->id.us == 0) {
955 BKE_id_free(bmain, (ID *)lib);
956 }
957 }
958 }
959
960 /* Update overrides of reloaded linked data-blocks.
961 * Note that this will not necessarily fully update the override, it might need to be manually
962 * 're-generated' depending on changes in linked data. */
963 ID *id;
964 FOREACH_MAIN_ID_BEGIN (bmain, id) {
965 if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
966 (id->tag & LIB_TAG_PRE_EXISTING) == 0) {
967 continue;
968 }
969 if (id->override_library->reference->lib == library) {
970 BKE_lib_override_library_update(bmain, id);
971 }
972 }
973 FOREACH_MAIN_ID_END;
974
975 BKE_main_collection_sync(bmain);
976
977 BKE_main_lib_objects_recalc_all(bmain);
978 IMB_colormanagement_check_file_config(bmain);
979
980 /* important we unset, otherwise these object wont
981 * link into other scenes from this blend file */
982 BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
983
984 /* recreate dependency graph to include new objects */
985 DEG_relations_tag_update(bmain);
986 }
987
WM_lib_reload(Library * lib,bContext * C,ReportList * reports)988 void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
989 {
990 if (!BLO_has_bfile_extension(lib->filepath_abs)) {
991 BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath_abs);
992 return;
993 }
994
995 if (!BLI_exists(lib->filepath_abs)) {
996 BKE_reportf(reports,
997 RPT_ERROR,
998 "Trying to reload library '%s' from invalid path '%s'",
999 lib->id.name,
1000 lib->filepath_abs);
1001 return;
1002 }
1003
1004 WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS |
1005 BLO_LIBLINK_FORCE_INDIRECT);
1006
1007 wm_link_append_data_library_add(lapp_data, lib->filepath_abs);
1008
1009 lib_relocate_do(CTX_data_main(C), lib, lapp_data, reports, true);
1010
1011 wm_link_append_data_free(lapp_data);
1012
1013 WM_event_add_notifier(C, NC_WINDOW, NULL);
1014 }
1015
wm_lib_relocate_exec_do(bContext * C,wmOperator * op,bool do_reload)1016 static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
1017 {
1018 Library *lib;
1019 char lib_name[MAX_NAME];
1020
1021 RNA_string_get(op->ptr, "library", lib_name);
1022 lib = (Library *)BKE_libblock_find_name(CTX_data_main(C), ID_LI, lib_name);
1023
1024 if (lib) {
1025 Main *bmain = CTX_data_main(C);
1026 PropertyRNA *prop;
1027 WMLinkAppendData *lapp_data;
1028
1029 char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
1030 short flag = 0;
1031
1032 if (RNA_boolean_get(op->ptr, "relative_path")) {
1033 flag |= FILE_RELPATH;
1034 }
1035
1036 if (lib->parent && !do_reload) {
1037 BKE_reportf(op->reports,
1038 RPT_ERROR_INVALID_INPUT,
1039 "Cannot relocate indirectly linked library '%s'",
1040 lib->filepath_abs);
1041 return OPERATOR_CANCELLED;
1042 }
1043
1044 RNA_string_get(op->ptr, "directory", root);
1045 RNA_string_get(op->ptr, "filename", libname);
1046
1047 if (!BLO_has_bfile_extension(libname)) {
1048 BKE_report(op->reports, RPT_ERROR, "Not a library");
1049 return OPERATOR_CANCELLED;
1050 }
1051
1052 BLI_join_dirfile(path, sizeof(path), root, libname);
1053
1054 if (!BLI_exists(path)) {
1055 BKE_reportf(op->reports,
1056 RPT_ERROR_INVALID_INPUT,
1057 "Trying to reload or relocate library '%s' to invalid path '%s'",
1058 lib->id.name,
1059 path);
1060 return OPERATOR_CANCELLED;
1061 }
1062
1063 if (BLI_path_cmp(BKE_main_blendfile_path(bmain), path) == 0) {
1064 BKE_reportf(op->reports,
1065 RPT_ERROR_INVALID_INPUT,
1066 "Cannot relocate library '%s' to current blend file '%s'",
1067 lib->id.name,
1068 path);
1069 return OPERATOR_CANCELLED;
1070 }
1071
1072 if (BLI_path_cmp(lib->filepath_abs, path) == 0) {
1073 #ifdef PRINT_DEBUG
1074 printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us);
1075 #endif
1076
1077 do_reload = true;
1078
1079 lapp_data = wm_link_append_data_new(flag);
1080 wm_link_append_data_library_add(lapp_data, path);
1081 }
1082 else {
1083 int totfiles = 0;
1084
1085 #ifdef PRINT_DEBUG
1086 printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname);
1087 #endif
1088
1089 /* Check if something is indicated for relocate. */
1090 prop = RNA_struct_find_property(op->ptr, "files");
1091 if (prop) {
1092 totfiles = RNA_property_collection_length(op->ptr, prop);
1093 if (totfiles == 0) {
1094 if (!libname[0]) {
1095 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
1096 return OPERATOR_CANCELLED;
1097 }
1098 }
1099 }
1100
1101 lapp_data = wm_link_append_data_new(flag);
1102
1103 if (totfiles) {
1104 RNA_BEGIN (op->ptr, itemptr, "files") {
1105 RNA_string_get(&itemptr, "name", relname);
1106
1107 BLI_join_dirfile(path, sizeof(path), root, relname);
1108
1109 if (BLI_path_cmp(path, lib->filepath_abs) == 0 || !BLO_has_bfile_extension(relname)) {
1110 continue;
1111 }
1112
1113 #ifdef PRINT_DEBUG
1114 printf("\t candidate new lib to reload datablocks from: %s\n", path);
1115 #endif
1116 wm_link_append_data_library_add(lapp_data, path);
1117 }
1118 RNA_END;
1119 }
1120 else {
1121 #ifdef PRINT_DEBUG
1122 printf("\t candidate new lib to reload datablocks from: %s\n", path);
1123 #endif
1124 wm_link_append_data_library_add(lapp_data, path);
1125 }
1126 }
1127
1128 if (do_reload) {
1129 lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT;
1130 }
1131
1132 lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload);
1133
1134 wm_link_append_data_free(lapp_data);
1135
1136 /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
1137 BLI_strncpy(G.lib, root, FILE_MAX);
1138
1139 WM_event_add_notifier(C, NC_WINDOW, NULL);
1140
1141 return OPERATOR_FINISHED;
1142 }
1143
1144 return OPERATOR_CANCELLED;
1145 }
1146
wm_lib_relocate_exec(bContext * C,wmOperator * op)1147 static int wm_lib_relocate_exec(bContext *C, wmOperator *op)
1148 {
1149 return wm_lib_relocate_exec_do(C, op, false);
1150 }
1151
WM_OT_lib_relocate(wmOperatorType * ot)1152 void WM_OT_lib_relocate(wmOperatorType *ot)
1153 {
1154 PropertyRNA *prop;
1155
1156 ot->name = "Relocate Library";
1157 ot->idname = "WM_OT_lib_relocate";
1158 ot->description = "Relocate the given library to one or several others";
1159
1160 ot->invoke = wm_lib_relocate_invoke;
1161 ot->exec = wm_lib_relocate_exec;
1162
1163 ot->flag |= OPTYPE_UNDO;
1164
1165 prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate");
1166 RNA_def_property_flag(prop, PROP_HIDDEN);
1167
1168 WM_operator_properties_filesel(ot,
1169 FILE_TYPE_FOLDER | FILE_TYPE_BLENDER,
1170 FILE_BLENDER,
1171 FILE_OPENFILE,
1172 WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
1173 WM_FILESEL_FILES | WM_FILESEL_RELPATH,
1174 FILE_DEFAULTDISPLAY,
1175 FILE_SORT_ALPHA);
1176 }
1177
wm_lib_reload_exec(bContext * C,wmOperator * op)1178 static int wm_lib_reload_exec(bContext *C, wmOperator *op)
1179 {
1180 return wm_lib_relocate_exec_do(C, op, true);
1181 }
1182
WM_OT_lib_reload(wmOperatorType * ot)1183 void WM_OT_lib_reload(wmOperatorType *ot)
1184 {
1185 PropertyRNA *prop;
1186
1187 ot->name = "Reload Library";
1188 ot->idname = "WM_OT_lib_reload";
1189 ot->description = "Reload the given library";
1190
1191 ot->exec = wm_lib_reload_exec;
1192
1193 ot->flag |= OPTYPE_UNDO;
1194
1195 prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload");
1196 RNA_def_property_flag(prop, PROP_HIDDEN);
1197
1198 WM_operator_properties_filesel(ot,
1199 FILE_TYPE_FOLDER | FILE_TYPE_BLENDER,
1200 FILE_BLENDER,
1201 FILE_OPENFILE,
1202 WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
1203 WM_FILESEL_RELPATH,
1204 FILE_DEFAULTDISPLAY,
1205 FILE_SORT_ALPHA);
1206 }
1207
1208 /** \} */
1209