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