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