Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_outliner / outliner_tools.c
index 7515132..8a01e5a 100644 (file)
 #include "BLI_utildefines.h"
 
 #include "BKE_animsys.h"
+#include "BKE_collection.h"
 #include "BKE_context.h"
 #include "BKE_constraint.h"
-#include "BKE_depsgraph.h"
 #include "BKE_fcurve.h"
-#include "BKE_group.h"
+#include "BKE_layer.h"
 #include "BKE_library.h"
+#include "BKE_library_override.h"
 #include "BKE_library_query.h"
 #include "BKE_library_remap.h"
 #include "BKE_main.h"
 #include "BKE_scene.h"
 #include "BKE_sequencer.h"
 
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
 #include "ED_armature.h"
 #include "ED_object.h"
+#include "ED_scene.h"
 #include "ED_screen.h"
 #include "ED_sequencer.h"
 #include "ED_undo.h"
@@ -100,7 +105,8 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
        for (te = lb->first; te; te = te->next) {
                tselem = TREESTORE(te);
                if (tselem->flag & TSE_SELECTED) {
-                       if (tselem->type) {
+                       /* Layer collection points to collection ID. */
+                       if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
                                if (*datalevel == 0)
                                        *datalevel = tselem->type;
                                else if (*datalevel != tselem->type)
@@ -124,6 +130,9 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
                                        case ID_LI:
                                                if (*idlevel == 0) *idlevel = idcode;
                                                else if (*idlevel != idcode) *idlevel = -1;
+                                               if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) {
+                                                       *datalevel = 0;
+                                               }
                                                break;
                                }
                        }
@@ -191,19 +200,7 @@ static void unlink_texture_cb(
        MTex **mtex = NULL;
        int a;
 
-       if (GS(tsep->id->name) == ID_MA) {
-               Material *ma = (Material *)tsep->id;
-               mtex = ma->mtex;
-       }
-       else if (GS(tsep->id->name) == ID_LA) {
-               Lamp *la = (Lamp *)tsep->id;
-               mtex = la->mtex;
-       }
-       else if (GS(tsep->id->name) == ID_WO) {
-               World *wrld = (World *)tsep->id;
-               mtex = wrld->mtex;
-       }
-       else if (GS(tsep->id->name) == ID_LS) {
+       if (GS(tsep->id->name) == ID_LS) {
                FreestyleLineStyle *ls = (FreestyleLineStyle *)tsep->id;
                mtex = ls->mtex;
        }
@@ -221,21 +218,52 @@ static void unlink_texture_cb(
        }
 }
 
-static void unlink_group_cb(
+static void unlink_collection_cb(
         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
         TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
 {
-       Group *group = (Group *)tselem->id;
+       Main *bmain = CTX_data_main(C);
+       Collection *collection = (Collection *)tselem->id;
 
        if (tsep) {
                if (GS(tsep->id->name) == ID_OB) {
                        Object *ob = (Object *)tsep->id;
                        ob->dup_group = NULL;
+                       DEG_relations_tag_update(bmain);
+               }
+               else if (GS(tsep->id->name) == ID_GR) {
+                       Collection *parent = (Collection *)tsep->id;
+                       id_fake_user_set(&collection->id);
+                       BKE_collection_child_remove(bmain, parent, collection);
+                       DEG_relations_tag_update(bmain);
+               }
+               else if (GS(tsep->id->name) == ID_SCE) {
+                       Collection *parent = BKE_collection_master((Scene *)tsep->id);
+                       id_fake_user_set(&collection->id);
+                       BKE_collection_child_remove(bmain, parent, collection);
+                       DEG_relations_tag_update(bmain);
                }
        }
-       else {
-               Main *bmain = CTX_data_main(C);
-               BKE_libblock_delete(bmain, group);
+}
+
+static void unlink_object_cb(
+        bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+        TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+       Main *bmain = CTX_data_main(C);
+       Object *ob = (Object *)tselem->id;
+
+       if (tsep) {
+               if (GS(tsep->id->name) == ID_GR) {
+                       Collection *parent = (Collection *)tsep->id;
+                       BKE_collection_object_remove(bmain, parent, ob, true);
+                       DEG_relations_tag_update(bmain);
+               }
+               else if (GS(tsep->id->name) == ID_SCE) {
+                       Collection *parent = BKE_collection_master((Scene *)tsep->id);
+                       BKE_collection_object_remove(bmain, parent, ob, true);
+                       DEG_relations_tag_update(bmain);
+               }
        }
 }
 
@@ -262,7 +290,7 @@ static void outliner_do_libdata_operation(
        for (te = lb->first; te; te = te->next) {
                tselem = TREESTORE(te);
                if (tselem->flag & TSE_SELECTED) {
-                       if (tselem->type == 0) {
+                       if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
                                TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
                                operation_cb(C, reports, scene, te, tsep, tselem, user_data);
                        }
@@ -308,7 +336,7 @@ static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNU
        Scene *scene = (Scene *)tselem->id;
 
        if (event == OL_SCENE_OP_DELETE) {
-               if (ED_screen_delete_scene(C, scene)) {
+               if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene)) {
                        WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
                }
                else {
@@ -359,15 +387,15 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
 /* ******************************************** */
 
 static void object_select_cb(
-        bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+        bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
 {
-       Base *base = (Base *)te->directdata;
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       Object *ob = (Object *)tselem->id;
+       Base *base = BKE_view_layer_base_find(view_layer, ob);
 
-       if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
-       if (base && ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0)) {
-               base->flag |= SELECT;
-               base->object->flag |= SELECT;
+       if (base && ((base->flag & BASE_VISIBLED) != 0)) {
+               base->flag |= BASE_SELECTED;
        }
 }
 
@@ -381,15 +409,15 @@ static void object_select_hierarchy_cb(
 }
 
 static void object_deselect_cb(
-        bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+        bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
 {
-       Base *base = (Base *)te->directdata;
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       Object *ob = (Object *)tselem->id;
+       Base *base = BKE_view_layer_base_find(view_layer, ob);
 
-       if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
        if (base) {
-               base->flag &= ~SELECT;
-               base->object->flag &= ~SELECT;
+               base->flag &= ~BASE_SELECTED;
        }
 }
 
@@ -397,31 +425,27 @@ static void object_delete_cb(
         bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
         TreeStoreElem *tsep, TreeStoreElem *tselem, void *user_data)
 {
-       Base *base = (Base *)te->directdata;
-
-       if (base == NULL)
-               base = BKE_scene_base_find(scene, (Object *)tselem->id);
-       if (base) {
+       Object *ob = (Object *)tselem->id;
+       if (ob) {
                Main *bmain = CTX_data_main(C);
-               if (base->object->id.tag & LIB_TAG_INDIRECT) {
-                       BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+               if (ob->id.tag & LIB_TAG_INDIRECT) {
+                       BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
                        return;
                }
-               else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
-                        ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
+               else if (BKE_library_ID_is_indirectly_used(bmain, ob) &&
+                        ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0)
                {
                        BKE_reportf(reports, RPT_WARNING,
                                    "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
-                                   base->object->id.name + 2, scene->id.name + 2);
+                                   ob->id.name + 2, scene->id.name + 2);
                        return;
                }
 
                // check also library later
-               if (scene->obedit == base->object) {
+               if (ob == CTX_data_edit_object(C)) {
                        ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
                }
-
-               ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+               ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob);
                /* leave for ED_outliner_id_unref to handle */
 #if 0
                te->directdata = NULL;
@@ -454,6 +478,19 @@ static void id_local_cb(
        }
 }
 
+static void id_static_override_cb(
+        bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+        TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+       if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+               Main *bmain = CTX_data_main(C);
+               ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id);
+               if (override_id != NULL) {
+                       BKE_main_id_clear_newpoins(bmain);
+               }
+       }
+}
+
 static void id_fake_user_set_cb(
         bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
@@ -518,38 +555,6 @@ static void singleuser_world_cb(
        }
 }
 
-static void group_linkobs2scene_cb(
-        bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
-        TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
-       Group *group = (Group *)tselem->id;
-       GroupObject *gob;
-       Base *base;
-
-       for (gob = group->gobject.first; gob; gob = gob->next) {
-               base = BKE_scene_base_find(scene, gob->ob);
-               if (!base) {
-                       /* link to scene */
-                       base = BKE_scene_base_add(scene, gob->ob);
-                       id_us_plus(&gob->ob->id);
-               }
-               base->object->flag |= SELECT;
-               base->flag |= SELECT;
-       }
-}
-
-static void group_instance_cb(
-        bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
-        TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
-       Group *group = (Group *)tselem->id;
-
-       Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor, NULL, false, scene->layact);
-       ob->dup_group = group;
-       ob->transflag |= OB_DUPLIGROUP;
-       id_lib_extern(&group->id);
-}
-
 /**
  * \param select_recurse: Set to false for operations which are already recursively operating on their children.
  */
@@ -567,7 +572,7 @@ void outliner_do_object_operation_ex(
                                // when objects selected in other scenes... dunno if that should be allowed
                                Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE);
                                if (scene_owner && scene_act != scene_owner) {
-                                       ED_screen_set_scene(C, CTX_wm_screen(C), scene_owner);
+                                       WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner);
                                }
                                /* important to use 'scene_owner' not scene_act else deleting objects can crash.
                                 * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
@@ -790,12 +795,12 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
 
        if (event == OL_MODIFIER_OP_TOGVIS) {
                md->mode ^= eModifierMode_Realtime;
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
        }
        else if (event == OL_MODIFIER_OP_TOGREN) {
                md->mode ^= eModifierMode_Render;
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
        }
        else if (event == OL_MODIFIER_OP_DELETE) {
@@ -829,12 +834,13 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
 {
        Base *child_base, *base_next;
        Object *parent;
+       ViewLayer *view_layer = CTX_data_view_layer(C);
 
        if (!base) {
                return NULL;
        }
 
-       for (child_base = scene->base.first; child_base; child_base = base_next) {
+       for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) {
                base_next = child_base->next;
                for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
                if (parent) {
@@ -857,7 +863,7 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
                            base->object->id.name + 2, scene->id.name + 2);
                return base_next;
        }
-       ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+       ED_object_base_free_and_unlink(CTX_data_main(C), scene, base->object);
        return base_next;
 }
 
@@ -865,11 +871,12 @@ static void object_delete_hierarchy_cb(
         bContext *C, ReportList *reports, Scene *scene,
         TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
 {
+       ViewLayer *view_layer = CTX_data_view_layer(C);
        Base *base = (Base *)te->directdata;
-       Object *obedit = scene->obedit;
+       Object *obedit = CTX_data_edit_object(C);
 
        if (!base) {
-               base = BKE_scene_base_find(scene, (Object *)tselem->id);
+               base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id);
        }
        if (base) {
                /* Check also library later. */
@@ -913,9 +920,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
        {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
        {OL_OP_REMAP, "REMAP",   0, "Remap Users",
         "Make all users of selected data-blocks to use instead a new chosen one"},
-       {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
-       {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
-       {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
        {OL_OP_RENAME, "RENAME", 0, "Rename", ""},
        {0, NULL, 0, NULL, NULL}
 };
@@ -924,6 +928,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
+       wmWindow *win = CTX_wm_window(C);
        SpaceOops *soops = CTX_wm_space_outliner(C);
        int event;
        const char *str = NULL;
@@ -938,7 +943,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
                Scene *sce = scene;  // to be able to delete, scenes are set...
                outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb);
                if (scene != sce) {
-                       ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+                       WM_window_change_active_scene(bmain, C, win, sce);
                }
 
                str = "Select Objects";
@@ -948,7 +953,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
                Scene *sce = scene;  // to be able to delete, scenes are set...
                outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
                if (scene != sce) {
-                       ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+                       WM_window_change_active_scene(bmain, C, win, sce);
                }
                str = "Select Object Hierarchy";
                WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -968,7 +973,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
                 *      cleanup tree here to prevent such cases. */
                outliner_cleanup_tree(soops);
 
-               DAG_relations_tag_update(bmain);
+               DEG_relations_tag_update(bmain);
                str = "Delete Objects";
                WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
        }
@@ -978,7 +983,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
                /* XXX: See OL_OP_DELETE comment above. */
                outliner_cleanup_tree(soops);
 
-               DAG_relations_tag_update(bmain);
+               DEG_relations_tag_update(bmain);
                str = "Delete Object Hierarchy";
                WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
        }
@@ -990,21 +995,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
                outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
                str = "Localized Objects";
        }
-       else if (event == OL_OP_TOGVIS) {
-               outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
-               str = "Toggle Visibility";
-               WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
-       }
-       else if (event == OL_OP_TOGSEL) {
-               outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
-               str = "Toggle Selectability";
-               WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
-       }
-       else if (event == OL_OP_TOGREN) {
-               outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
-               str = "Toggle Renderability";
-               WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
-       }
        else if (event == OL_OP_RENAME) {
                outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb);
                str = "Rename Object";
@@ -1039,114 +1029,12 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
 
 /* **************************************** */
 
-typedef enum eOutliner_PropGroupOps {
-       OL_GROUPOP_UNLINK = 1,
-       OL_GROUPOP_LOCAL,
-       OL_GROUPOP_LINK,
-       OL_GROUPOP_DELETE,
-       OL_GROUPOP_REMAP,
-       OL_GROUPOP_INSTANCE,
-       OL_GROUPOP_TOGVIS,
-       OL_GROUPOP_TOGSEL,
-       OL_GROUPOP_TOGREN,
-       OL_GROUPOP_RENAME,
-} eOutliner_PropGroupOps;
-
-static const EnumPropertyItem prop_group_op_types[] = {
-       {OL_GROUPOP_UNLINK, "UNLINK",     0, "Unlink Group", ""},
-       {OL_GROUPOP_LOCAL, "LOCAL",       0, "Make Local Group", ""},
-       {OL_GROUPOP_LINK, "LINK",         0, "Link Group Objects to Scene", ""},
-       {OL_GROUPOP_DELETE, "DELETE",     0, "Delete Group", ""},
-       {OL_GROUPOP_REMAP, "REMAP",       0, "Remap Users",
-        "Make all users of selected data-blocks to use instead current (clicked) one"},
-       {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
-       {OL_GROUPOP_TOGVIS, "TOGVIS",     0, "Toggle Visible Group", ""},
-       {OL_GROUPOP_TOGSEL, "TOGSEL",     0, "Toggle Selectable", ""},
-       {OL_GROUPOP_TOGREN, "TOGREN",     0, "Toggle Renderable", ""},
-       {OL_GROUPOP_RENAME, "RENAME",     0, "Rename", ""},
-       {0, NULL, 0, NULL, NULL}
-};
-
-static int outliner_group_operation_exec(bContext *C, wmOperator *op)
-{
-       Scene *scene = CTX_data_scene(C);
-       SpaceOops *soops = CTX_wm_space_outliner(C);
-       int event;
-
-       /* check for invalid states */
-       if (soops == NULL)
-               return OPERATOR_CANCELLED;
-
-       event = RNA_enum_get(op->ptr, "type");
-
-       switch (event) {
-               case OL_GROUPOP_UNLINK:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL);
-                       break;
-               case OL_GROUPOP_LOCAL:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
-                       break;
-               case OL_GROUPOP_LINK:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
-                       break;
-               case OL_GROUPOP_INSTANCE:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL);
-                       /* works without this except if you try render right after, see: 22027 */
-                       DAG_relations_tag_update(CTX_data_main(C));
-                       break;
-               case OL_GROUPOP_DELETE:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
-                       break;
-               case OL_GROUPOP_REMAP:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
-                       break;
-               case OL_GROUPOP_TOGVIS:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
-                       break;
-               case OL_GROUPOP_TOGSEL:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
-                       break;
-               case OL_GROUPOP_TOGREN:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
-                       break;
-               case OL_GROUPOP_RENAME:
-                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
-                       break;
-               default:
-                       BLI_assert(0);
-       }
-
-       ED_undo_push(C, prop_group_op_types[event - 1].name);
-       WM_event_add_notifier(C, NC_GROUP, NULL);
-
-       return OPERATOR_FINISHED;
-}
-
-
-void OUTLINER_OT_group_operation(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name = "Outliner Group Operation";
-       ot->idname = "OUTLINER_OT_group_operation";
-       ot->description = "";
-
-       /* callbacks */
-       ot->invoke = WM_menu_invoke;
-       ot->exec = outliner_group_operation_exec;
-       ot->poll = ED_operator_outliner_active;
-
-       ot->flag = 0;
-
-       ot->prop = RNA_def_enum(ot->srna, "type", prop_group_op_types, 0, "Group Operation", "");
-}
-
-/* **************************************** */
-
 typedef enum eOutlinerIdOpTypes {
        OUTLINER_IDOP_INVALID = 0,
 
        OUTLINER_IDOP_UNLINK,
        OUTLINER_IDOP_LOCAL,
+       OUTLINER_IDOP_STATIC_OVERRIDE,
        OUTLINER_IDOP_SINGLE,
        OUTLINER_IDOP_DELETE,
        OUTLINER_IDOP_REMAP,
@@ -1162,6 +1050,8 @@ typedef enum eOutlinerIdOpTypes {
 static const EnumPropertyItem prop_id_op_types[] = {
        {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
        {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
+       {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE",
+        0, "Add Static Override", "Add a local static override of this data-block"},
        {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
        {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
        {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
@@ -1193,6 +1083,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
                case OUTLINER_IDOP_UNLINK:
                {
                        /* unlink datablock from its parent */
+                       if (objectlevel) {
+                               outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_object_cb, NULL);
+
+                               WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+                               ED_undo_push(C, "Unlink Object");
+                               break;
+                       }
+
                        switch (idlevel) {
                                case ID_AC:
                                        outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL);
@@ -1218,6 +1116,12 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
                                        WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
                                        ED_undo_push(C, "Unlink world");
                                        break;
+                               case ID_GR:
+                                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_collection_cb, NULL);
+
+                                       WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+                                       ED_undo_push(C, "Unlink Collection");
+                                       break;
                                default:
                                        BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
                                        break;
@@ -1231,6 +1135,13 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
                        ED_undo_push(C, "Localized Data");
                        break;
                }
+               case OUTLINER_IDOP_STATIC_OVERRIDE:
+               {
+                       /* make local */
+                       outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL);
+                       ED_undo_push(C, "Overrided Data");
+                       break;
+               }
                case OUTLINER_IDOP_SINGLE:
                {
                        /* make single user */
@@ -1630,7 +1541,7 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
        /* update dependencies */
        if (updateDeps) {
                /* rebuild depsgraph for the new deps */
-               DAG_relations_tag_update(CTX_data_main(C));
+               DEG_relations_tag_update(CTX_data_main(C));
        }
 
        return OPERATOR_FINISHED;
@@ -1864,9 +1775,10 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
                                outliner_set_flag(&soops->tree, TSE_SELECTED, 0);
 
                        tselem->flag |= TSE_SELECTED;
-                       /* redraw, same as outliner_select function */
-                       soops->storeflag |= SO_TREESTORE_REDRAW;
-                       ED_region_tag_redraw(ar);
+
+                       /* Only redraw, don't rebuild here because TreeElement pointers will
+                        * become invalid and operations will crash. */
+                       ED_region_tag_redraw_no_rebuild(ar);
                }
 
                set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -1880,7 +1792,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
                        }
                }
                else if (objectlevel) {
-                       WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+                       WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
                }
                else if (idlevel) {
                        if (idlevel == -1 || datalevel) {
@@ -1889,7 +1801,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
                        else {
                                switch (idlevel) {
                                        case ID_GR:
-                                               WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+                                               WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
                                                break;
                                        case ID_LI:
                                                WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL);
@@ -1910,8 +1822,11 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
                                else if (datalevel == TSE_DRIVER_BASE) {
                                        /* do nothing... no special ops needed yet */
                                }
-                               else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
-                                       /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
+                               else if (datalevel == TSE_LAYER_COLLECTION) {
+                                       WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
+                               }
+                               else if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
+                                       WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
                                }
                                else if (datalevel == TSE_ID_BASE) {
                                        /* do nothing... there are no ops needed here yet */
@@ -1946,6 +1861,7 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
        uiBut *but = UI_context_active_but_get(C);
        TreeElement *te;
        float fmval[2];
+       bool found = false;
 
        if (but) {
                UI_but_tooltip_timer_remove(C, but);
@@ -1955,10 +1871,18 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
 
        for (te = soops->tree.first; te; te = te->next) {
                if (do_outliner_operation_event(C, ar, soops, te, fmval)) {
+                       found = true;
                        break;
                }
        }
 
+       if (!found) {
+               /* Menus for clicking in empty space. */
+               if (soops->outlinevis == SO_VIEW_LAYER) {
+                       WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
+               }
+       }
+
        return OPERATOR_FINISHED;
 }