Outliner: Collection - Duplicate Hierarchy, and Duplicate Linked Hierarchy
[blender.git] / source / blender / editors / space_outliner / outliner_collections.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
17 /** \file
18  * \ingroup spoutliner
19  */
20
21 #include <string.h>
22
23 #include "BLI_utildefines.h"
24 #include "BLI_listbase.h"
25
26 #include "DNA_collection_types.h"
27 #include "DNA_object_types.h"
28
29 #include "BKE_context.h"
30 #include "BKE_collection.h"
31 #include "BKE_layer.h"
32 #include "BKE_library.h"
33 #include "BKE_main.h"
34 #include "BKE_report.h"
35
36 #include "DEG_depsgraph.h"
37 #include "DEG_depsgraph_build.h"
38
39 #include "ED_object.h"
40 #include "ED_outliner.h"
41 #include "ED_screen.h"
42
43 #include "WM_api.h"
44 #include "WM_types.h"
45 #include "WM_message.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49 #include "RNA_enum_types.h"
50
51 #include "UI_resources.h"
52
53 #include "outliner_intern.h" /* own include */
54
55 /* -------------------------------------------------------------------- */
56
57 bool outliner_is_collection_tree_element(const TreeElement *te)
58 {
59         TreeStoreElem *tselem = TREESTORE(te);
60
61         if (!tselem) {
62                 return false;
63         }
64
65         if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
66                 return true;
67         }
68         else if (tselem->type == 0 && te->idcode == ID_GR) {
69                 return true;
70         }
71
72         return false;
73 }
74
75 Collection *outliner_collection_from_tree_element(const TreeElement *te)
76 {
77         TreeStoreElem *tselem = TREESTORE(te);
78
79         if (!tselem) {
80                 return NULL;
81         }
82
83         if (tselem->type == TSE_LAYER_COLLECTION) {
84                 LayerCollection *lc = te->directdata;
85                 return lc->collection;
86         }
87         else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
88                 Scene *scene = (Scene *)tselem->id;
89                 return BKE_collection_master(scene);
90         }
91         else if (tselem->type == 0 && te->idcode == ID_GR) {
92                 return (Collection *)tselem->id;
93         }
94
95         return NULL;
96 }
97
98 TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
99 {
100         struct IDsSelectedData *data = customdata;
101         TreeStoreElem *tselem = TREESTORE(te);
102
103         if (outliner_is_collection_tree_element(te)) {
104                 BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
105                 return TRAVERSE_CONTINUE;
106         }
107
108         if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) {
109                 return TRAVERSE_SKIP_CHILDS;
110         }
111
112         return TRAVERSE_CONTINUE;
113 }
114
115 TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
116 {
117         struct IDsSelectedData *data = customdata;
118         TreeStoreElem *tselem = TREESTORE(te);
119
120         if (outliner_is_collection_tree_element(te)) {
121                 return TRAVERSE_CONTINUE;
122         }
123
124         if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
125                 return TRAVERSE_SKIP_CHILDS;
126         }
127
128         BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
129
130         return TRAVERSE_CONTINUE;
131 }
132
133 /* -------------------------------------------------------------------- */
134 /* Poll functions. */
135
136 bool ED_outliner_collections_editor_poll(bContext *C)
137 {
138         SpaceOutliner *so = CTX_wm_space_outliner(C);
139         return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
140 }
141
142 static bool outliner_view_layer_collections_editor_poll(bContext *C)
143 {
144         SpaceOutliner *so = CTX_wm_space_outliner(C);
145         return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER);
146 }
147
148 /********************************* New Collection ****************************/
149
150 struct CollectionNewData
151 {
152         bool error;
153         Collection *collection;
154 };
155
156 static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
157 {
158         struct CollectionNewData *data = customdata;
159         Collection *collection = outliner_collection_from_tree_element(te);
160
161         if (!collection) {
162                 return TRAVERSE_SKIP_CHILDS;
163         }
164
165         if (data->collection != NULL) {
166                 data->error = true;
167                 return TRAVERSE_BREAK;
168         }
169
170         data->collection = collection;
171         return TRAVERSE_CONTINUE;
172 }
173
174 static int collection_new_exec(bContext *C, wmOperator *op)
175 {
176         SpaceOutliner *soops = CTX_wm_space_outliner(C);
177         ARegion *ar = CTX_wm_region(C);
178         Main *bmain = CTX_data_main(C);
179         Scene *scene = CTX_data_scene(C);
180         ViewLayer *view_layer = CTX_data_view_layer(C);
181
182         struct CollectionNewData data = {
183                 .error = false,
184                 .collection = NULL,
185         };
186
187         if (RNA_boolean_get(op->ptr, "nested")) {
188                 outliner_build_tree(bmain, scene, view_layer, soops, ar);
189
190                 outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
191
192                 if (data.error) {
193                         BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
194                         return OPERATOR_CANCELLED;
195                 }
196         }
197
198         if (data.collection == NULL) {
199                 data.collection = BKE_collection_master(scene);
200         }
201
202         BKE_collection_add(
203                     bmain,
204                     data.collection,
205                     NULL);
206
207         DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE);
208         DEG_relations_tag_update(bmain);
209
210         outliner_cleanup_tree(soops);
211         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
212         return OPERATOR_FINISHED;
213 }
214
215 void OUTLINER_OT_collection_new(wmOperatorType *ot)
216 {
217         /* identifiers */
218         ot->name = "New Collection";
219         ot->idname = "OUTLINER_OT_collection_new";
220         ot->description = "Add a new collection inside selected collection";
221
222         /* api callbacks */
223         ot->exec = collection_new_exec;
224         ot->poll = ED_outliner_collections_editor_poll;
225
226         /* flags */
227         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
228
229         /* properties */
230         PropertyRNA *prop = RNA_def_boolean(ot->srna, "nested", true, "Nested", "Add as child of selected collection");
231         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
232 }
233
234 /**************************** Delete Collection ******************************/
235
236 struct CollectionEditData {
237         Scene *scene;
238         SpaceOutliner *soops;
239         GSet *collections_to_edit;
240 };
241
242 static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
243 {
244         struct CollectionEditData *data = customdata;
245         Collection *collection = outliner_collection_from_tree_element(te);
246
247         if (!collection) {
248                 return TRAVERSE_SKIP_CHILDS;
249         }
250
251         if (collection->flag & COLLECTION_IS_MASTER) {
252                 /* skip - showing warning/error message might be misleading
253                  * when deleting multiple collections, so just do nothing */
254         }
255         else {
256                 /* Delete, duplicate and link don't edit children, those will come along
257                  * with the parents. */
258                 BLI_gset_add(data->collections_to_edit, collection);
259                 return TRAVERSE_SKIP_CHILDS;
260         }
261
262         return TRAVERSE_CONTINUE;
263 }
264
265 static int collection_delete_exec(bContext *C, wmOperator *op)
266 {
267         struct wmMsgBus *mbus = CTX_wm_message_bus(C);
268         Main *bmain = CTX_data_main(C);
269         Scene *scene = CTX_data_scene(C);
270         ViewLayer *view_layer = CTX_data_view_layer(C);
271         const Base *basact_prev = BASACT(view_layer);
272         SpaceOutliner *soops = CTX_wm_space_outliner(C);
273         struct CollectionEditData data = {.scene = scene, .soops = soops,};
274         bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
275
276         data.collections_to_edit = BLI_gset_ptr_new(__func__);
277
278         /* We first walk over and find the Collections we actually want to delete (ignoring duplicates). */
279         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
280
281         /* Effectively delete the collections. */
282         GSetIterator collections_to_edit_iter;
283         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
284                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
285
286                 /* Test in case collection got deleted as part of another one. */
287                 if (BLI_findindex(&bmain->collection, collection) != -1) {
288                         BKE_collection_delete(bmain, collection, hierarchy);
289                 }
290         }
291
292         BLI_gset_free(data.collections_to_edit, NULL);
293
294         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
295         DEG_relations_tag_update(bmain);
296
297         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
298
299         if (basact_prev != BASACT(view_layer)) {
300                 WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
301         }
302
303         return OPERATOR_FINISHED;
304 }
305
306 void OUTLINER_OT_collection_delete(wmOperatorType *ot)
307 {
308         /* identifiers */
309         ot->name = "Delete Collection";
310         ot->idname = "OUTLINER_OT_collection_delete";
311         ot->description = "Delete selected collections";
312
313         /* api callbacks */
314         ot->exec = collection_delete_exec;
315         ot->poll = ED_outliner_collections_editor_poll;
316
317         /* flags */
318         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
319
320         /* properties */
321         PropertyRNA *prop = RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
322         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
323 }
324
325 /****************************** Select Objects *******************************/
326
327 struct CollectionObjectsSelectData {
328         bool error;
329         LayerCollection *layer_collection;
330 };
331
332 static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata)
333 {
334         struct CollectionObjectsSelectData *data = customdata;
335         TreeStoreElem *tselem = TREESTORE(te);
336
337         switch (tselem->type) {
338                 case TSE_LAYER_COLLECTION:
339                         data->layer_collection = te->directdata;
340                         return TRAVERSE_BREAK;
341                 case TSE_R_LAYER:
342                 case TSE_SCENE_COLLECTION_BASE:
343                 case TSE_VIEW_COLLECTION_BASE:
344                         return TRAVERSE_CONTINUE;
345                 default:
346                         return TRAVERSE_SKIP_CHILDS;
347         }
348 }
349
350 static LayerCollection *outliner_active_layer_collection(bContext *C)
351 {
352         SpaceOutliner *soops = CTX_wm_space_outliner(C);
353
354         struct CollectionObjectsSelectData data = {
355                 .layer_collection = NULL,
356         };
357
358         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data);
359         return data.layer_collection;
360 }
361
362 static int collection_objects_select_exec(bContext *C, wmOperator *op)
363 {
364         ViewLayer *view_layer = CTX_data_view_layer(C);
365         LayerCollection *layer_collection = outliner_active_layer_collection(C);
366         bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
367
368         if (layer_collection == NULL) {
369                 return OPERATOR_CANCELLED;
370         }
371
372         BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
373
374         Scene *scene = CTX_data_scene(C);
375         DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
376         WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
377
378         return OPERATOR_FINISHED;
379 }
380
381 void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
382 {
383         /* identifiers */
384         ot->name = "Select Objects";
385         ot->idname = "OUTLINER_OT_collection_objects_select";
386         ot->description = "Select objects in collection";
387
388         /* api callbacks */
389         ot->exec = collection_objects_select_exec;
390         ot->poll = ED_outliner_collections_editor_poll;
391
392         /* flags */
393         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
394 }
395
396 void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
397 {
398         /* identifiers */
399         ot->name = "Deselect Objects";
400         ot->idname = "OUTLINER_OT_collection_objects_deselect";
401         ot->description = "Deselect objects in collection";
402
403         /* api callbacks */
404         ot->exec = collection_objects_select_exec;
405         ot->poll = ED_outliner_collections_editor_poll;
406
407         /* flags */
408         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
409 }
410
411 /************************** Duplicate Collection *****************************/
412
413 struct CollectionDuplicateData {
414         TreeElement *te;
415 };
416
417 static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata)
418 {
419         struct CollectionDuplicateData *data = customdata;
420         TreeStoreElem *tselem = TREESTORE(te);
421
422         switch (tselem->type) {
423                 case TSE_LAYER_COLLECTION:
424                         data->te = te;
425                         return TRAVERSE_BREAK;
426                 case TSE_R_LAYER:
427                 case TSE_SCENE_COLLECTION_BASE:
428                 case TSE_VIEW_COLLECTION_BASE:
429                 default:
430                         return TRAVERSE_CONTINUE;
431         }
432 }
433
434 static TreeElement *outliner_active_collection(bContext *C)
435 {
436         SpaceOutliner *soops = CTX_wm_space_outliner(C);
437
438         struct CollectionDuplicateData data = {
439                 .te = NULL,
440         };
441
442         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data);
443         return data.te;
444 }
445
446 static int collection_duplicate_exec(bContext *C, wmOperator *op)
447 {
448         Main *bmain = CTX_data_main(C);
449         SpaceOutliner *soops = CTX_wm_space_outliner(C);
450         TreeElement *te = outliner_active_collection(C);
451         bool hierarchy = strstr(op->idname, "hierarchy") != NULL;
452         bool linked = strstr(op->idname, "linked") != NULL;
453
454         /* Can happen when calling from a key binding. */
455         if (te == NULL) {
456                 BKE_report(op->reports, RPT_ERROR, "No active collection");
457                 return OPERATOR_CANCELLED;
458         }
459
460         Collection *collection = outliner_collection_from_tree_element(te);
461         Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
462
463         if (collection->flag & COLLECTION_IS_MASTER) {
464                 BKE_report(op->reports, RPT_ERROR, "Can't duplicate the master collection");
465                 return OPERATOR_CANCELLED;
466         }
467
468         switch (soops->outlinevis) {
469                 case SO_SCENES:
470                 case SO_VIEW_LAYER:
471                 case SO_LIBRARIES:
472                         BKE_collection_duplicate(bmain, parent, collection, hierarchy, !linked);
473                         break;
474         }
475
476         DEG_relations_tag_update(bmain);
477         WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
478
479         return OPERATOR_FINISHED;
480 }
481
482 void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
483 {
484         /* identifiers */
485         ot->name = "Duplicate Collection";
486         ot->idname = "OUTLINER_OT_collection_duplicate";
487         ot->description = "Make a new collection with linked content (collection and objects)";
488
489         /* api callbacks */
490         ot->exec = collection_duplicate_exec;
491         ot->poll = ED_outliner_collections_editor_poll;
492
493         /* flags */
494         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
495 }
496
497 void OUTLINER_OT_collection_duplicate_hierarchy(wmOperatorType *ot)
498 {
499         /* identifiers */
500         ot->name = "Duplicate Collection Hierarchy";
501         ot->idname = "OUTLINER_OT_collection_duplicate_hierarchy";
502         ot->description = "Duplicate entire hierarchy and make all content single user";
503
504         /* api callbacks */
505         ot->exec = collection_duplicate_exec;
506         ot->poll = ED_outliner_collections_editor_poll;
507
508         /* flags */
509         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
510 }
511
512 void OUTLINER_OT_collection_duplicate_linked_hierarchy(wmOperatorType *ot)
513 {
514         /* identifiers */
515         ot->name = "Duplicate Linked Collection Hierarchy";
516         ot->idname = "OUTLINER_OT_collection_duplicate_linked_hierarchy";
517         ot->description = "Duplicate entire hierarchy with linked object data";
518
519         /* api callbacks */
520         ot->exec = collection_duplicate_exec;
521         ot->poll = ED_outliner_collections_editor_poll;
522
523         /* flags */
524         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
525 }
526
527 /**************************** Link Collection ******************************/
528
529 static int collection_link_exec(bContext *C, wmOperator *UNUSED(op))
530 {
531         Main *bmain = CTX_data_main(C);
532         Scene *scene = CTX_data_scene(C);
533         Collection *active_collection = CTX_data_layer_collection(C)->collection;
534         SpaceOutliner *soops = CTX_wm_space_outliner(C);
535         struct CollectionEditData data = {.scene = scene, .soops = soops,};
536
537         data.collections_to_edit = BLI_gset_ptr_new(__func__);
538
539         /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */
540         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
541
542         /* Effectively link the collections. */
543         GSetIterator collections_to_edit_iter;
544         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
545                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
546                 BKE_collection_child_add(bmain, active_collection, collection);
547                 id_fake_user_clear(&collection->id);
548         }
549
550         BLI_gset_free(data.collections_to_edit, NULL);
551
552         DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE);
553         DEG_relations_tag_update(bmain);
554
555         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
556
557         return OPERATOR_FINISHED;
558 }
559
560 void OUTLINER_OT_collection_link(wmOperatorType *ot)
561 {
562         /* identifiers */
563         ot->name = "Link Collection";
564         ot->idname = "OUTLINER_OT_collection_link";
565         ot->description = "Link selected collections to active scene";
566
567         /* api callbacks */
568         ot->exec = collection_link_exec;
569         ot->poll = ED_outliner_collections_editor_poll;
570
571         /* flags */
572         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
573 }
574
575 /************************** Instance Collection ******************************/
576
577 static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
578 {
579         Main *bmain = CTX_data_main(C);
580         Scene *scene = CTX_data_scene(C);
581         ViewLayer *view_layer = CTX_data_view_layer(C);
582         SpaceOutliner *soops = CTX_wm_space_outliner(C);
583         struct CollectionEditData data = {.scene = scene, .soops = soops,};
584
585         data.collections_to_edit = BLI_gset_ptr_new(__func__);
586
587         /* We first walk over and find the Collections we actually want to instance (ignoring duplicates). */
588         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
589
590         /* Find an active collection to add to, that doesn't give dependency cycles. */
591         LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
592
593         GSetIterator collections_to_edit_iter;
594         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
595                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
596
597                 while (BKE_collection_find_cycle(active_lc->collection, collection)) {
598                         active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
599                 }
600         }
601
602         /* Effectively instance the collections. */
603         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
604                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
605                 Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0);
606                 ob->instance_collection = collection;
607                 ob->transflag |= OB_DUPLICOLLECTION;
608                 id_lib_extern(&collection->id);
609         }
610
611         BLI_gset_free(data.collections_to_edit, NULL);
612
613         DEG_relations_tag_update(bmain);
614
615         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
616
617         return OPERATOR_FINISHED;
618 }
619
620 void OUTLINER_OT_collection_instance(wmOperatorType *ot)
621 {
622         /* identifiers */
623         ot->name = "Instance Collection";
624         ot->idname = "OUTLINER_OT_collection_instance";
625         ot->description = "Instance selected collections to active scene";
626
627         /* api callbacks */
628         ot->exec = collection_instance_exec;
629         ot->poll = ED_outliner_collections_editor_poll;
630
631         /* flags */
632         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
633 }
634
635 /************************** Exclude Collection ******************************/
636
637 static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
638 {
639         struct CollectionEditData *data = customdata;
640         TreeStoreElem *tselem = TREESTORE(te);
641
642         if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
643                 return TRAVERSE_CONTINUE;
644         }
645
646         LayerCollection *lc = te->directdata;
647
648         if (lc->collection->flag & COLLECTION_IS_MASTER) {
649                 /* skip - showing warning/error message might be misleading
650                  * when deleting multiple collections, so just do nothing */
651         }
652         else {
653                 /* Delete, duplicate and link don't edit children, those will come along
654                  * with the parents. */
655                 BLI_gset_add(data->collections_to_edit, lc);
656         }
657
658         return TRAVERSE_CONTINUE;
659 }
660
661 static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
662 {
663         /* Poll function so the right click menu show current state of selected collections. */
664         SpaceOutliner *soops = CTX_wm_space_outliner(C);
665         if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) {
666                 return false;
667         }
668
669         Scene *scene = CTX_data_scene(C);
670         struct CollectionEditData data = {.scene = scene, .soops = soops,};
671         data.collections_to_edit = BLI_gset_ptr_new(__func__);
672         bool result = false;
673
674         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
675
676         GSetIterator collections_to_edit_iter;
677         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
678                 LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
679
680                 if (clear && (lc->flag & flag)) {
681                         result = true;
682                 }
683                 else if (!clear && !(lc->flag & flag)) {
684                         result = true;
685                 }
686         }
687
688         BLI_gset_free(data.collections_to_edit, NULL);
689         return result;
690 }
691
692 static bool collections_exclude_set_poll(bContext *C)
693 {
694         return collections_view_layer_poll(C, false, LAYER_COLLECTION_EXCLUDE);
695 }
696
697 static bool collections_exclude_clear_poll(bContext *C)
698 {
699         return collections_view_layer_poll(C, true, LAYER_COLLECTION_EXCLUDE);
700 }
701
702 static bool collections_holdout_set_poll(bContext *C)
703 {
704         return collections_view_layer_poll(C, false, LAYER_COLLECTION_HOLDOUT);
705 }
706
707 static bool collections_holdout_clear_poll(bContext *C)
708 {
709         return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT);
710 }
711
712 static bool collections_indirect_only_set_poll(bContext *C)
713 {
714         return collections_view_layer_poll(C, false, LAYER_COLLECTION_INDIRECT_ONLY);
715 }
716
717 static bool collections_indirect_only_clear_poll(bContext *C)
718 {
719         return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY);
720 }
721
722 static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag)
723 {
724         for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
725                 if (lc->flag & flag) {
726                         nlc->flag |= flag;
727                 }
728                 else {
729                         nlc->flag &= ~flag;
730                 }
731
732                 layer_collection_flag_recursive_set(nlc, flag);
733         }
734 }
735
736 static int collection_view_layer_exec(bContext *C, wmOperator *op)
737 {
738         Main *bmain = CTX_data_main(C);
739         Scene *scene = CTX_data_scene(C);
740         ViewLayer *view_layer = CTX_data_view_layer(C);
741         SpaceOutliner *soops = CTX_wm_space_outliner(C);
742         struct CollectionEditData data = {.scene = scene, .soops = soops,};
743         bool clear = strstr(op->idname, "clear") != NULL;
744         int flag = strstr(op->idname, "holdout") ?       LAYER_COLLECTION_HOLDOUT :
745                    strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY :
746                                                          LAYER_COLLECTION_EXCLUDE;
747
748         data.collections_to_edit = BLI_gset_ptr_new(__func__);
749
750         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
751
752         GSetIterator collections_to_edit_iter;
753         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
754                 LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
755
756                 if (clear) {
757                         lc->flag &= ~flag;
758                 }
759                 else {
760                         lc->flag |= flag;
761                 }
762
763                 layer_collection_flag_recursive_set(lc, flag);
764         }
765
766         BLI_gset_free(data.collections_to_edit, NULL);
767
768         BKE_layer_collection_sync(scene, view_layer);
769         DEG_relations_tag_update(bmain);
770
771         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
772
773         return OPERATOR_FINISHED;
774 }
775
776 void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot)
777 {
778         /* identifiers */
779         ot->name = "Set Exclude";
780         ot->idname = "OUTLINER_OT_collection_exclude_set";
781         ot->description = "Exclude collection from the active view layer";
782
783         /* api callbacks */
784         ot->exec = collection_view_layer_exec;
785         ot->poll = collections_exclude_set_poll;
786
787         /* flags */
788         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
789 }
790
791 void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot)
792 {
793         /* identifiers */
794         ot->name = "Clear Exclude";
795         ot->idname = "OUTLINER_OT_collection_exclude_clear";
796         ot->description = "Include collection in the active view layer";
797
798         /* api callbacks */
799         ot->exec = collection_view_layer_exec;
800         ot->poll = collections_exclude_clear_poll;
801
802         /* flags */
803         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
804 }
805
806 void OUTLINER_OT_collection_holdout_set(wmOperatorType *ot)
807 {
808         /* identifiers */
809         ot->name = "Set Holdout";
810         ot->idname = "OUTLINER_OT_collection_holdout_set";
811         ot->description = "Mask collection in the active view layer";
812
813         /* api callbacks */
814         ot->exec = collection_view_layer_exec;
815         ot->poll = collections_holdout_set_poll;
816
817         /* flags */
818         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
819 }
820
821 void OUTLINER_OT_collection_holdout_clear(wmOperatorType *ot)
822 {
823         /* identifiers */
824         ot->name = "Clear Holdout";
825         ot->idname = "OUTLINER_OT_collection_holdout_clear";
826         ot->description = "Clear masking of collection in the active view layer";
827
828         /* api callbacks */
829         ot->exec = collection_view_layer_exec;
830         ot->poll = collections_holdout_clear_poll;
831
832         /* flags */
833         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
834 }
835
836 void OUTLINER_OT_collection_indirect_only_set(wmOperatorType *ot)
837 {
838         /* identifiers */
839         ot->name = "Set Indirect Only";
840         ot->idname = "OUTLINER_OT_collection_indirect_only_set";
841         ot->description = "Set collection to only contribute indirectly (through shadows and reflections) in the view layer";
842
843         /* api callbacks */
844         ot->exec = collection_view_layer_exec;
845         ot->poll = collections_indirect_only_set_poll;
846
847         /* flags */
848         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
849 }
850
851 void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot)
852 {
853         /* identifiers */
854         ot->name = "Clear Indirect Only";
855         ot->idname = "OUTLINER_OT_collection_indirect_only_clear";
856         ot->description = "Clear collection contributing only indirectly in the view layer";
857
858         /* api callbacks */
859         ot->exec = collection_view_layer_exec;
860         ot->poll = collections_indirect_only_clear_poll;
861
862         /* flags */
863         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
864 }
865
866 /************************** Visibility Operators ******************************/
867
868 static int collection_isolate_exec(bContext *C, wmOperator *op)
869 {
870         Scene *scene = CTX_data_scene(C);
871         ViewLayer *view_layer = CTX_data_view_layer(C);
872         SpaceOutliner *soops = CTX_wm_space_outliner(C);
873         const bool extend = RNA_boolean_get(op->ptr, "extend");
874         bool depsgraph_changed = false;
875         struct CollectionEditData data = {.scene = scene, .soops = soops,};
876         data.collections_to_edit = BLI_gset_ptr_new(__func__);
877
878         /* Hide all collections before the isolate function - needed in order to support multiple selected collections. */
879         if (!extend) {
880                 LayerCollection *lc_master = view_layer->layer_collections.first;
881                 for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
882                         lc_iter->flag |= LAYER_COLLECTION_RESTRICT_VIEW;
883                         layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW);
884                 }
885         }
886
887         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
888
889         GSetIterator collections_to_edit_iter;
890         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
891                 LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
892                 depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, layer_collection, true);
893         }
894         BLI_gset_free(data.collections_to_edit, NULL);
895
896         BKE_layer_collection_sync(scene, view_layer);
897         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
898
899         if (depsgraph_changed) {
900                 DEG_relations_tag_update(CTX_data_main(C));
901         }
902
903         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
904         return OPERATOR_FINISHED;
905 }
906
907 static int collection_isolate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
908 {
909         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "extend");
910         if (!RNA_property_is_set(op->ptr, prop) && (event->shift)) {
911                 RNA_property_boolean_set(op->ptr, prop, true);
912         }
913         return collection_isolate_exec(C, op);
914 }
915
916 void OUTLINER_OT_collection_isolate(wmOperatorType *ot)
917 {
918         /* identifiers */
919         ot->name = "Isolate Collection";
920         ot->idname = "OUTLINER_OT_collection_isolate";
921         ot->description = "Hide all but this collection and its parents";
922
923         /* api callbacks */
924         ot->exec = collection_isolate_exec;
925         ot->invoke = collection_isolate_invoke;
926         ot->poll = ED_outliner_collections_editor_poll;
927
928         /* flags */
929         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
930
931         /* properties */
932         PropertyRNA *prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend current visible collections");
933         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
934 }
935
936 static bool collection_show_poll(bContext *C)
937 {
938         return collections_view_layer_poll(C, true, LAYER_COLLECTION_RESTRICT_VIEW);
939 }
940
941 static bool collection_hide_poll(bContext *C)
942 {
943         return collections_view_layer_poll(C, false, LAYER_COLLECTION_RESTRICT_VIEW);
944 }
945
946 static bool collection_inside_poll(bContext *C)
947 {
948         if (!ED_outliner_collections_editor_poll(C)) {
949                 return false;
950         }
951         return outliner_active_layer_collection(C) != NULL;
952 }
953
954 static int collection_visibility_exec(bContext *C, wmOperator *op)
955 {
956         Scene *scene = CTX_data_scene(C);
957         ViewLayer *view_layer = CTX_data_view_layer(C);
958         SpaceOutliner *soops = CTX_wm_space_outliner(C);
959         const bool is_inside = strstr(op->idname, "inside") != NULL;
960         const bool show = strstr(op->idname, "show") != NULL;
961         bool depsgraph_changed = false;
962         struct CollectionEditData data = {.scene = scene, .soops = soops,};
963         data.collections_to_edit = BLI_gset_ptr_new(__func__);
964
965         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
966
967         GSetIterator collections_to_edit_iter;
968         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
969                 LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
970                 depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside);
971         }
972         BLI_gset_free(data.collections_to_edit, NULL);
973
974         BKE_layer_collection_sync(scene, view_layer);
975         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
976
977         if (depsgraph_changed) {
978                 DEG_relations_tag_update(CTX_data_main(C));
979         }
980
981         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
982         return OPERATOR_FINISHED;
983 }
984
985 void OUTLINER_OT_collection_show(wmOperatorType *ot)
986 {
987         /* identifiers */
988         ot->name = "Show Collection";
989         ot->idname = "OUTLINER_OT_collection_show";
990         ot->description = "Show the collection in this view layer";
991
992         /* api callbacks */
993         ot->exec = collection_visibility_exec;
994         ot->poll = collection_show_poll;
995
996         /* flags */
997         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
998 }
999
1000 void OUTLINER_OT_collection_hide(wmOperatorType *ot)
1001 {
1002         /* identifiers */
1003         ot->name = "Hide Collection";
1004         ot->idname = "OUTLINER_OT_collection_hide";
1005         ot->description = "Hide the collection in this view layer";
1006
1007         /* api callbacks */
1008         ot->exec = collection_visibility_exec;
1009         ot->poll = collection_hide_poll;
1010
1011         /* flags */
1012         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1013 }
1014
1015 void OUTLINER_OT_collection_show_inside(wmOperatorType *ot)
1016 {
1017         /* identifiers */
1018         ot->name = "Show Inside Collection";
1019         ot->idname = "OUTLINER_OT_collection_show_inside";
1020         ot->description = "Show all the objects and collections inside the collection";
1021
1022         /* api callbacks */
1023         ot->exec = collection_visibility_exec;
1024         ot->poll = collection_inside_poll;
1025
1026         /* flags */
1027         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1028 }
1029
1030 void OUTLINER_OT_collection_hide_inside(wmOperatorType *ot)
1031 {
1032         /* identifiers */
1033         ot->name = "Hide Inside Collection";
1034         ot->idname = "OUTLINER_OT_collection_hide_inside";
1035         ot->description = "Hide all the objects and collections inside the collection";
1036
1037         /* api callbacks */
1038         ot->exec = collection_visibility_exec;
1039         ot->poll = collection_inside_poll;
1040
1041         /* flags */
1042         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1043 }
1044
1045 static bool collection_flag_poll(bContext *C, bool clear, int flag)
1046 {
1047         if (!ED_outliner_collections_editor_poll(C)) {
1048                 return false;
1049         }
1050
1051         TreeElement *te = outliner_active_collection(C);
1052         if (te == NULL) {
1053                 return false;
1054         }
1055
1056         Collection *collection = outliner_collection_from_tree_element(te);
1057         if (collection == NULL) {
1058                 return false;
1059         }
1060
1061         if (clear && (collection->flag & flag)) {
1062                 return true;
1063         }
1064         else if (!clear && !(collection->flag & flag)) {
1065                 return true;
1066         }
1067
1068         return false;
1069 }
1070
1071 static bool collection_enable_poll(bContext *C)
1072 {
1073         return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEW);
1074 }
1075
1076 static bool collection_disable_poll(bContext *C)
1077 {
1078         return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEW);
1079 }
1080
1081 static bool collection_enable_render_poll(bContext *C)
1082 {
1083         return collection_flag_poll(C, true, COLLECTION_RESTRICT_RENDER);
1084 }
1085
1086 static bool collection_disable_render_poll(bContext *C)
1087 {
1088         return collection_flag_poll(C, false, COLLECTION_RESTRICT_RENDER);
1089 }
1090
1091 static int collection_flag_exec(bContext *C, wmOperator *op)
1092 {
1093         Scene *scene = CTX_data_scene(C);
1094         ViewLayer *view_layer = CTX_data_view_layer(C);
1095         SpaceOutliner *soops = CTX_wm_space_outliner(C);
1096         const bool is_render = strstr(op->idname, "render");
1097         const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable");
1098         int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEW;
1099         struct CollectionEditData data = {.scene = scene, .soops = soops,};
1100         data.collections_to_edit = BLI_gset_ptr_new(__func__);
1101         const bool has_layer_collection = soops->outlinevis == SO_VIEW_LAYER;
1102
1103         if (has_layer_collection) {
1104                 outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
1105                 GSetIterator collections_to_edit_iter;
1106                 GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
1107                         LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
1108                         Collection *collection = layer_collection->collection;
1109                         if (ID_IS_LINKED(collection)) {
1110                                 continue;
1111                         }
1112                         if (clear) {
1113                                 collection->flag &= ~flag;
1114                         }
1115                         else {
1116                                 collection->flag |= flag;
1117                         }
1118
1119                         /* Make sure (at least for this view layer) the collection is visible. */
1120                         if (clear && !is_render) {
1121                                 layer_collection->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
1122                         }
1123                 }
1124                 BLI_gset_free(data.collections_to_edit, NULL);
1125         }
1126         else {
1127                 outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
1128                 GSetIterator collections_to_edit_iter;
1129                 GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
1130                         Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
1131
1132                         if (clear) {
1133                                 collection->flag &= ~flag;
1134                         }
1135                         else {
1136                                 collection->flag |= flag;
1137                         }
1138                 }
1139                 BLI_gset_free(data.collections_to_edit, NULL);
1140         }
1141
1142         BKE_layer_collection_sync(scene, view_layer);
1143         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
1144
1145         if (!is_render) {
1146                 DEG_relations_tag_update(CTX_data_main(C));
1147         }
1148
1149         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
1150         return OPERATOR_FINISHED;
1151 }
1152
1153 void OUTLINER_OT_collection_enable(wmOperatorType *ot)
1154 {
1155         /* identifiers */
1156         ot->name = "Enable Collection";
1157         ot->idname = "OUTLINER_OT_collection_enable";
1158         ot->description = "Enable viewport drawing in the view layers";
1159
1160         /* api callbacks */
1161         ot->exec = collection_flag_exec;
1162         ot->poll = collection_enable_poll;
1163
1164         /* flags */
1165         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1166 }
1167
1168 void OUTLINER_OT_collection_disable(wmOperatorType *ot)
1169 {
1170         /* identifiers */
1171         ot->name = "Disable Collection";
1172         ot->idname = "OUTLINER_OT_collection_disable";
1173         ot->description = "Disable viewport drawing in the view layers";
1174
1175         /* api callbacks */
1176         ot->exec = collection_flag_exec;
1177         ot->poll = collection_disable_poll;
1178
1179         /* flags */
1180         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1181 }
1182
1183 void OUTLINER_OT_collection_enable_render(wmOperatorType *ot)
1184 {
1185         /* identifiers */
1186         ot->name = "Enable Collection in Render";
1187         ot->idname = "OUTLINER_OT_collection_enable_render";
1188         ot->description = "Render the collection";
1189
1190         /* api callbacks */
1191         ot->exec = collection_flag_exec;
1192         ot->poll = collection_enable_render_poll;
1193
1194         /* flags */
1195         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1196 }
1197
1198 void OUTLINER_OT_collection_disable_render(wmOperatorType *ot)
1199 {
1200         /* identifiers */
1201         ot->name = "Disable Collection in Render";
1202         ot->idname = "OUTLINER_OT_collection_disable_render";
1203         ot->description = "Do not render this collection";
1204
1205         /* api callbacks */
1206         ot->exec = collection_flag_exec;
1207         ot->poll = collection_disable_render_poll;
1208
1209         /* flags */
1210         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1211 }
1212
1213 struct OutlinerHideEditData {
1214         Scene *scene;
1215         ViewLayer *view_layer;
1216         SpaceOutliner *soops;
1217         GSet *collections_to_edit;
1218         GSet *bases_to_edit;
1219 };
1220
1221 static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata)
1222 {
1223         struct OutlinerHideEditData *data = customdata;
1224         TreeStoreElem *tselem = TREESTORE(te);
1225
1226         if (tselem == NULL) {
1227                 return TRAVERSE_CONTINUE;
1228         }
1229
1230         if (tselem->type == TSE_LAYER_COLLECTION) {
1231                 LayerCollection *lc = te->directdata;
1232
1233                 if (lc->collection->flag & COLLECTION_IS_MASTER) {
1234                         /* Skip - showing warning/error message might be misleading
1235                          * when deleting multiple collections, so just do nothing. */
1236                 }
1237                 else {
1238                         /* Delete, duplicate and link don't edit children,
1239                          * those will come along with the parents. */
1240                         BLI_gset_add(data->collections_to_edit, lc);
1241                 }
1242         }
1243         else if (tselem->type == 0 && te->idcode == ID_OB) {
1244                 Object *ob = (Object *)tselem->id;
1245                 Base *base = BKE_view_layer_base_find(data->view_layer, ob);
1246                 BLI_gset_add(data->bases_to_edit, base);
1247         }
1248
1249         return TRAVERSE_CONTINUE;
1250 }
1251
1252 static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
1253 {
1254         Scene *scene = CTX_data_scene(C);
1255         ViewLayer *view_layer = CTX_data_view_layer(C);
1256         SpaceOutliner *soops = CTX_wm_space_outliner(C);
1257         struct OutlinerHideEditData data = {.scene = scene, .view_layer = view_layer, .soops = soops,};
1258         data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit");
1259         data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit");
1260
1261         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_hide_find_data_to_edit, &data);
1262
1263         GSetIterator collections_to_edit_iter;
1264         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
1265                 LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
1266                 BKE_layer_collection_set_visible(view_layer, layer_collection, false, false);
1267         }
1268         BLI_gset_free(data.collections_to_edit, NULL);
1269
1270         GSetIterator bases_to_edit_iter;
1271         GSET_ITER(bases_to_edit_iter, data.bases_to_edit) {
1272                 Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter);
1273                 base->flag |= BASE_HIDDEN;
1274         }
1275         BLI_gset_free(data.bases_to_edit, NULL);
1276
1277         BKE_layer_collection_sync(scene, view_layer);
1278         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
1279
1280         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
1281         return OPERATOR_FINISHED;
1282 }
1283
1284 void OUTLINER_OT_hide(wmOperatorType *ot)
1285 {
1286         /* identifiers */
1287         ot->name = "Hide";
1288         ot->idname = "OUTLINER_OT_hide";
1289         ot->description = "Hide selected objects and collections";
1290
1291         /* api callbacks */
1292         ot->exec = outliner_hide_exec;
1293         ot->poll = outliner_view_layer_collections_editor_poll;
1294
1295         /* flags */
1296         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1297 }
1298
1299 static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
1300 {
1301         Scene *scene = CTX_data_scene(C);
1302         ViewLayer *view_layer = CTX_data_view_layer(C);
1303
1304         /* Unhide all the collections. */
1305         LayerCollection *lc_master = view_layer->layer_collections.first;
1306         for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
1307                 lc_iter->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
1308                 layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW);
1309         }
1310
1311         /* Unhide all objects. */
1312         for (Base *base = view_layer->object_bases.first; base; base = base->next) {
1313                 base->flag &= ~BASE_HIDDEN;
1314         }
1315
1316         BKE_layer_collection_sync(scene, view_layer);
1317         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
1318
1319         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
1320         return OPERATOR_FINISHED;
1321 }
1322
1323 void OUTLINER_OT_unhide_all(wmOperatorType *ot)
1324 {
1325         /* identifiers */
1326         ot->name = "Unhide All";
1327         ot->idname = "OUTLINER_OT_unhide_all";
1328         ot->description = "Unhide all objects and collections";
1329
1330         /* api callbacks */
1331         ot->exec = outliner_unhide_all_exec;
1332         ot->poll = outliner_view_layer_collections_editor_poll;
1333
1334         /* flags */
1335         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1336 }
1337
1338 /**
1339  * Populates the \param objects: ListBase with all the outliner selected objects
1340  * We store it as (Object *)LinkData->data
1341  * \param objects: expected to be empty
1342  */
1343 void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
1344 {
1345         SpaceOutliner *soops = CTX_wm_space_outliner(C);
1346         struct IDsSelectedData data = {{NULL}};
1347         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
1348         LISTBASE_FOREACH (LinkData *, link, &data.selected_array) {
1349                 TreeElement *ten_selected = (TreeElement *)link->data;
1350                 Object *ob = (Object *)TREESTORE(ten_selected)->id;
1351                 BLI_addtail(objects, BLI_genericNodeN(ob));
1352         }
1353         BLI_freelistN(&data.selected_array);
1354 }