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