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