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