Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_outliner / outliner_tools.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2004 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_outliner/outliner_tools.c
29  *  \ingroup spoutliner
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_anim_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_group_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_linestyle_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_mesh_types.h"
42 #include "DNA_meta_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_sequence_types.h"
45 #include "DNA_world_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_constraint_types.h"
48 #include "DNA_modifier_types.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_utildefines.h"
52
53 #include "BKE_animsys.h"
54 #include "BKE_context.h"
55 #include "BKE_constraint.h"
56 #include "BKE_fcurve.h"
57 #include "BKE_group.h"
58 #include "BKE_layer.h"
59 #include "BKE_library.h"
60 #include "BKE_library_override.h"
61 #include "BKE_library_query.h"
62 #include "BKE_library_remap.h"
63 #include "BKE_main.h"
64 #include "BKE_report.h"
65 #include "BKE_scene.h"
66 #include "BKE_sequencer.h"
67
68 #include "DEG_depsgraph.h"
69 #include "DEG_depsgraph_build.h"
70
71 #include "ED_armature.h"
72 #include "ED_object.h"
73 #include "ED_scene.h"
74 #include "ED_screen.h"
75 #include "ED_sequencer.h"
76 #include "ED_undo.h"
77
78 #include "WM_api.h"
79 #include "WM_types.h"
80
81 #include "UI_interface.h"
82 #include "UI_view2d.h"
83 #include "UI_resources.h"
84
85 #include "RNA_access.h"
86 #include "RNA_define.h"
87 #include "RNA_enum_types.h"
88
89 #include "outliner_intern.h"
90
91
92 /* ****************************************************** */
93
94 /* ************ SELECTION OPERATIONS ********* */
95
96 static void set_operation_types(SpaceOops *soops, ListBase *lb,
97                                 int *scenelevel,
98                                 int *objectlevel,
99                                 int *idlevel,
100                                 int *datalevel)
101 {
102         TreeElement *te;
103         TreeStoreElem *tselem;
104         
105         for (te = lb->first; te; te = te->next) {
106                 tselem = TREESTORE(te);
107                 if (tselem->flag & TSE_SELECTED) {
108                         if (tselem->type) {
109                                 if (*datalevel == 0)
110                                         *datalevel = tselem->type;
111                                 else if (*datalevel != tselem->type)
112                                         *datalevel = -1;
113                         }
114                         else {
115                                 int idcode = GS(tselem->id->name);
116                                 switch (idcode) {
117                                         case ID_SCE:
118                                                 *scenelevel = 1;
119                                                 break;
120                                         case ID_OB:
121                                                 *objectlevel = 1;
122                                                 break;
123                                                 
124                                         case ID_ME: case ID_CU: case ID_MB: case ID_LT:
125                                         case ID_LA: case ID_AR: case ID_CA: case ID_SPK:
126                                         case ID_MA: case ID_TE: case ID_IP: case ID_IM:
127                                         case ID_SO: case ID_KE: case ID_WO: case ID_AC:
128                                         case ID_NLA: case ID_TXT: case ID_GR: case ID_LS:
129                                         case ID_LI:
130                                                 if (*idlevel == 0) *idlevel = idcode;
131                                                 else if (*idlevel != idcode) *idlevel = -1;
132                                                 break;
133                                 }
134                         }
135                 }
136                 if (TSELEM_OPEN(tselem, soops)) {
137                         set_operation_types(soops, &te->subtree,
138                                             scenelevel, objectlevel, idlevel, datalevel);
139                 }
140         }
141 }
142
143 static void unlink_action_cb(
144         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
145         TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
146 {
147         /* just set action to NULL */
148         BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
149 }
150
151 static void unlink_material_cb(
152         bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
153         TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
154 {
155         Material **matar = NULL;
156         int a, totcol = 0;
157         
158         if (GS(tsep->id->name) == ID_OB) {
159                 Object *ob = (Object *)tsep->id;
160                 totcol = ob->totcol;
161                 matar = ob->mat;
162         }
163         else if (GS(tsep->id->name) == ID_ME) {
164                 Mesh *me = (Mesh *)tsep->id;
165                 totcol = me->totcol;
166                 matar = me->mat;
167         }
168         else if (GS(tsep->id->name) == ID_CU) {
169                 Curve *cu = (Curve *)tsep->id;
170                 totcol = cu->totcol;
171                 matar = cu->mat;
172         }
173         else if (GS(tsep->id->name) == ID_MB) {
174                 MetaBall *mb = (MetaBall *)tsep->id;
175                 totcol = mb->totcol;
176                 matar = mb->mat;
177         }
178         else {
179                 BLI_assert(0);
180         }
181
182         if (LIKELY(matar != NULL)) {
183                 for (a = 0; a < totcol; a++) {
184                         if (a == te->index && matar[a]) {
185                                 id_us_min(&matar[a]->id);
186                                 matar[a] = NULL;
187                         }
188                 }
189         }
190 }
191
192 static void unlink_texture_cb(
193         bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
194         TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
195 {
196         MTex **mtex = NULL;
197         int a;
198         
199         if (GS(tsep->id->name) == ID_LS) {
200                 FreestyleLineStyle *ls = (FreestyleLineStyle *)tsep->id;
201                 mtex = ls->mtex;
202         }
203         else {
204                 return;
205         }
206
207         for (a = 0; a < MAX_MTEX; a++) {
208                 if (a == te->index && mtex[a]) {
209                         if (mtex[a]->tex) {
210                                 id_us_min(&mtex[a]->tex->id);
211                                 mtex[a]->tex = NULL;
212                         }
213                 }
214         }
215 }
216
217 static void unlink_group_cb(
218         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
219         TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
220 {
221         Group *group = (Group *)tselem->id;
222         
223         if (tsep) {
224                 if (GS(tsep->id->name) == ID_OB) {
225                         Object *ob = (Object *)tsep->id;
226                         ob->dup_group = NULL;
227                 }
228         }
229         else {
230                 Main *bmain = CTX_data_main(C);
231                 BKE_libblock_delete(bmain, group);
232         }
233 }
234
235 static void unlink_world_cb(
236         bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
237         TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
238 {
239         Scene *parscene = (Scene *)tsep->id;
240         World *wo = (World *)tselem->id;
241         
242         /* need to use parent scene not just scene, otherwise may end up getting wrong one */
243         id_us_min(&wo->id);
244         parscene->world = NULL;
245 }
246
247 static void outliner_do_libdata_operation(
248         bContext *C, ReportList *reports, Scene *scene, SpaceOops *soops, ListBase *lb,
249         outliner_operation_cb operation_cb,
250         void *user_data)
251 {
252         TreeElement *te;
253         TreeStoreElem *tselem;
254         
255         for (te = lb->first; te; te = te->next) {
256                 tselem = TREESTORE(te);
257                 if (tselem->flag & TSE_SELECTED) {
258                         if (tselem->type == 0) {
259                                 TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
260                                 operation_cb(C, reports, scene, te, tsep, tselem, user_data);
261                         }
262                 }
263                 if (TSELEM_OPEN(tselem, soops)) {
264                         outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data);
265                 }
266         }
267 }
268
269 /* ******************************************** */
270 typedef enum eOutliner_PropSceneOps {
271         OL_SCENE_OP_DELETE = 1
272 } eOutliner_PropSceneOps;
273
274 static const EnumPropertyItem prop_scene_op_types[] = {
275         {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
276         {0, NULL, 0, NULL, NULL}
277 };
278
279 static bool outliner_do_scene_operation(
280         bContext *C, eOutliner_PropSceneOps event, ListBase *lb,
281         bool (*operation_cb)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
282 {
283         TreeElement *te;
284         TreeStoreElem *tselem;
285         bool success = false;
286
287         for (te = lb->first; te; te = te->next) {
288                 tselem = TREESTORE(te);
289                 if (tselem->flag & TSE_SELECTED) {
290                         if (operation_cb(C, event, te, tselem)) {
291                                 success = true;
292                         }
293                 }
294         }
295
296         return success;
297 }
298
299 static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNUSED(te), TreeStoreElem *tselem)
300 {
301         Scene *scene = (Scene *)tselem->id;
302
303         if (event == OL_SCENE_OP_DELETE) {
304                 if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene)) {
305                         WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
306                 }
307                 else {
308                         return false;
309                 }
310         }
311
312         return true;
313 }
314
315 static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
316 {
317         SpaceOops *soops = CTX_wm_space_outliner(C);
318         const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type");
319
320         if (outliner_do_scene_operation(C, event, &soops->tree, scene_cb) == false) {
321                 return OPERATOR_CANCELLED;
322         }
323
324         if (event == OL_SCENE_OP_DELETE) {
325                 outliner_cleanup_tree(soops);
326                 ED_undo_push(C, "Delete Scene(s)");
327         }
328         else {
329                 BLI_assert(0);
330                 return OPERATOR_CANCELLED;
331         }
332
333         return OPERATOR_FINISHED;
334 }
335
336 void OUTLINER_OT_scene_operation(wmOperatorType *ot)
337 {
338         /* identifiers */
339         ot->name = "Outliner Scene Operation";
340         ot->idname = "OUTLINER_OT_scene_operation";
341         ot->description = "Context menu for scene operations";
342
343         /* callbacks */
344         ot->invoke = WM_menu_invoke;
345         ot->exec = outliner_scene_operation_exec;
346         ot->poll = ED_operator_outliner_active;
347
348         ot->flag = 0;
349
350         ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
351 }
352 /* ******************************************** */
353
354 static void object_select_cb(
355         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
356         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
357 {
358         ViewLayer *view_layer = CTX_data_view_layer(C);
359         Object *ob = (Object *)tselem->id;
360         Base *base = BKE_view_layer_base_find(view_layer, ob);
361
362         if (base && ((base->flag & BASE_VISIBLED) != 0)) {
363                 base->flag |= BASE_SELECTED;
364         }
365 }
366
367 static void object_select_hierarchy_cb(
368         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
369         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
370 {
371         /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item.
372          * it's especially confusing when multiple items are selected since some toggle on/off. */
373         outliner_item_do_activate_from_tree_element(C, te, tselem, false, true);
374 }
375
376 static void object_deselect_cb(
377         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
378         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
379 {
380         ViewLayer *view_layer = CTX_data_view_layer(C);
381         Object *ob = (Object *)tselem->id;
382         Base *base = BKE_view_layer_base_find(view_layer, ob);
383
384         if (base) {
385                 base->flag &= ~BASE_SELECTED;
386         }
387 }
388
389 static void object_delete_cb(
390         bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
391         TreeStoreElem *tsep, TreeStoreElem *tselem, void *user_data)
392 {
393         Object *ob = (Object *)tselem->id;
394         if (ob) {
395                 Main *bmain = CTX_data_main(C);
396                 if (ob->id.tag & LIB_TAG_INDIRECT) {
397                         BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
398                         return;
399                 }
400                 else if (BKE_library_ID_is_indirectly_used(bmain, ob) &&
401                          ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0)
402                 {
403                         BKE_reportf(reports, RPT_WARNING,
404                                     "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
405                                     ob->id.name + 2, scene->id.name + 2);
406                         return;
407                 }
408
409                 // check also library later
410                 if (ob == CTX_data_edit_object(C)) {
411                         ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
412                 }
413                 ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob);
414                 /* leave for ED_outliner_id_unref to handle */
415 #if 0
416                 te->directdata = NULL;
417                 tselem->id = NULL;
418 #endif
419         }
420         else {
421                 /* No base, means object is no more instantiated in any scene.
422                  * Should not happen ideally, but does happens, see T51625.
423                  * Rather than twisting in all kind of ways to address all possible cases leading to that situation, simpler
424                  * to allow deleting such object as a mere generic data-block. */
425                 id_delete_cb(C, reports, scene, te, tsep, tselem, user_data);
426         }
427 }
428
429 static void id_local_cb(
430         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
431         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
432 {
433         if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
434                 Main *bmain = CTX_data_main(C);
435                 /* if the ID type has no special local function,
436                  * just clear the lib */
437                 if (id_make_local(bmain, tselem->id, false, false) == false) {
438                         id_clear_lib_data(bmain, tselem->id);
439                 }
440                 else {
441                         BKE_main_id_clear_newpoins(bmain);
442                 }
443         }
444 }
445
446 static void id_static_override_cb(
447         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
448         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
449 {
450         if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
451                 Main *bmain = CTX_data_main(C);
452                 ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id);
453                 if (override_id != NULL) {
454                         BKE_main_id_clear_newpoins(bmain);
455                 }
456         }
457 }
458
459 static void id_fake_user_set_cb(
460         bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
461         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
462 {
463         ID *id = tselem->id;
464         
465         id_fake_user_set(id);
466 }
467
468 static void id_fake_user_clear_cb(
469         bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
470         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
471 {
472         ID *id = tselem->id;
473         
474         id_fake_user_clear(id);
475 }
476
477 static void id_select_linked_cb(
478         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
479         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
480 {
481         ID *id = tselem->id;
482
483         ED_object_select_linked_by_id(C, id);
484 }
485
486 static void singleuser_action_cb(
487         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
488         TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
489 {
490         ID *id = tselem->id;
491         
492         if (id) {
493                 IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
494                 PointerRNA ptr = {{NULL}};
495                 PropertyRNA *prop;
496                 
497                 RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr);
498                 prop = RNA_struct_find_property(&ptr, "action");
499                 
500                 id_single_user(C, id, &ptr, prop);
501         }
502 }
503
504 static void singleuser_world_cb(
505         bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
506         TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
507 {
508         ID *id = tselem->id;
509         
510         /* need to use parent scene not just scene, otherwise may end up getting wrong one */
511         if (id) {
512                 Scene *parscene = (Scene *)tsep->id;
513                 PointerRNA ptr = {{NULL}};
514                 PropertyRNA *prop;
515                 
516                 RNA_id_pointer_create(&parscene->id, &ptr);
517                 prop = RNA_struct_find_property(&ptr, "world");
518                 
519                 id_single_user(C, id, &ptr, prop);
520         }
521 }
522
523 static void group_linkobs2scene_cb(
524         bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
525         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
526 {
527         ViewLayer *view_layer = CTX_data_view_layer(C);
528         SceneCollection *sc = CTX_data_scene_collection(C);
529         Group *group = (Group *)tselem->id;
530         Base *base;
531
532         FOREACH_GROUP_OBJECT_BEGIN(group, object)
533         {
534                 base = BKE_view_layer_base_find(view_layer, object);
535                 if (!base) {
536                         /* link to scene */
537                         BKE_collection_object_add(&scene->id, sc, object);
538                         base = BKE_view_layer_base_find(view_layer, object);
539                         id_us_plus(&object->id);
540                 }
541
542                 base->flag |= BASE_SELECTED;
543         }
544         FOREACH_GROUP_OBJECT_END;
545 }
546
547 static void group_instance_cb(
548         bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
549         TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
550 {
551         Group *group = (Group *)tselem->id;
552
553         Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor, NULL, false, scene->layact);
554         ob->dup_group = group;
555         ob->transflag |= OB_DUPLIGROUP;
556         id_lib_extern(&group->id);
557 }
558
559 /**
560  * \param select_recurse: Set to false for operations which are already recursively operating on their children.
561  */
562 void outliner_do_object_operation_ex(
563         bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
564         outliner_operation_cb operation_cb, bool select_recurse)
565 {
566         TreeElement *te;
567         
568         for (te = lb->first; te; te = te->next) {
569                 TreeStoreElem *tselem = TREESTORE(te);
570                 bool select_handled = false;
571                 if (tselem->flag & TSE_SELECTED) {
572                         if (tselem->type == 0 && te->idcode == ID_OB) {
573                                 // when objects selected in other scenes... dunno if that should be allowed
574                                 Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE);
575                                 if (scene_owner && scene_act != scene_owner) {
576                                         WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner);
577                                 }
578                                 /* important to use 'scene_owner' not scene_act else deleting objects can crash.
579                                  * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
580                                  * outliner isn't showing scenes: Visible Layer draw mode for eg. */
581                                 operation_cb(C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
582                                 select_handled = true;
583                         }
584                 }
585                 if (TSELEM_OPEN(tselem, soops)) {
586                         if ((select_handled == false) || select_recurse) {
587                                 outliner_do_object_operation_ex(
588                                             C, reports, scene_act, soops, &te->subtree, operation_cb, select_recurse);
589                         }
590                 }
591         }
592 }
593
594 void outliner_do_object_operation(
595         bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
596         outliner_operation_cb operation_cb)
597 {
598         outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, true);
599 }
600
601 /* ******************************************** */
602
603 static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
604                               TreeStoreElem *tselem, void *UNUSED(arg))
605 {
606         BKE_animdata_free(tselem->id, true);
607 }
608
609
610 static void unlinkact_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
611                                   TreeStoreElem *tselem, void *UNUSED(arg))
612 {
613         /* just set action to NULL */
614         BKE_animdata_set_action(NULL, tselem->id, NULL);
615 }
616
617 static void cleardrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
618                                      TreeStoreElem *tselem, void *UNUSED(arg))
619 {
620         IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
621         
622         /* just free drivers - stored as a list of F-Curves */
623         free_fcurves(&iat->adt->drivers);
624 }
625
626 static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
627                                        TreeStoreElem *tselem, void *UNUSED(arg))
628 {
629         IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
630         FCurve *fcu;
631         
632         /* loop over drivers, performing refresh (i.e. check graph_buttons.c and rna_fcurve.c for details) */
633         for (fcu = iat->adt->drivers.first; fcu; fcu = fcu->next) {
634                 fcu->flag &= ~FCURVE_DISABLED;
635                 
636                 if (fcu->driver)
637                         fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
638         }
639 }
640
641 /* --------------------------------- */
642
643 typedef enum eOutliner_PropDataOps {
644         OL_DOP_SELECT = 1,
645         OL_DOP_DESELECT,
646         OL_DOP_HIDE,
647         OL_DOP_UNHIDE,
648         OL_DOP_SELECT_LINKED,
649 } eOutliner_PropDataOps;
650
651 typedef enum eOutliner_PropConstraintOps {
652         OL_CONSTRAINTOP_ENABLE = 1,
653         OL_CONSTRAINTOP_DISABLE,
654         OL_CONSTRAINTOP_DELETE
655 } eOutliner_PropConstraintOps;
656
657 typedef enum eOutliner_PropModifierOps {
658         OL_MODIFIER_OP_TOGVIS = 1,
659         OL_MODIFIER_OP_TOGREN,
660         OL_MODIFIER_OP_DELETE
661 } eOutliner_PropModifierOps;
662
663 typedef enum eOutliner_PropCollectionOps {
664         OL_COLLECTION_OP_OBJECTS_ADD = 1,
665         OL_COLLECTION_OP_OBJECTS_REMOVE,
666         OL_COLLECTION_OP_OBJECTS_SELECT,
667         OL_COLLECTION_OP_COLLECTION_NEW,
668         OL_COLLECTION_OP_COLLECTION_COPY,
669         OL_COLLECTION_OP_COLLECTION_DEL,
670         OL_COLLECTION_OP_COLLECTION_UNLINK,
671         OL_COLLECTION_OP_GROUP_CREATE,
672 } eOutliner_PropCollectionOps;
673
674 static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
675 {
676         bPoseChannel *pchan = (bPoseChannel *)te->directdata;
677         
678         if (event == OL_DOP_SELECT)
679                 pchan->bone->flag |= BONE_SELECTED;
680         else if (event == OL_DOP_DESELECT)
681                 pchan->bone->flag &= ~BONE_SELECTED;
682         else if (event == OL_DOP_HIDE) {
683                 pchan->bone->flag |= BONE_HIDDEN_P;
684                 pchan->bone->flag &= ~BONE_SELECTED;
685         }
686         else if (event == OL_DOP_UNHIDE)
687                 pchan->bone->flag &= ~BONE_HIDDEN_P;
688 }
689
690 static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
691 {
692         Bone *bone = (Bone *)te->directdata;
693         
694         if (event == OL_DOP_SELECT)
695                 bone->flag |= BONE_SELECTED;
696         else if (event == OL_DOP_DESELECT)
697                 bone->flag &= ~BONE_SELECTED;
698         else if (event == OL_DOP_HIDE) {
699                 bone->flag |= BONE_HIDDEN_P;
700                 bone->flag &= ~BONE_SELECTED;
701         }
702         else if (event == OL_DOP_UNHIDE)
703                 bone->flag &= ~BONE_HIDDEN_P;
704 }
705
706 static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
707 {
708         EditBone *ebone = (EditBone *)te->directdata;
709         
710         if (event == OL_DOP_SELECT)
711                 ebone->flag |= BONE_SELECTED;
712         else if (event == OL_DOP_DESELECT)
713                 ebone->flag &= ~BONE_SELECTED;
714         else if (event == OL_DOP_HIDE) {
715                 ebone->flag |= BONE_HIDDEN_A;
716                 ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
717         }
718         else if (event == OL_DOP_UNHIDE)
719                 ebone->flag &= ~BONE_HIDDEN_A;
720 }
721
722 static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void *scene_ptr)
723 {
724         Sequence *seq = (Sequence *)te->directdata;
725         if (event == OL_DOP_SELECT) {
726                 Scene *scene = (Scene *)scene_ptr;
727                 Editing *ed = BKE_sequencer_editing_get(scene, false);
728                 if (BLI_findindex(ed->seqbasep, seq) != -1) {
729                         ED_sequencer_select_sequence_single(scene, seq, true);
730                 }
731         }
732
733         (void)tselem;
734 }
735
736 static void gp_layer_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
737 {
738         bGPDlayer *gpl = (bGPDlayer *)te->directdata;
739         
740         if (event == OL_DOP_SELECT)
741                 gpl->flag |= GP_LAYER_SELECT;
742         else if (event == OL_DOP_DESELECT)
743                 gpl->flag &= ~GP_LAYER_SELECT;
744         else if (event == OL_DOP_HIDE)
745                 gpl->flag |= GP_LAYER_HIDE;
746         else if (event == OL_DOP_UNHIDE)
747                 gpl->flag &= ~GP_LAYER_HIDE;
748 }
749
750 static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
751 {
752         if (event == OL_DOP_SELECT_LINKED) {
753                 if (RNA_struct_is_ID(te->rnaptr.type)) {
754                         bContext *C = (bContext *) C_v;
755                         ID *id = te->rnaptr.data;
756
757                         ED_object_select_linked_by_id(C, id);
758                 }
759         }
760 }
761
762 static void constraint_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
763 {
764         bContext *C = C_v;
765         SpaceOops *soops = CTX_wm_space_outliner(C);
766         bConstraint *constraint = (bConstraint *)te->directdata;
767         Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
768
769         if (event == OL_CONSTRAINTOP_ENABLE) {
770                 constraint->flag &= ~CONSTRAINT_OFF;
771                 ED_object_constraint_update(ob);
772                 WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
773         }
774         else if (event == OL_CONSTRAINTOP_DISABLE) {
775                 constraint->flag = CONSTRAINT_OFF;
776                 ED_object_constraint_update(ob);
777                 WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
778         }
779         else if (event == OL_CONSTRAINTOP_DELETE) {
780                 ListBase *lb = NULL;
781
782                 if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
783                         lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
784                 }
785                 else {
786                         lb = &ob->constraints;
787                 }
788
789                 if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
790                         /* there's no active constraint now, so make sure this is the case */
791                         BKE_constraints_active_set(&ob->constraints, NULL);
792                         ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
793                         WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
794                         te->store_elem->flag &= ~TSE_SELECTED;
795                 }
796         }
797 }
798
799 static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg)
800 {
801         bContext *C = (bContext *)Carg;
802         Main *bmain = CTX_data_main(C);
803         SpaceOops *soops = CTX_wm_space_outliner(C);
804         ModifierData *md = (ModifierData *)te->directdata;
805         Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
806
807         if (event == OL_MODIFIER_OP_TOGVIS) {
808                 md->mode ^= eModifierMode_Realtime;
809                 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
810                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
811         }
812         else if (event == OL_MODIFIER_OP_TOGREN) {
813                 md->mode ^= eModifierMode_Render;
814                 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
815                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
816         }
817         else if (event == OL_MODIFIER_OP_DELETE) {
818                 ED_object_modifier_remove(NULL, bmain, ob, md);
819                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob);
820                 te->store_elem->flag &= ~TSE_SELECTED;
821         }
822 }
823
824 static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg)
825 {
826         bContext *C = (bContext *)Carg;
827         Scene *scene = CTX_data_scene(C);
828         LayerCollection *lc = te->directdata;
829         ID *id = te->store_elem->id;
830         SceneCollection *sc = lc->scene_collection;
831
832         if (event == OL_COLLECTION_OP_OBJECTS_ADD) {
833                 CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
834                 {
835                         BKE_collection_object_add(id, sc, ob);
836                 }
837                 CTX_DATA_END;
838
839                 WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
840         }
841         else if (event == OL_COLLECTION_OP_OBJECTS_REMOVE) {
842                 Main *bmain = CTX_data_main(C);
843
844                 CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
845                 {
846                         BKE_collection_object_remove(bmain, id, sc, ob, true);
847                 }
848                 CTX_DATA_END;
849
850                 WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
851                 te->store_elem->flag &= ~TSE_SELECTED;
852         }
853         else if (event == OL_COLLECTION_OP_OBJECTS_SELECT) {
854                 BKE_layer_collection_objects_select(lc);
855                 WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
856         }
857         else if (event == OL_COLLECTION_OP_COLLECTION_NEW) {
858                 if (GS(id->name) == ID_GR) {
859                         BKE_collection_add(id, sc, COLLECTION_TYPE_GROUP_INTERNAL, NULL);
860                 }
861                 else {
862                         BLI_assert(GS(id->name) == ID_SCE);
863                         BKE_collection_add(id, sc, COLLECTION_TYPE_NONE, NULL);
864                 }
865                 WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
866         }
867         else if (event == OL_COLLECTION_OP_COLLECTION_COPY) {
868                 BKE_layer_collection_duplicate(id, lc);
869                 DEG_relations_tag_update(CTX_data_main(C));
870                 WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
871         }
872         else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) {
873                 ViewLayer *view_layer = CTX_data_view_layer(C);
874
875                 if (BLI_findindex(&view_layer->layer_collections, lc) == -1) {
876                         /* we can't unlink if the layer collection wasn't directly linked */
877                         TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */
878                 }
879                 else {
880                         BKE_collection_unlink(view_layer, lc);
881                         DEG_relations_tag_update(CTX_data_main(C));
882                         WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
883                 }
884         }
885         else if (event == OL_COLLECTION_OP_COLLECTION_DEL) {
886                 if (BKE_collection_remove(id, sc)) {
887                         DEG_relations_tag_update(CTX_data_main(C));
888                         WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
889                 }
890                 else {
891                         /* we can't remove the master collection */
892                         TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */
893                 }
894         }
895         else if (event == OL_COLLECTION_OP_GROUP_CREATE) {
896                 Main *bmain = CTX_data_main(C);
897                 BKE_collection_group_create(bmain, scene, lc);
898                 DEG_relations_tag_update(bmain);
899                 /* TODO(sergey): Use proper flag for tagging here. */
900                 DEG_id_tag_update(&scene->id, 0);
901                 WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
902         }
903         else {
904                 BLI_assert(!"Collection operation not fully implemented!");
905         }
906 }
907
908 static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb,
909                                        void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *),
910                                        void *arg)
911 {
912         TreeElement *te;
913         TreeStoreElem *tselem;
914         
915         for (te = lb->first; te; te = te->next) {
916                 tselem = TREESTORE(te);
917                 if (tselem->flag & TSE_SELECTED) {
918                         if (tselem->type == type) {
919                                 operation_cb(event, te, tselem, arg);
920                         }
921                 }
922                 if (TSELEM_OPEN(tselem, soops)) {
923                         outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb, arg);
924                 }
925         }
926 }
927
928 static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base)
929 {
930         Base *child_base, *base_next;
931         Object *parent;
932         ViewLayer *view_layer = CTX_data_view_layer(C);
933
934         if (!base) {
935                 return NULL;
936         }
937
938         for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) {
939                 base_next = child_base->next;
940                 for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
941                 if (parent) {
942                         base_next = outline_delete_hierarchy(C, reports, scene, child_base);
943                 }
944         }
945
946         base_next = base->next;
947
948         Main *bmain = CTX_data_main(C);
949         if (base->object->id.tag & LIB_TAG_INDIRECT) {
950                 BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
951                 return base_next;
952         }
953         else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
954                  ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
955         {
956                 BKE_reportf(reports, RPT_WARNING,
957                             "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
958                             base->object->id.name + 2, scene->id.name + 2);
959                 return base_next;
960         }
961         ED_object_base_free_and_unlink(CTX_data_main(C), scene, base->object);
962         return base_next;
963 }
964
965 static void object_delete_hierarchy_cb(
966         bContext *C, ReportList *reports, Scene *scene,
967         TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
968 {
969         ViewLayer *view_layer = CTX_data_view_layer(C);
970         Base *base = (Base *)te->directdata;
971         Object *obedit = CTX_data_edit_object(C);
972
973         if (!base) {
974                 base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id);
975         }
976         if (base) {
977                 /* Check also library later. */
978                 for (; obedit && (obedit != base->object); obedit = obedit->parent);
979                 if (obedit == base->object) {
980                         ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
981                 }
982
983                 outline_delete_hierarchy(C, reports, scene, base);
984                 /* leave for ED_outliner_id_unref to handle */
985 #if 0
986                 te->directdata = NULL;
987                 tselem->id = NULL;
988 #endif
989         }
990
991         WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
992 }
993
994 /* **************************************** */
995
996 enum {
997         OL_OP_SELECT = 1,
998         OL_OP_DESELECT,
999         OL_OP_SELECT_HIERARCHY,
1000         OL_OP_DELETE,
1001         OL_OP_DELETE_HIERARCHY,
1002         OL_OP_REMAP,
1003         OL_OP_LOCALIZED,  /* disabled, see below */
1004         OL_OP_TOGVIS,
1005         OL_OP_TOGSEL,
1006         OL_OP_TOGREN,
1007         OL_OP_RENAME,
1008 };
1009
1010 static const EnumPropertyItem prop_object_op_types[] = {
1011         {OL_OP_SELECT, "SELECT", 0, "Select", ""},
1012         {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
1013         {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
1014         {OL_OP_DELETE, "DELETE", 0, "Delete", ""},
1015         {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
1016         {OL_OP_REMAP, "REMAP",   0, "Remap Users",
1017          "Make all users of selected data-blocks to use instead a new chosen one"},
1018         {OL_OP_RENAME, "RENAME", 0, "Rename", ""},
1019         {0, NULL, 0, NULL, NULL}
1020 };
1021
1022 static int outliner_object_operation_exec(bContext *C, wmOperator *op)
1023 {
1024         Main *bmain = CTX_data_main(C);
1025         Scene *scene = CTX_data_scene(C);
1026         wmWindow *win = CTX_wm_window(C);
1027         SpaceOops *soops = CTX_wm_space_outliner(C);
1028         int event;
1029         const char *str = NULL;
1030         
1031         /* check for invalid states */
1032         if (soops == NULL)
1033                 return OPERATOR_CANCELLED;
1034         
1035         event = RNA_enum_get(op->ptr, "type");
1036
1037         if (event == OL_OP_SELECT) {
1038                 Scene *sce = scene;  // to be able to delete, scenes are set...
1039                 outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb);
1040                 if (scene != sce) {
1041                         WM_window_change_active_scene(bmain, C, win, sce);
1042                 }
1043                 
1044                 str = "Select Objects";
1045                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1046         }
1047         else if (event == OL_OP_SELECT_HIERARCHY) {
1048                 Scene *sce = scene;  // to be able to delete, scenes are set...
1049                 outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
1050                 if (scene != sce) {
1051                         WM_window_change_active_scene(bmain, C, win, sce);
1052                 }
1053                 str = "Select Object Hierarchy";
1054                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1055         }
1056         else if (event == OL_OP_DESELECT) {
1057                 outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb);
1058                 str = "Deselect Objects";
1059                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1060         }
1061         else if (event == OL_OP_DELETE) {
1062                 outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb);
1063
1064                 /* XXX: tree management normally happens from draw_outliner(), but when
1065                  *      you're clicking to fast on Delete object from context menu in
1066                  *      outliner several mouse events can be handled in one cycle without
1067                  *      handling notifiers/redraw which leads to deleting the same object twice.
1068                  *      cleanup tree here to prevent such cases. */
1069                 outliner_cleanup_tree(soops);
1070
1071                 DEG_relations_tag_update(bmain);
1072                 str = "Delete Objects";
1073                 WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
1074         }
1075         else if (event == OL_OP_DELETE_HIERARCHY) {
1076                 outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
1077
1078                 /* XXX: See OL_OP_DELETE comment above. */
1079                 outliner_cleanup_tree(soops);
1080
1081                 DEG_relations_tag_update(bmain);
1082                 str = "Delete Object Hierarchy";
1083                 WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
1084         }
1085         else if (event == OL_OP_REMAP) {
1086                 outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
1087                 str = "Remap ID";
1088         }
1089         else if (event == OL_OP_LOCALIZED) {    /* disabled, see above enum (ton) */
1090                 outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
1091                 str = "Localized Objects";
1092         }
1093         else if (event == OL_OP_RENAME) {
1094                 outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb);
1095                 str = "Rename Object";
1096         }
1097         else {
1098                 BLI_assert(0);
1099                 return OPERATOR_CANCELLED;
1100         }
1101
1102         ED_undo_push(C, str);
1103         
1104         return OPERATOR_FINISHED;
1105 }
1106
1107
1108 void OUTLINER_OT_object_operation(wmOperatorType *ot)
1109 {
1110         /* identifiers */
1111         ot->name = "Outliner Object Operation";
1112         ot->idname = "OUTLINER_OT_object_operation";
1113         ot->description = "";
1114         
1115         /* callbacks */
1116         ot->invoke = WM_menu_invoke;
1117         ot->exec = outliner_object_operation_exec;
1118         ot->poll = ED_operator_outliner_active;
1119         
1120         ot->flag = 0;
1121
1122         ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
1123 }
1124
1125 /* **************************************** */
1126
1127 typedef enum eOutliner_PropGroupOps {
1128         OL_GROUPOP_UNLINK = 1,
1129         OL_GROUPOP_LOCAL,
1130         OL_GROUPOP_STATIC_OVERRIDE,
1131         OL_GROUPOP_LINK,
1132         OL_GROUPOP_DELETE,
1133         OL_GROUPOP_REMAP,
1134         OL_GROUPOP_INSTANCE,
1135         OL_GROUPOP_TOGVIS,
1136         OL_GROUPOP_TOGSEL,
1137         OL_GROUPOP_TOGREN,
1138         OL_GROUPOP_RENAME,
1139 } eOutliner_PropGroupOps;
1140
1141 static const EnumPropertyItem prop_group_op_types[] = {
1142         {OL_GROUPOP_UNLINK, "UNLINK",     0, "Unlink Group", ""},
1143         {OL_GROUPOP_LOCAL, "LOCAL",       0, "Make Local Group", ""},
1144         {OL_GROUPOP_STATIC_OVERRIDE, "STATIC_OVERRIDE",
1145          0, "Add Static Override", "Add a local static override of that group"},
1146         {OL_GROUPOP_LINK, "LINK",         0, "Link Group Objects to Scene", ""},
1147         {OL_GROUPOP_DELETE, "DELETE",     0, "Delete Group", ""},
1148         {OL_GROUPOP_REMAP, "REMAP",       0, "Remap Users",
1149          "Make all users of selected data-blocks to use instead current (clicked) one"},
1150         {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
1151         {OL_GROUPOP_TOGVIS, "TOGVIS",     0, "Toggle Visible Group", ""},
1152         {OL_GROUPOP_TOGSEL, "TOGSEL",     0, "Toggle Selectable", ""},
1153         {OL_GROUPOP_TOGREN, "TOGREN",     0, "Toggle Renderable", ""},
1154         {OL_GROUPOP_RENAME, "RENAME",     0, "Rename", ""},
1155         {0, NULL, 0, NULL, NULL}
1156 };
1157
1158 static int outliner_group_operation_exec(bContext *C, wmOperator *op)
1159 {
1160         Scene *scene = CTX_data_scene(C);
1161         SpaceOops *soops = CTX_wm_space_outliner(C);
1162         int event;
1163         
1164         /* check for invalid states */
1165         if (soops == NULL)
1166                 return OPERATOR_CANCELLED;
1167         
1168         event = RNA_enum_get(op->ptr, "type");
1169
1170         switch (event) {
1171                 case OL_GROUPOP_UNLINK:
1172                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL);
1173                         break;
1174                 case OL_GROUPOP_LOCAL:
1175                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
1176                         break;
1177                 case OL_GROUPOP_STATIC_OVERRIDE:
1178                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL);
1179                         break;
1180                 case OL_GROUPOP_LINK:
1181                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
1182                         break;
1183                 case OL_GROUPOP_INSTANCE:
1184                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL);
1185                         /* works without this except if you try render right after, see: 22027 */
1186                         DEG_relations_tag_update(CTX_data_main(C));
1187                         break;
1188                 case OL_GROUPOP_DELETE:
1189                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
1190                         break;
1191                 case OL_GROUPOP_REMAP:
1192                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
1193                         break;
1194                 case OL_GROUPOP_RENAME:
1195                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
1196                         break;
1197                 default:
1198                         BLI_assert(0);
1199         }
1200
1201         ED_undo_push(C, prop_group_op_types[event - 1].name);
1202         WM_event_add_notifier(C, NC_GROUP, NULL);
1203
1204         return OPERATOR_FINISHED;
1205 }
1206
1207
1208 void OUTLINER_OT_group_operation(wmOperatorType *ot)
1209 {
1210         /* identifiers */
1211         ot->name = "Outliner Group Operation";
1212         ot->idname = "OUTLINER_OT_group_operation";
1213         ot->description = "";
1214         
1215         /* callbacks */
1216         ot->invoke = WM_menu_invoke;
1217         ot->exec = outliner_group_operation_exec;
1218         ot->poll = ED_operator_outliner_active;
1219         
1220         ot->flag = 0;
1221         
1222         ot->prop = RNA_def_enum(ot->srna, "type", prop_group_op_types, 0, "Group Operation", "");
1223 }
1224
1225 /* **************************************** */
1226
1227 typedef enum eOutlinerIdOpTypes {
1228         OUTLINER_IDOP_INVALID = 0,
1229         
1230         OUTLINER_IDOP_UNLINK,
1231         OUTLINER_IDOP_LOCAL,
1232         OUTLINER_IDOP_STATIC_OVERRIDE,
1233         OUTLINER_IDOP_SINGLE,
1234         OUTLINER_IDOP_DELETE,
1235         OUTLINER_IDOP_REMAP,
1236         
1237         OUTLINER_IDOP_FAKE_ADD,
1238         OUTLINER_IDOP_FAKE_CLEAR,
1239         OUTLINER_IDOP_RENAME,
1240
1241         OUTLINER_IDOP_SELECT_LINKED
1242 } eOutlinerIdOpTypes;
1243
1244 // TODO: implement support for changing the ID-block used
1245 static const EnumPropertyItem prop_id_op_types[] = {
1246         {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
1247         {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
1248         {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE",
1249          0, "Add Static Override", "Add a local static override of this data-block"},
1250         {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
1251         {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
1252         {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
1253          "Make all users of selected data-blocks to use instead current (clicked) one"},
1254         {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User",
1255          "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material libraries)"},
1256         {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
1257         {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
1258         {OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
1259         {0, NULL, 0, NULL, NULL}
1260 };
1261
1262 static int outliner_id_operation_exec(bContext *C, wmOperator *op)
1263 {
1264         Scene *scene = CTX_data_scene(C);
1265         SpaceOops *soops = CTX_wm_space_outliner(C);
1266         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1267         eOutlinerIdOpTypes event;
1268         
1269         /* check for invalid states */
1270         if (soops == NULL)
1271                 return OPERATOR_CANCELLED;
1272         
1273         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1274         
1275         event = RNA_enum_get(op->ptr, "type");
1276         
1277         switch (event) {
1278                 case OUTLINER_IDOP_UNLINK:
1279                 {
1280                         /* unlink datablock from its parent */
1281                         switch (idlevel) {
1282                                 case ID_AC:
1283                                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL);
1284                                         
1285                                         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
1286                                         ED_undo_push(C, "Unlink action");
1287                                         break;
1288                                 case ID_MA:
1289                                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL);
1290                                         
1291                                         WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
1292                                         ED_undo_push(C, "Unlink material");
1293                                         break;
1294                                 case ID_TE:
1295                                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL);
1296                                         
1297                                         WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
1298                                         ED_undo_push(C, "Unlink texture");
1299                                         break;
1300                                 case ID_WO:
1301                                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL);
1302                                         
1303                                         WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
1304                                         ED_undo_push(C, "Unlink world");
1305                                         break;
1306                                 default:
1307                                         BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
1308                                         break;
1309                         }
1310                         break;
1311                 }
1312                 case OUTLINER_IDOP_LOCAL:
1313                 {
1314                         /* make local */
1315                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
1316                         ED_undo_push(C, "Localized Data");
1317                         break;
1318                 }
1319                 case OUTLINER_IDOP_STATIC_OVERRIDE:
1320                 {
1321                         /* make local */
1322                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL);
1323                         ED_undo_push(C, "Overrided Data");
1324                         break;
1325                 }
1326                 case OUTLINER_IDOP_SINGLE:
1327                 {
1328                         /* make single user */
1329                         switch (idlevel) {
1330                                 case ID_AC:
1331                                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL);
1332                                         
1333                                         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
1334                                         ED_undo_push(C, "Single-User Action");
1335                                         break;
1336                                         
1337                                 case ID_WO:
1338                                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL);
1339                                         
1340                                         WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
1341                                         ED_undo_push(C, "Single-User World");
1342                                         break;
1343                                         
1344                                 default:
1345                                         BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
1346                                         break;
1347                         }
1348                         break;
1349                 }
1350                 case OUTLINER_IDOP_DELETE:
1351                 {
1352                         if (idlevel > 0) {
1353                                 outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
1354                                 ED_undo_push(C, "Delete");
1355                         }
1356                         break;
1357                 }
1358                 case OUTLINER_IDOP_REMAP:
1359                 {
1360                         if (idlevel > 0) {
1361                                 outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
1362                                 ED_undo_push(C, "Remap");
1363                         }
1364                         break;
1365                 }
1366                 case OUTLINER_IDOP_FAKE_ADD:
1367                 {
1368                         /* set fake user */
1369                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
1370                         
1371                         WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
1372                         ED_undo_push(C, "Add Fake User");
1373                         break;
1374                 }
1375                 case OUTLINER_IDOP_FAKE_CLEAR:
1376                 {
1377                         /* clear fake user */
1378                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
1379                         
1380                         WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
1381                         ED_undo_push(C, "Clear Fake User");
1382                         break;
1383                 }
1384                 case OUTLINER_IDOP_RENAME:
1385                 {
1386                         /* rename */
1387                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
1388                         
1389                         WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
1390                         ED_undo_push(C, "Rename");
1391                         break;
1392                 }
1393                 case OUTLINER_IDOP_SELECT_LINKED:
1394                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL);
1395                         ED_undo_push(C, "Select");
1396                         break;
1397                         
1398                 default:
1399                         // invalid - unhandled
1400                         break;
1401         }
1402         
1403         /* wrong notifier still... */
1404         WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
1405         
1406         // XXX: this is just so that outliner is always up to date 
1407         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
1408         
1409         return OPERATOR_FINISHED;
1410 }
1411
1412
1413 void OUTLINER_OT_id_operation(wmOperatorType *ot)
1414 {
1415         /* identifiers */
1416         ot->name = "Outliner ID data Operation";
1417         ot->idname = "OUTLINER_OT_id_operation";
1418         ot->description = "";
1419         
1420         /* callbacks */
1421         ot->invoke = WM_menu_invoke;
1422         ot->exec = outliner_id_operation_exec;
1423         ot->poll = ED_operator_outliner_active;
1424         
1425         ot->flag = 0;
1426         
1427         ot->prop = RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID data Operation", "");
1428 }
1429
1430 /* **************************************** */
1431
1432 typedef enum eOutlinerLibOpTypes {
1433         OL_LIB_INVALID = 0,
1434
1435         OL_LIB_RENAME,
1436         OL_LIB_DELETE,
1437         OL_LIB_RELOCATE,
1438         OL_LIB_RELOAD,
1439 } eOutlinerLibOpTypes;
1440
1441 static const EnumPropertyItem outliner_lib_op_type_items[] = {
1442         {OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
1443         {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"},
1444         {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"},
1445         {OL_LIB_RELOAD, "RELOAD", 0, "Reload", "Reload all data from this library"},
1446         {0, NULL, 0, NULL, NULL}
1447 };
1448
1449 static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
1450 {
1451         Scene *scene = CTX_data_scene(C);
1452         SpaceOops *soops = CTX_wm_space_outliner(C);
1453         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1454         eOutlinerLibOpTypes event;
1455
1456         /* check for invalid states */
1457         if (soops == NULL)
1458                 return OPERATOR_CANCELLED;
1459
1460         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1461
1462         event = RNA_enum_get(op->ptr, "type");
1463
1464         switch (event) {
1465                 case OL_LIB_RENAME:
1466                 {
1467                         /* rename */
1468                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
1469
1470                         WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
1471                         ED_undo_push(C, "Rename Library");
1472                         break;
1473                 }
1474                 case OL_LIB_DELETE:
1475                 {
1476                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
1477                         ED_undo_push(C, "Delete Library");
1478                         break;
1479                 }
1480                 case OL_LIB_RELOCATE:
1481                 {
1482                         /* rename */
1483                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
1484                         ED_undo_push(C, "Relocate Library");
1485                         break;
1486                 }
1487                 case OL_LIB_RELOAD:
1488                 {
1489                         /* rename */
1490                         outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL);
1491                         break;
1492                 }
1493                 default:
1494                         /* invalid - unhandled */
1495                         break;
1496         }
1497
1498         /* wrong notifier still... */
1499         WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
1500
1501         /* XXX: this is just so that outliner is always up to date */
1502         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
1503
1504         return OPERATOR_FINISHED;
1505 }
1506
1507
1508 void OUTLINER_OT_lib_operation(wmOperatorType *ot)
1509 {
1510         /* identifiers */
1511         ot->name = "Outliner Library Operation";
1512         ot->idname = "OUTLINER_OT_lib_operation";
1513         ot->description = "";
1514
1515         /* callbacks */
1516         ot->invoke = WM_menu_invoke;
1517         ot->exec = outliner_lib_operation_exec;
1518         ot->poll = ED_operator_outliner_active;
1519
1520         ot->prop = RNA_def_enum(ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
1521 }
1522
1523 /* **************************************** */
1524
1525 static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *lb, ID *newid,
1526                                          void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
1527 {
1528         TreeElement *te;
1529         TreeStoreElem *tselem;
1530         
1531         for (te = lb->first; te; te = te->next) {
1532                 tselem = TREESTORE(te);
1533                 if (tselem->flag & TSE_SELECTED) {
1534                         if (tselem->type == type) {
1535                                 TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
1536                                 operation_cb(te, tselem, tsep, newid);
1537                         }
1538                 }
1539                 if (TSELEM_OPEN(tselem, soops)) {
1540                         outliner_do_id_set_operation(soops, type, &te->subtree, newid, operation_cb);
1541                 }
1542         }
1543 }
1544
1545 /* ------------------------------------------ */
1546
1547 static void actionset_id_cb(TreeElement *UNUSED(te), TreeStoreElem *tselem, TreeStoreElem *tsep, ID *actId)
1548 {
1549         bAction *act = (bAction *)actId;
1550         
1551         if (tselem->type == TSE_ANIM_DATA) {
1552                 /* "animation" entries - action is child of this */
1553                 BKE_animdata_set_action(NULL, tselem->id, act);
1554         }
1555         /* TODO: if any other "expander" channels which own actions need to support this menu, 
1556          * add: tselem->type = ...
1557          */
1558         else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
1559                 /* "animation" entries case again */
1560                 BKE_animdata_set_action(NULL, tsep->id, act);
1561         }
1562         // TODO: other cases not supported yet
1563 }
1564
1565 static int outliner_action_set_exec(bContext *C, wmOperator *op)
1566 {
1567         SpaceOops *soops = CTX_wm_space_outliner(C);
1568         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1569         
1570         bAction *act;
1571         
1572         /* check for invalid states */
1573         if (soops == NULL)
1574                 return OPERATOR_CANCELLED;
1575         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1576         
1577         /* get action to use */
1578         act = BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action"));
1579         
1580         if (act == NULL) {
1581                 BKE_report(op->reports, RPT_ERROR, "No valid action to add");
1582                 return OPERATOR_CANCELLED;
1583         }
1584         else if (act->idroot == 0) {
1585                 /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
1586                 BKE_reportf(op->reports, RPT_WARNING,
1587                             "Action '%s' does not specify what data-blocks it can be used on "
1588                             "(try setting the 'ID Root Type' setting from the data-blocks editor "
1589                             "for this action to avoid future problems)",
1590                             act->id.name + 2);
1591         }
1592         
1593         /* perform action if valid channel */
1594         if (datalevel == TSE_ANIM_DATA)
1595                 outliner_do_id_set_operation(soops, datalevel, &soops->tree, (ID *)act, actionset_id_cb);
1596         else if (idlevel == ID_AC)
1597                 outliner_do_id_set_operation(soops, idlevel, &soops->tree, (ID *)act, actionset_id_cb);
1598         else
1599                 return OPERATOR_CANCELLED;
1600                 
1601         /* set notifier that things have changed */
1602         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
1603         ED_undo_push(C, "Set action");
1604         
1605         /* done */
1606         return OPERATOR_FINISHED;
1607 }
1608
1609 void OUTLINER_OT_action_set(wmOperatorType *ot)
1610 {
1611         PropertyRNA *prop;
1612
1613         /* identifiers */
1614         ot->name = "Outliner Set Action";
1615         ot->idname = "OUTLINER_OT_action_set";
1616         ot->description = "Change the active action used";
1617         
1618         /* api callbacks */
1619         ot->invoke = WM_enum_search_invoke;
1620         ot->exec = outliner_action_set_exec;
1621         ot->poll = ED_operator_outliner_active;
1622         
1623         /* flags */
1624         ot->flag = 0;
1625         
1626         /* props */
1627         // TODO: this would be nicer as an ID-pointer...
1628         prop = RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
1629         RNA_def_enum_funcs(prop, RNA_action_itemf);
1630         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
1631         ot->prop = prop;
1632 }
1633
1634 /* **************************************** */
1635
1636 typedef enum eOutliner_AnimDataOps {
1637         OUTLINER_ANIMOP_INVALID = 0,
1638         
1639         OUTLINER_ANIMOP_CLEAR_ADT,
1640         
1641         OUTLINER_ANIMOP_SET_ACT,
1642         OUTLINER_ANIMOP_CLEAR_ACT,
1643         
1644         OUTLINER_ANIMOP_REFRESH_DRV,
1645         OUTLINER_ANIMOP_CLEAR_DRV
1646         
1647         //OUTLINER_ANIMOP_COPY_DRIVERS,
1648         //OUTLINER_ANIMOP_PASTE_DRIVERS
1649 } eOutliner_AnimDataOps;
1650
1651 static const EnumPropertyItem prop_animdata_op_types[] = {
1652         {OUTLINER_ANIMOP_CLEAR_ADT, "CLEAR_ANIMDATA", 0, "Clear Animation Data", "Remove this animation data container"},
1653         {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""},
1654         {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
1655         {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
1656         //{OUTLINER_ANIMOP_COPY_DRIVERS, "COPY_DRIVERS", 0, "Copy Drivers", ""},
1657         //{OUTLINER_ANIMOP_PASTE_DRIVERS, "PASTE_DRIVERS", 0, "Paste Drivers", ""},
1658         {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
1659         {0, NULL, 0, NULL, NULL}
1660 };
1661
1662 static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
1663 {
1664         SpaceOops *soops = CTX_wm_space_outliner(C);
1665         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1666         eOutliner_AnimDataOps event;
1667         short updateDeps = 0;
1668         
1669         /* check for invalid states */
1670         if (soops == NULL)
1671                 return OPERATOR_CANCELLED;
1672         
1673         event = RNA_enum_get(op->ptr, "type");
1674         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1675         
1676         if (datalevel != TSE_ANIM_DATA)
1677                 return OPERATOR_CANCELLED;
1678         
1679         /* perform the core operation */
1680         switch (event) {
1681                 case OUTLINER_ANIMOP_CLEAR_ADT:
1682                         /* Remove Animation Data - this may remove the active action, in some cases... */
1683                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, clear_animdata_cb, NULL);
1684                         
1685                         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
1686                         ED_undo_push(C, "Clear Animation Data");
1687                         break;
1688                 
1689                 case OUTLINER_ANIMOP_SET_ACT:
1690                         /* delegate once again... */
1691                         WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
1692                         break;
1693                 
1694                 case OUTLINER_ANIMOP_CLEAR_ACT:
1695                         /* clear active action - using standard rules */
1696                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, unlinkact_animdata_cb, NULL);
1697                         
1698                         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
1699                         ED_undo_push(C, "Unlink action");
1700                         break;
1701                         
1702                 case OUTLINER_ANIMOP_REFRESH_DRV:
1703                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, refreshdrivers_animdata_cb, NULL);
1704                         
1705                         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
1706                         //ED_undo_push(C, "Refresh Drivers"); /* no undo needed - shouldn't have any impact? */
1707                         updateDeps = 1;
1708                         break;
1709                         
1710                 case OUTLINER_ANIMOP_CLEAR_DRV:
1711                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, cleardrivers_animdata_cb, NULL);
1712                         
1713                         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
1714                         ED_undo_push(C, "Clear Drivers");
1715                         updateDeps = 1;
1716                         break;
1717                         
1718                 default: // invalid
1719                         break;
1720         }
1721         
1722         /* update dependencies */
1723         if (updateDeps) {
1724                 /* rebuild depsgraph for the new deps */
1725                 DEG_relations_tag_update(CTX_data_main(C));
1726         }
1727         
1728         return OPERATOR_FINISHED;
1729 }
1730
1731
1732 void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
1733 {
1734         /* identifiers */
1735         ot->name = "Outliner Animation Data Operation";
1736         ot->idname = "OUTLINER_OT_animdata_operation";
1737         ot->description = "";
1738         
1739         /* callbacks */
1740         ot->invoke = WM_menu_invoke;
1741         ot->exec = outliner_animdata_operation_exec;
1742         ot->poll = ED_operator_outliner_active;
1743         
1744         ot->flag = 0;
1745         
1746         ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
1747 }
1748
1749 /* **************************************** */
1750
1751 static const EnumPropertyItem prop_constraint_op_types[] = {
1752         {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_RESTRICT_VIEW_OFF, "Enable", ""},
1753         {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_RESTRICT_VIEW_ON, "Disable", ""},
1754         {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
1755         {0, NULL, 0, NULL, NULL}
1756 };
1757
1758 static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
1759 {
1760         SpaceOops *soops = CTX_wm_space_outliner(C);
1761         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1762         eOutliner_PropConstraintOps event;
1763
1764         event = RNA_enum_get(op->ptr, "type");
1765         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1766
1767         outliner_do_data_operation(soops, datalevel, event, &soops->tree, constraint_cb, C);
1768
1769         if (event == OL_CONSTRAINTOP_DELETE) {
1770                 outliner_cleanup_tree(soops);
1771         }
1772
1773         ED_undo_push(C, "Constraint operation");
1774
1775         return OPERATOR_FINISHED;
1776 }
1777
1778 void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
1779 {
1780         /* identifiers */
1781         ot->name = "Outliner Constraint Operation";
1782         ot->idname = "OUTLINER_OT_constraint_operation";
1783         ot->description = "";
1784
1785         /* callbacks */
1786         ot->invoke = WM_menu_invoke;
1787         ot->exec = outliner_constraint_operation_exec;
1788         ot->poll = ED_operator_outliner_active;
1789
1790         ot->flag = 0;
1791
1792         ot->prop = RNA_def_enum(ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
1793 }
1794
1795 /* ******************** */
1796
1797 static const EnumPropertyItem prop_modifier_op_types[] = {
1798         {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""},
1799         {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle render use", ""},
1800         {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
1801         {0, NULL, 0, NULL, NULL}
1802 };
1803
1804 static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
1805 {
1806         SpaceOops *soops = CTX_wm_space_outliner(C);
1807         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1808         eOutliner_PropModifierOps event;
1809
1810         event = RNA_enum_get(op->ptr, "type");
1811         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1812
1813         outliner_do_data_operation(soops, datalevel, event, &soops->tree, modifier_cb, C);
1814
1815         if (event == OL_MODIFIER_OP_DELETE) {
1816                 outliner_cleanup_tree(soops);
1817         }
1818
1819         ED_undo_push(C, "Modifier operation");
1820
1821         return OPERATOR_FINISHED;
1822 }
1823
1824 void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
1825 {
1826         /* identifiers */
1827         ot->name = "Outliner Modifier Operation";
1828         ot->idname = "OUTLINER_OT_modifier_operation";
1829         ot->description = "";
1830
1831         /* callbacks */
1832         ot->invoke = WM_menu_invoke;
1833         ot->exec = outliner_modifier_operation_exec;
1834         ot->poll = ED_operator_outliner_active;
1835
1836         ot->flag = 0;
1837
1838         ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
1839 }
1840
1841 /* ******************** */
1842
1843 static EnumPropertyItem prop_collection_op_types[] = {
1844         {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"},
1845         {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"},
1846         {OL_COLLECTION_OP_OBJECTS_SELECT, "OBJECTS_SELECT", ICON_RESTRICT_SELECT_OFF, "Select Objects", "Select collection objects"},
1847         {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"},
1848         {OL_COLLECTION_OP_COLLECTION_COPY, "COLLECTION_DUPLI", ICON_NONE, "Duplicate Collection", "Duplicate the collection"},
1849         {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"},
1850         {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"},
1851         {OL_COLLECTION_OP_GROUP_CREATE, "GROUP_CREATE", ICON_GROUP, "Create Group", "Turn the collection into a group collection"},
1852         {0, NULL, 0, NULL, NULL}
1853 };
1854
1855 static int outliner_collection_operation_exec(bContext *C, wmOperator *op)
1856 {
1857         SpaceOops *soops = CTX_wm_space_outliner(C);
1858         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1859         eOutliner_PropCollectionOps event;
1860
1861         event = RNA_enum_get(op->ptr, "type");
1862         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1863
1864         outliner_do_data_operation(soops, datalevel, event, &soops->tree, collection_cb, C);
1865
1866         outliner_cleanup_tree(soops);
1867
1868         ED_undo_push(C, "Collection operation");
1869
1870         return OPERATOR_FINISHED;
1871 }
1872
1873 static int outliner_collection_operation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1874 {
1875         SpaceOops *soops = CTX_wm_space_outliner(C);
1876         wmOperatorType *ot = op->type;
1877         EnumPropertyItem *prop = &prop_collection_op_types[0];
1878
1879         uiPopupMenu *pup = UI_popup_menu_begin(C, "Collection", ICON_NONE);
1880         uiLayout *layout = UI_popup_menu_layout(pup);
1881
1882         for (int i = 0; i < (ARRAY_SIZE(prop_collection_op_types) - 1); i++, prop++) {
1883                 if (soops->outlinevis != SO_GROUPS ||
1884                     !ELEM(prop->value,
1885                           OL_COLLECTION_OP_OBJECTS_SELECT,
1886                           OL_COLLECTION_OP_COLLECTION_UNLINK,
1887                           OL_COLLECTION_OP_GROUP_CREATE))
1888                 {
1889                         uiItemEnumO_ptr(layout, ot, NULL, prop->icon, "type", prop->value);
1890                 }
1891         }
1892
1893         UI_popup_menu_end(C, pup);
1894
1895         return OPERATOR_INTERFACE;
1896 }
1897
1898 void OUTLINER_OT_collection_operation(wmOperatorType *ot)
1899 {
1900         PropertyRNA *prop;
1901
1902         /* identifiers */
1903         ot->name = "Outliner Collection Operation";
1904         ot->idname = "OUTLINER_OT_collection_operation";
1905         ot->description = "";
1906
1907         /* callbacks */
1908         ot->invoke = outliner_collection_operation_invoke;
1909         ot->exec = outliner_collection_operation_exec;
1910         ot->poll = ED_operator_outliner_active;
1911
1912         ot->flag = 0;
1913
1914         prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, OL_COLLECTION_OP_OBJECTS_ADD, "Collection Operation", "");
1915         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
1916         ot->prop = prop;
1917 }
1918
1919 /* ******************** */
1920
1921 // XXX: select linked is for RNA structs only
1922 static const EnumPropertyItem prop_data_op_types[] = {
1923         {OL_DOP_SELECT, "SELECT", 0, "Select", ""},
1924         {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
1925         {OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
1926         {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
1927         {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
1928         {0, NULL, 0, NULL, NULL}
1929 };
1930
1931 static int outliner_data_operation_exec(bContext *C, wmOperator *op)
1932 {
1933         SpaceOops *soops = CTX_wm_space_outliner(C);
1934         int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1935         eOutliner_PropDataOps event;
1936         
1937         /* check for invalid states */
1938         if (soops == NULL)
1939                 return OPERATOR_CANCELLED;
1940         
1941         event = RNA_enum_get(op->ptr, "type");
1942         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
1943         
1944         switch (datalevel) {
1945                 case TSE_POSE_CHANNEL:
1946                 {
1947                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb, NULL);
1948                         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
1949                         ED_undo_push(C, "PoseChannel operation");
1950
1951                         break;
1952                 }
1953                 case TSE_BONE:
1954                 {
1955                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb, NULL);
1956                         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
1957                         ED_undo_push(C, "Bone operation");
1958
1959                         break;
1960                 }
1961                 case TSE_EBONE:
1962                 {
1963                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb, NULL);
1964                         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
1965                         ED_undo_push(C, "EditBone operation");
1966
1967                         break;
1968                 }
1969                 case TSE_SEQUENCE:
1970                 {
1971                         Scene *scene = CTX_data_scene(C);
1972                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, sequence_cb, scene);
1973
1974                         break;
1975                 }
1976                 case TSE_GP_LAYER:
1977                 {
1978                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, gp_layer_cb, NULL);
1979                         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
1980                         ED_undo_push(C, "Grease Pencil Layer operation");
1981
1982                         break;
1983                 }
1984                 case TSE_RNA_STRUCT:
1985                         if (event == OL_DOP_SELECT_LINKED) {
1986                                 outliner_do_data_operation(soops, datalevel, event, &soops->tree, data_select_linked_cb, C);
1987                         }
1988
1989                         break;
1990
1991                 default:
1992                         BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
1993                         break;
1994         }
1995         
1996         return OPERATOR_FINISHED;
1997 }
1998
1999
2000 void OUTLINER_OT_data_operation(wmOperatorType *ot)
2001 {
2002         /* identifiers */
2003         ot->name = "Outliner Data Operation";
2004         ot->idname = "OUTLINER_OT_data_operation";
2005         ot->description = "";
2006         
2007         /* callbacks */
2008         ot->invoke = WM_menu_invoke;
2009         ot->exec = outliner_data_operation_exec;
2010         ot->poll = ED_operator_outliner_active;
2011         
2012         ot->flag = 0;
2013         
2014         ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", "");
2015 }
2016
2017
2018 /* ******************** */
2019
2020
2021 static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soops,
2022                                        TreeElement *te, const float mval[2])
2023 {
2024         ReportList *reports = CTX_wm_reports(C); // XXX...
2025         
2026         if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
2027                 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
2028                 TreeStoreElem *tselem = TREESTORE(te);
2029                 
2030                 /* select object that's clicked on and popup context menu */
2031                 if (!(tselem->flag & TSE_SELECTED)) {
2032                         
2033                         if (outliner_has_one_flag(&soops->tree, TSE_SELECTED, 1))
2034                                 outliner_set_flag(&soops->tree, TSE_SELECTED, 0);
2035                         
2036                         tselem->flag |= TSE_SELECTED;
2037                         /* redraw, same as outliner_select function */
2038                         soops->storeflag |= SO_TREESTORE_REDRAW;
2039                         ED_region_tag_redraw(ar);
2040                 }
2041                 
2042                 set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
2043                 
2044                 if (scenelevel) {
2045                         if (objectlevel || datalevel || idlevel) {
2046                                 BKE_report(reports, RPT_WARNING, "Mixed selection");
2047                         }
2048                         else {
2049                                 WM_operator_name_call(C, "OUTLINER_OT_scene_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2050                         }
2051                 }
2052                 else if (objectlevel) {
2053                         WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN);
2054                 }
2055                 else if (idlevel) {
2056                         if (idlevel == -1 || datalevel) {
2057                                 BKE_report(reports, RPT_WARNING, "Mixed selection");
2058                         }
2059                         else {
2060                                 switch (idlevel) {
2061                                         case ID_GR:
2062                                                 WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2063                                                 break;
2064                                         case ID_LI:
2065                                                 WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2066                                                 break;
2067                                         default:
2068                                                 WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2069                                                 break;
2070                                 }
2071                         }
2072                 }
2073                 else if (datalevel) {
2074                         if (datalevel == -1) {
2075                                 BKE_report(reports, RPT_WARNING, "Mixed selection");
2076                         }
2077                         else {
2078                                 if (datalevel == TSE_ANIM_DATA)
2079                                         WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2080                                 else if (datalevel == TSE_DRIVER_BASE) {
2081                                         /* do nothing... no special ops needed yet */
2082                                 }
2083                                 else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER)) {
2084                                         /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
2085                                 }
2086                                 else if (datalevel == TSE_ID_BASE) {
2087                                         /* do nothing... there are no ops needed here yet */
2088                                 }
2089                                 else if (datalevel == TSE_CONSTRAINT) {
2090                                         WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2091                                 }
2092                                 else if (datalevel == TSE_MODIFIER) {
2093                                         WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2094                                 }
2095                                 else if (datalevel == TSE_LAYER_COLLECTION) {
2096                                         WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2097                                 }
2098                                 else if (datalevel == TSE_SCENE_COLLECTION) {
2099                                         WM_menu_name_call(C, "OUTLINER_MT_context_scene_collection", WM_OP_INVOKE_REGION_WIN);
2100                                 }
2101                                 else {
2102                                         WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
2103                                 }
2104                         }
2105                 }
2106                 
2107                 return 1;
2108         }
2109         
2110         for (te = te->subtree.first; te; te = te->next) {
2111                 if (do_outliner_operation_event(C, ar, soops, te, mval))
2112                         return 1;
2113         }
2114         return 0;
2115 }
2116
2117
2118 static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
2119 {
2120         ARegion *ar = CTX_wm_region(C);
2121         SpaceOops *soops = CTX_wm_space_outliner(C);
2122         uiBut *but = UI_context_active_but_get(C);
2123         TreeElement *te;
2124         float fmval[2];
2125
2126         if (but) {
2127                 UI_but_tooltip_timer_remove(C, but);
2128         }
2129
2130         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
2131         
2132         for (te = soops->tree.first; te; te = te->next) {
2133                 if (do_outliner_operation_event(C, ar, soops, te, fmval)) {
2134                         break;
2135                 }
2136         }
2137         
2138         return OPERATOR_FINISHED;
2139 }
2140
2141 /* Menu only! Calls other operators */
2142 void OUTLINER_OT_operation(wmOperatorType *ot)
2143 {
2144         ot->name = "Execute Operation";
2145         ot->idname = "OUTLINER_OT_operation";
2146         ot->description = "Context menu for item operations";
2147         
2148         ot->invoke = outliner_operation;
2149         
2150         ot->poll = ED_operator_outliner_active;
2151 }
2152
2153 /* ****************************************************** */