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