Blender  V2.59
outliner_tools.c
Go to the documentation of this file.
00001 /*
00002  * $Id: outliner_tools.c 39294 2011-08-11 06:40:04Z gsrb3d $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2004 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Joshua Leung
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00034 #include <math.h>
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include <stddef.h>
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "DNA_anim_types.h"
00042 #include "DNA_armature_types.h"
00043 #include "DNA_constraint_types.h"
00044 #include "DNA_camera_types.h"
00045 #include "DNA_group_types.h"
00046 #include "DNA_key_types.h"
00047 #include "DNA_lamp_types.h"
00048 #include "DNA_material_types.h"
00049 #include "DNA_mesh_types.h"
00050 #include "DNA_meta_types.h"
00051 #include "DNA_particle_types.h"
00052 #include "DNA_scene_types.h"
00053 #include "DNA_world_types.h"
00054 #include "DNA_sequence_types.h"
00055 #include "DNA_object_types.h"
00056 
00057 #include "BLI_blenlib.h"
00058 #include "BLI_utildefines.h"
00059 #include "BLI_math_base.h"
00060 
00061 #if defined WIN32 && !defined _LIBC
00062 # include "BLI_fnmatch.h" /* use fnmatch included in blenlib */
00063 #else
00064 #  ifndef _GNU_SOURCE
00065 #    define _GNU_SOURCE
00066 #  endif
00067 # include <fnmatch.h>
00068 #endif
00069 
00070 
00071 #include "BKE_animsys.h"
00072 #include "BKE_context.h"
00073 #include "BKE_deform.h"
00074 #include "BKE_depsgraph.h"
00075 #include "BKE_fcurve.h"
00076 #include "BKE_global.h"
00077 #include "BKE_group.h"
00078 #include "BKE_library.h"
00079 #include "BKE_main.h"
00080 #include "BKE_modifier.h"
00081 #include "BKE_report.h"
00082 #include "BKE_scene.h"
00083 #include "BKE_sequencer.h"
00084 
00085 #include "ED_armature.h"
00086 #include "ED_object.h"
00087 #include "ED_screen.h"
00088 #include "ED_util.h"
00089 
00090 #include "WM_api.h"
00091 #include "WM_types.h"
00092 
00093 #include "BIF_gl.h"
00094 #include "BIF_glutil.h"
00095 
00096 #include "UI_interface.h"
00097 #include "UI_interface_icons.h"
00098 #include "UI_resources.h"
00099 #include "UI_view2d.h"
00100 
00101 #include "RNA_access.h"
00102 #include "RNA_define.h"
00103 #include "RNA_enum_types.h"
00104 
00105 #include "outliner_intern.h"
00106 
00107 /* ****************************************************** */
00108 
00109 /* ************ SELECTION OPERATIONS ********* */
00110 
00111 static void set_operation_types(SpaceOops *soops, ListBase *lb,
00112                                 int *scenelevel,
00113                                 int *objectlevel,
00114                                 int *idlevel,
00115                                 int *datalevel)
00116 {
00117         TreeElement *te;
00118         TreeStoreElem *tselem;
00119         
00120         for(te= lb->first; te; te= te->next) {
00121                 tselem= TREESTORE(te);
00122                 if(tselem->flag & TSE_SELECTED) {
00123                         if(tselem->type) {
00124                                 if(*datalevel==0) 
00125                                         *datalevel= tselem->type;
00126                                 else if(*datalevel!=tselem->type) 
00127                                         *datalevel= -1;
00128                         }
00129                         else {
00130                                 int idcode= GS(tselem->id->name);
00131                                 switch(idcode) {
00132                                         case ID_SCE:
00133                                                 *scenelevel= 1;
00134                                                 break;
00135                                         case ID_OB:
00136                                                 *objectlevel= 1;
00137                                                 break;
00138                                                 
00139                                         case ID_ME: case ID_CU: case ID_MB: case ID_LT:
00140                                         case ID_LA: case ID_AR: case ID_CA: /* case ID_SPK: */ /* GSOC_PEPPER */
00141                                         case ID_MA: case ID_TE: case ID_IP: case ID_IM:
00142                                         case ID_SO: case ID_KE: case ID_WO: case ID_AC:
00143                                         case ID_NLA: case ID_TXT: case ID_GR:
00144                                                 if(*idlevel==0) *idlevel= idcode;
00145                                                 else if(*idlevel!=idcode) *idlevel= -1;
00146                                                         break;
00147                                 }
00148                         }
00149                 }
00150                 if((tselem->flag & TSE_CLOSED)==0) {
00151                         set_operation_types(soops, &te->subtree,
00152                                                                 scenelevel, objectlevel, idlevel, datalevel);
00153                 }
00154         }
00155 }
00156 
00157 #if 0 // GSOC_PEPPER
00158 
00159 static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem))
00160 {
00161         /* just set action to NULL */
00162         BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
00163 }
00164 
00165 #endif // GSOC_PEPPER
00166 
00167 static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem))
00168 {
00169         Material **matar=NULL;
00170         int a, totcol=0;
00171         
00172         if( GS(tsep->id->name)==ID_OB) {
00173                 Object *ob= (Object *)tsep->id;
00174                 totcol= ob->totcol;
00175                 matar= ob->mat;
00176         }
00177         else if( GS(tsep->id->name)==ID_ME) {
00178                 Mesh *me= (Mesh *)tsep->id;
00179                 totcol= me->totcol;
00180                 matar= me->mat;
00181         }
00182         else if( GS(tsep->id->name)==ID_CU) {
00183                 Curve *cu= (Curve *)tsep->id;
00184                 totcol= cu->totcol;
00185                 matar= cu->mat;
00186         }
00187         else if( GS(tsep->id->name)==ID_MB) {
00188                 MetaBall *mb= (MetaBall *)tsep->id;
00189                 totcol= mb->totcol;
00190                 matar= mb->mat;
00191         }
00192 
00193         for(a=0; a<totcol; a++) {
00194                 if(a==te->index && matar[a]) {
00195                         matar[a]->id.us--;
00196                         matar[a]= NULL;
00197                 }
00198         }
00199 }
00200 
00201 static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem))
00202 {
00203         MTex **mtex= NULL;
00204         int a;
00205         
00206         if( GS(tsep->id->name)==ID_MA) {
00207                 Material *ma= (Material *)tsep->id;
00208                 mtex= ma->mtex;
00209         }
00210         else if( GS(tsep->id->name)==ID_LA) {
00211                 Lamp *la= (Lamp *)tsep->id;
00212                 mtex= la->mtex;
00213         }
00214         else if( GS(tsep->id->name)==ID_WO) {
00215                 World *wrld= (World *)tsep->id;
00216                 mtex= wrld->mtex;
00217         }
00218         else return;
00219         
00220         for(a=0; a<MAX_MTEX; a++) {
00221                 if(a==te->index && mtex[a]) {
00222                         if(mtex[a]->tex) {
00223                                 mtex[a]->tex->id.us--;
00224                                 mtex[a]->tex= NULL;
00225                         }
00226                 }
00227         }
00228 }
00229 
00230 static void unlink_group_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem)
00231 {
00232         Group *group= (Group *)tselem->id;
00233         
00234         if(tsep) {
00235                 if( GS(tsep->id->name)==ID_OB) {
00236                         Object *ob= (Object *)tsep->id;
00237                         ob->dup_group= NULL;
00238                 }
00239         }
00240         else {
00241                 unlink_group(group);
00242         }
00243 }
00244 
00245 static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb, 
00246                                                                                  void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *))
00247 {
00248         TreeElement *te;
00249         TreeStoreElem *tselem;
00250         
00251         for(te=lb->first; te; te= te->next) {
00252                 tselem= TREESTORE(te);
00253                 if(tselem->flag & TSE_SELECTED) {
00254                         if(tselem->type==0) {
00255                                 TreeStoreElem *tsep= TREESTORE(te->parent);
00256                                 operation_cb(C, scene, te, tsep, tselem);
00257                         }
00258                 }
00259                 if((tselem->flag & TSE_CLOSED)==0) {
00260                         outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb);
00261                 }
00262         }
00263 }
00264 
00265 /* */
00266 
00267 static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
00268 {
00269         Base *base= (Base *)te->directdata;
00270         
00271         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
00272         if(base && ((base->object->restrictflag & OB_RESTRICT_VIEW)==0)) {
00273                 base->flag |= SELECT;
00274                 base->object->flag |= SELECT;
00275         }
00276 }
00277 
00278 static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
00279 {
00280         Base *base= (Base *)te->directdata;
00281         
00282         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
00283         if(base) {
00284                 base->flag &= ~SELECT;
00285                 base->object->flag &= ~SELECT;
00286         }
00287 }
00288 
00289 static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
00290 {
00291         Base *base= (Base *)te->directdata;
00292         
00293         if(base==NULL) 
00294                 base= object_in_scene((Object *)tselem->id, scene);
00295         if(base) {
00296                 // check also library later
00297                 if(scene->obedit==base->object) 
00298                         ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
00299                 
00300                 ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
00301                 te->directdata= NULL;
00302                 tselem->id= NULL;
00303         }
00304 
00305 }
00306 
00307 static void id_local_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
00308 {
00309         if (tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) {
00310                 tselem->id->lib= NULL;
00311                 tselem->id->flag= LIB_LOCAL;
00312                 new_id(NULL, tselem->id, NULL);
00313         }
00314 }
00315 
00316 static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
00317 {
00318         ID *id = tselem->id;
00319         
00320         if ((id) && ((id->flag & LIB_FAKEUSER) == 0)) {
00321                 id->flag |= LIB_FAKEUSER;
00322                 id_us_plus(id);
00323         }
00324 }
00325 
00326 static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
00327 {
00328         ID *id = tselem->id;
00329         
00330         if ((id) && (id->flag & LIB_FAKEUSER)) {
00331                 id->flag &= ~LIB_FAKEUSER;
00332                 id_us_min(id);
00333         }
00334 }
00335 
00336 #if 0 // GSOC_PEPPER
00337 
00338 static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem)
00339 {
00340         ID *id = tselem->id;
00341         
00342         if (id) {
00343                 IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
00344                 PointerRNA ptr = {{0}};
00345                 PropertyRNA *prop;
00346                 
00347                 RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr);
00348                 prop = RNA_struct_find_property(&ptr, "action");
00349                 
00350                 id_single_user(C, id, &ptr, prop);
00351         }
00352 }
00353 
00354 #endif
00355 
00356 static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
00357 {
00358         Group *group= (Group *)tselem->id;
00359         GroupObject *gob;
00360         Base *base;
00361         
00362         for(gob=group->gobject.first; gob; gob=gob->next) {
00363                 base= object_in_scene(gob->ob, scene);
00364                 if (base) {
00365                         base->object->flag |= SELECT;
00366                         base->flag |= SELECT;
00367                 } else {
00368                         /* link to scene */
00369                         base= MEM_callocN( sizeof(Base), "add_base");
00370                         BLI_addhead(&scene->base, base);
00371                         base->lay= (1<<20)-1; /*v3d->lay;*/ /* would be nice to use the 3d layer but the include's not here */
00372                         gob->ob->flag |= SELECT;
00373                         base->flag = gob->ob->flag;
00374                         base->object= gob->ob;
00375                         id_lib_extern((ID *)gob->ob); /* incase these are from a linked group */
00376                 }
00377         }
00378 }
00379 
00380 void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, 
00381                                                                   void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *))
00382 {
00383         TreeElement *te;
00384         TreeStoreElem *tselem;
00385         
00386         for(te=lb->first; te; te= te->next) {
00387                 tselem= TREESTORE(te);
00388                 if(tselem->flag & TSE_SELECTED) {
00389                         if(tselem->type==0 && te->idcode==ID_OB) {
00390                                 // when objects selected in other scenes... dunno if that should be allowed
00391                                 Scene *scene_owner= (Scene *)outliner_search_back(soops, te, ID_SCE);
00392                                 if(scene_owner && scene_act != scene_owner) {
00393                                         ED_screen_set_scene(C, scene_owner);
00394                                 }
00395                                 /* important to use 'scene_owner' not scene_act else deleting objects can crash.
00396                                  * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
00397                                  * outliner isnt showing scenes: Visible Layer draw mode for eg. */
00398                                 operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem);
00399                         }
00400                 }
00401                 if((tselem->flag & TSE_CLOSED)==0) {
00402                         outliner_do_object_operation(C, scene_act, soops, &te->subtree, operation_cb);
00403                 }
00404         }
00405 }
00406 
00407 /* ******************************************** */
00408 
00409 #if 0 // GSOC_PEPPER
00410 
00411 static void unlinkact_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem)
00412 {
00413         /* just set action to NULL */
00414         BKE_animdata_set_action(NULL, tselem->id, NULL);
00415 }
00416 
00417 #endif // GSOC_PEPPER
00418 
00419 static void cleardrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem)
00420 {
00421         IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
00422         
00423         /* just free drivers - stored as a list of F-Curves */
00424         free_fcurves(&iat->adt->drivers);
00425 }
00426 
00427 static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem)
00428 {
00429         IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
00430         FCurve *fcu;
00431         
00432         /* loop over drivers, performing refresh (i.e. check graph_buttons.c and rna_fcurve.c for details) */
00433         for (fcu = iat->adt->drivers.first; fcu; fcu= fcu->next) {
00434                 fcu->flag &= ~FCURVE_DISABLED;
00435                 
00436                 if (fcu->driver)
00437                         fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
00438         }
00439 }
00440 
00441 /* --------------------------------- */
00442 
00443 static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem))
00444 {
00445         bPoseChannel *pchan= (bPoseChannel *)te->directdata;
00446         
00447         if(event==1)
00448                 pchan->bone->flag |= BONE_SELECTED;
00449         else if(event==2)
00450                 pchan->bone->flag &= ~BONE_SELECTED;
00451         else if(event==3) {
00452                 pchan->bone->flag |= BONE_HIDDEN_P;
00453                 pchan->bone->flag &= ~BONE_SELECTED;
00454         }
00455         else if(event==4)
00456                 pchan->bone->flag &= ~BONE_HIDDEN_P;
00457 }
00458 
00459 static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem))
00460 {
00461         Bone *bone= (Bone *)te->directdata;
00462         
00463         if(event==1)
00464                 bone->flag |= BONE_SELECTED;
00465         else if(event==2)
00466                 bone->flag &= ~BONE_SELECTED;
00467         else if(event==3) {
00468                 bone->flag |= BONE_HIDDEN_P;
00469                 bone->flag &= ~BONE_SELECTED;
00470         }
00471         else if(event==4)
00472                 bone->flag &= ~BONE_HIDDEN_P;
00473 }
00474 
00475 static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem))
00476 {
00477         EditBone *ebone= (EditBone *)te->directdata;
00478         
00479         if(event==1)
00480                 ebone->flag |= BONE_SELECTED;
00481         else if(event==2)
00482                 ebone->flag &= ~BONE_SELECTED;
00483         else if(event==3) {
00484                 ebone->flag |= BONE_HIDDEN_A;
00485                 ebone->flag &= ~BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
00486         }
00487         else if(event==4)
00488                 ebone->flag &= ~BONE_HIDDEN_A;
00489 }
00490 
00491 static void sequence_cb(int event, TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tselem))
00492 {
00493 //      Sequence *seq= (Sequence*) te->directdata;
00494         if(event==1) {
00495 // XXX          select_single_seq(seq, 1);
00496         }
00497 }
00498 
00499 static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, 
00500                                                                                  void (*operation_cb)(int, TreeElement *, TreeStoreElem *))
00501 {
00502         TreeElement *te;
00503         TreeStoreElem *tselem;
00504         
00505         for(te=lb->first; te; te= te->next) {
00506                 tselem= TREESTORE(te);
00507                 if(tselem->flag & TSE_SELECTED) {
00508                         if(tselem->type==type) {
00509                                 operation_cb(event, te, tselem);
00510                         }
00511                 }
00512                 if((tselem->flag & TSE_CLOSED)==0) {
00513                         outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb);
00514                 }
00515         }
00516 }
00517 
00518 /* **************************************** */
00519 
00520 static EnumPropertyItem prop_object_op_types[] = {
00521         {1, "SELECT", 0, "Select", ""},
00522         {2, "DESELECT", 0, "Deselect", ""},
00523         {4, "DELETE", 0, "Delete", ""},
00524         {6, "TOGVIS", 0, "Toggle Visible", ""},
00525         {7, "TOGSEL", 0, "Toggle Selectable", ""},
00526         {8, "TOGREN", 0, "Toggle Renderable", ""},
00527         {0, NULL, 0, NULL, NULL}
00528 };
00529 
00530 static int outliner_object_operation_exec(bContext *C, wmOperator *op)
00531 {
00532         Main *bmain= CTX_data_main(C);
00533         Scene *scene= CTX_data_scene(C);
00534         SpaceOops *soops= CTX_wm_space_outliner(C);
00535         int event;
00536         const char *str= NULL;
00537         
00538         /* check for invalid states */
00539         if (soops == NULL)
00540                 return OPERATOR_CANCELLED;
00541         
00542         event= RNA_enum_get(op->ptr, "type");
00543 
00544         if(event==1) {
00545                 Scene *sce= scene;      // to be able to delete, scenes are set...
00546                 outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb);
00547                 if(scene != sce) {
00548                         ED_screen_set_scene(C, sce);
00549                 }
00550                 
00551                 str= "Select Objects";
00552                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
00553         }
00554         else if(event==2) {
00555                 outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb);
00556                 str= "Deselect Objects";
00557                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
00558         }
00559         else if(event==4) {
00560                 outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb);
00561                 DAG_scene_sort(bmain, scene);
00562                 str= "Delete Objects";
00563                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
00564         }
00565         else if(event==5) {     /* disabled, see above enum (ton) */
00566                 outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
00567                 str= "Localized Objects";
00568         }
00569         else if(event==6) {
00570                 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
00571                 str= "Toggle Visibility";
00572                 WM_event_add_notifier(C, NC_SCENE|ND_OB_VISIBLE, scene);
00573         }
00574         else if(event==7) {
00575                 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
00576                 str= "Toggle Selectability";
00577                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
00578         }
00579         else if(event==8) {
00580                 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
00581                 str= "Toggle Renderability";
00582                 WM_event_add_notifier(C, NC_SCENE|ND_OB_RENDER, scene);
00583         }
00584 
00585         ED_undo_push(C, str);
00586         
00587         return OPERATOR_FINISHED;
00588 }
00589 
00590 
00591 void OUTLINER_OT_object_operation(wmOperatorType *ot)
00592 {
00593         /* identifiers */
00594         ot->name= "Outliner Object Operation";
00595         ot->idname= "OUTLINER_OT_object_operation";
00596         ot->description= "";
00597         
00598         /* callbacks */
00599         ot->invoke= WM_menu_invoke;
00600         ot->exec= outliner_object_operation_exec;
00601         ot->poll= ED_operator_outliner_active;
00602         
00603         ot->flag= 0;
00604 
00605         ot->prop= RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
00606 }
00607 
00608 /* **************************************** */
00609 
00610 static EnumPropertyItem prop_group_op_types[] = {
00611         {1, "UNLINK", 0, "Unlink", ""},
00612         {2, "LOCAL", 0, "Make Local", ""},
00613         {3, "LINK", 0, "Link Group Objects to Scene", ""},
00614         {4, "TOGVIS", 0, "Toggle Visible", ""},
00615         {5, "TOGSEL", 0, "Toggle Selectable", ""},
00616         {6, "TOGREN", 0, "Toggle Renderable", ""},
00617         {0, NULL, 0, NULL, NULL}
00618 };
00619 
00620 static int outliner_group_operation_exec(bContext *C, wmOperator *op)
00621 {
00622         Scene *scene= CTX_data_scene(C);
00623         SpaceOops *soops= CTX_wm_space_outliner(C);
00624         int event;
00625         
00626         /* check for invalid states */
00627         if (soops == NULL)
00628                 return OPERATOR_CANCELLED;
00629         
00630         event= RNA_enum_get(op->ptr, "type");
00631         
00632         if(event==1) {
00633                 outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb);
00634                 ED_undo_push(C, "Unlink group");
00635         }
00636         else if(event==2) {
00637                 outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
00638                 ED_undo_push(C, "Localized Data");
00639         }
00640         else if(event==3) {
00641                 outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb);
00642                 ED_undo_push(C, "Link Group Objects to Scene");
00643         }
00644         
00645         
00646         WM_event_add_notifier(C, NC_GROUP, NULL);
00647         
00648         return OPERATOR_FINISHED;
00649 }
00650 
00651 
00652 void OUTLINER_OT_group_operation(wmOperatorType *ot)
00653 {
00654         /* identifiers */
00655         ot->name= "Outliner Group Operation";
00656         ot->idname= "OUTLINER_OT_group_operation";
00657         ot->description= "";
00658         
00659         /* callbacks */
00660         ot->invoke= WM_menu_invoke;
00661         ot->exec= outliner_group_operation_exec;
00662         ot->poll= ED_operator_outliner_active;
00663         
00664         ot->flag= 0;
00665         
00666         ot->prop= RNA_def_enum(ot->srna, "type", prop_group_op_types, 0, "Group Operation", "");
00667 }
00668 
00669 /* **************************************** */
00670 
00671 typedef enum eOutlinerIdOpTypes {
00672         OUTLINER_IDOP_INVALID = 0,
00673         
00674         OUTLINER_IDOP_UNLINK,
00675         OUTLINER_IDOP_LOCAL,
00676         OUTLINER_IDOP_SINGLE,
00677         
00678         OUTLINER_IDOP_FAKE_ADD,
00679         OUTLINER_IDOP_FAKE_CLEAR
00680 } eOutlinerIdOpTypes;
00681 
00682 // TODO: implement support for changing the ID-block used
00683 static EnumPropertyItem prop_id_op_types[] = {
00684         {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
00685         {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
00686         {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
00687         {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User", "Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"},
00688         {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
00689         {0, NULL, 0, NULL, NULL}
00690 };
00691 
00692 static int outliner_id_operation_exec(bContext *C, wmOperator *op)
00693 {
00694         Scene *scene= CTX_data_scene(C);
00695         SpaceOops *soops= CTX_wm_space_outliner(C);
00696         int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0;
00697         eOutlinerIdOpTypes event;
00698         
00699         /* check for invalid states */
00700         if (soops == NULL)
00701                 return OPERATOR_CANCELLED;
00702         
00703         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
00704         
00705         event= RNA_enum_get(op->ptr, "type");
00706         
00707         switch (event) {
00708                 case OUTLINER_IDOP_UNLINK:
00709                 {
00710                         /* unlink datablock from its parent */
00711                         switch (idlevel) {
00712 
00713 #if 0 // GSOC_PEPPER
00714 
00715                                 case ID_AC:
00716                                         outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb);
00717                                         
00718                                         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
00719                                         ED_undo_push(C, "Unlink action");
00720                                         break;
00721 
00722 #endif // GSOC_PEPPER
00723 
00724                                 case ID_MA:
00725                                         outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb);
00726                                         
00727                                         WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL);
00728                                         ED_undo_push(C, "Unlink material");
00729                                         break;
00730                                 case ID_TE:
00731                                         outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb);
00732                                         
00733                                         WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL);
00734                                         ED_undo_push(C, "Unlink texture");
00735                                         break;
00736                                 default:
00737                                         BKE_report(op->reports, RPT_WARNING, "Not Yet");
00738                                         break;
00739                         }
00740                 }
00741                         break;
00742                         
00743                 case OUTLINER_IDOP_LOCAL:
00744                 {
00745                         /* make local */
00746                         outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
00747                         ED_undo_push(C, "Localized Data");
00748                 }
00749                         break;
00750                         
00751 #if 0 // GSOC_PEPPER
00752 
00753                 case OUTLINER_IDOP_SINGLE:
00754                 {
00755                         /* make single user */
00756                         switch (idlevel) {
00757                                 case ID_AC:
00758                                         outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb);
00759                                         
00760                                         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
00761                                         ED_undo_push(C, "Single-User Action");
00762                                         break;
00763                                         
00764                                 default:
00765                                         BKE_report(op->reports, RPT_WARNING, "Not Yet");
00766                                         break;
00767                         }
00768                 }
00769                         break;
00770                         
00771 #endif // GSOC_PEPPER
00772 
00773                 case OUTLINER_IDOP_FAKE_ADD:
00774                 {
00775                         /* set fake user */
00776                         outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb);
00777                         
00778                         WM_event_add_notifier(C, NC_ID|NA_EDITED, NULL);
00779                         ED_undo_push(C, "Add Fake User");
00780                 }
00781                         break;
00782                         
00783                 case OUTLINER_IDOP_FAKE_CLEAR:
00784                 {
00785                         /* clear fake user */
00786                         outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb);
00787                         
00788                         WM_event_add_notifier(C, NC_ID|NA_EDITED, NULL);
00789                         ED_undo_push(C, "Clear Fake User");
00790                 }
00791                         break;
00792                         
00793                 default:
00794                         // invalid - unhandled
00795                         break;
00796         }
00797         
00798         /* wrong notifier still... */
00799         WM_event_add_notifier(C, NC_ID|NA_EDITED, NULL);
00800         
00801         // XXX: this is just so that outliner is always up to date 
00802         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_OUTLINER, NULL);
00803         
00804         return OPERATOR_FINISHED;
00805 }
00806 
00807 
00808 void OUTLINER_OT_id_operation(wmOperatorType *ot)
00809 {
00810         /* identifiers */
00811         ot->name= "Outliner ID data Operation";
00812         ot->idname= "OUTLINER_OT_id_operation";
00813         ot->description= "";
00814         
00815         /* callbacks */
00816         ot->invoke= WM_menu_invoke;
00817         ot->exec= outliner_id_operation_exec;
00818         ot->poll= ED_operator_outliner_active;
00819         
00820         ot->flag= 0;
00821         
00822         ot->prop= RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID data Operation", "");
00823 }
00824 
00825 /* **************************************** */
00826 
00827 static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *lb, ID *newid,
00828                                                                                  void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
00829 {
00830         TreeElement *te;
00831         TreeStoreElem *tselem;
00832         
00833         for (te=lb->first; te; te= te->next) {
00834                 tselem= TREESTORE(te);
00835                 if (tselem->flag & TSE_SELECTED) {
00836                         if(tselem->type==type) {
00837                                 TreeStoreElem *tsep = TREESTORE(te->parent);
00838                                 operation_cb(te, tselem, tsep, newid);
00839                         }
00840                 }
00841                 if ((tselem->flag & TSE_CLOSED)==0) {
00842                         outliner_do_id_set_operation(soops, type, &te->subtree, newid, operation_cb);
00843                 }
00844         }
00845 }
00846 
00847 /* ------------------------------------------ */
00848 
00849 #if 0 // GSOC_PEPPER
00850 
00851 static void actionset_id_cb(TreeElement *te, TreeStoreElem *tselem, TreeStoreElem *tsep, ID *actId)
00852 {
00853         bAction *act = (bAction *)actId;
00854         
00855         if (tselem->type == TSE_ANIM_DATA) {
00856                 /* "animation" entries - action is child of this */
00857                 BKE_animdata_set_action(NULL, tselem->id, act);
00858         }
00859         /* TODO: if any other "expander" channels which own actions need to support this menu, 
00860          * add: tselem->type = ...
00861          */
00862         else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
00863                 /* "animation" entries case again */
00864                 BKE_animdata_set_action(NULL, tsep->id, act);
00865         }
00866         // TODO: other cases not supported yet
00867 }
00868 
00869 static int outliner_action_set_exec(bContext *C, wmOperator *op)
00870 {
00871         SpaceOops *soops= CTX_wm_space_outliner(C);
00872         int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0;
00873         
00874         bAction *act;
00875         
00876         /* check for invalid states */
00877         if (soops == NULL)
00878                 return OPERATOR_CANCELLED;
00879         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
00880         
00881         /* get action to use */
00882         act= BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action"));
00883         
00884         if (act == NULL) {
00885                 BKE_report(op->reports, RPT_ERROR, "No valid Action to add.");
00886                 return OPERATOR_CANCELLED;
00887         }
00888         else if (act->idroot == 0) {
00889                 /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
00890                 BKE_reportf(op->reports, RPT_WARNING,
00891                         "Action '%s' does not specify what datablocks it can be used on. Try setting the 'ID Root Type' setting from the Datablocks Editor for this Action to avoid future problems",
00892                         act->id.name+2);
00893         }
00894         
00895         /* perform action if valid channel */
00896         if (datalevel == TSE_ANIM_DATA)
00897                 outliner_do_id_set_operation(soops, datalevel, &soops->tree, (ID*)act, actionset_id_cb);
00898         else if (idlevel == ID_AC)
00899                 outliner_do_id_set_operation(soops, idlevel, &soops->tree, (ID*)act, actionset_id_cb);
00900         else
00901                 return OPERATOR_CANCELLED;
00902                 
00903         /* set notifier that things have changed */
00904         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
00905         ED_undo_push(C, "Set action");
00906         
00907         /* done */
00908         return OPERATOR_FINISHED;
00909 }
00910 
00911 void OUTLINER_OT_action_set(wmOperatorType *ot)
00912 {
00913         PropertyRNA *prop;
00914 
00915         /* identifiers */
00916         ot->name= "Outliner Set Action";
00917         ot->idname= "OUTLINER_OT_action_set";
00918         ot->description= "Change the active action used";
00919         
00920         /* api callbacks */
00921         ot->invoke= WM_enum_search_invoke;
00922         ot->exec= outliner_action_set_exec;
00923         ot->poll= ED_operator_outliner_active;
00924         
00925         /* flags */
00926         ot->flag= 0;
00927         
00928         /* props */
00929                 // TODO: this would be nicer as an ID-pointer...
00930         prop= RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
00931         RNA_def_enum_funcs(prop, RNA_action_itemf);
00932         ot->prop= prop;
00933 }
00934 
00935 #endif // GSOC_PEPPER
00936 
00937 /* **************************************** */
00938 
00939 typedef enum eOutliner_AnimDataOps {
00940         OUTLINER_ANIMOP_INVALID = 0,
00941         
00942         OUTLINER_ANIMOP_SET_ACT,
00943         OUTLINER_ANIMOP_CLEAR_ACT,
00944         
00945         OUTLINER_ANIMOP_REFRESH_DRV,
00946         OUTLINER_ANIMOP_CLEAR_DRV
00947         
00948         //OUTLINER_ANIMOP_COPY_DRIVERS,
00949         //OUTLINER_ANIMOP_PASTE_DRIVERS
00950 } eOutliner_AnimDataOps;
00951 
00952 static EnumPropertyItem prop_animdata_op_types[] = {
00953         {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""},
00954         {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
00955         {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
00956         //{OUTLINER_ANIMOP_COPY_DRIVERS, "COPY_DRIVERS", 0, "Copy Drivers", ""},
00957         //{OUTLINER_ANIMOP_PASTE_DRIVERS, "PASTE_DRIVERS", 0, "Paste Drivers", ""},
00958         {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
00959         {0, NULL, 0, NULL, NULL}
00960 };
00961 
00962 static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
00963 {
00964         SpaceOops *soops= CTX_wm_space_outliner(C);
00965         int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0;
00966         eOutliner_AnimDataOps event;
00967         short updateDeps = 0;
00968         
00969         /* check for invalid states */
00970         if (soops == NULL)
00971                 return OPERATOR_CANCELLED;
00972         
00973         event= RNA_enum_get(op->ptr, "type");
00974         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
00975         
00976         if (datalevel != TSE_ANIM_DATA)
00977                 return OPERATOR_CANCELLED;
00978         
00979         /* perform the core operation */
00980         switch (event) {
00981 
00982 #if 0 // GSOC_PEPPER
00983 
00984                 case OUTLINER_ANIMOP_SET_ACT:
00985                         /* delegate once again... */
00986                         WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
00987                         break;
00988                 
00989                 case OUTLINER_ANIMOP_CLEAR_ACT:
00990                         /* clear active action - using standard rules */
00991                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, unlinkact_animdata_cb);
00992                         
00993                         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
00994                         ED_undo_push(C, "Unlink action");
00995                         break;
00996                         
00997 #endif // GSOC_PEPPER
00998 
00999                 case OUTLINER_ANIMOP_REFRESH_DRV:
01000                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, refreshdrivers_animdata_cb);
01001                         
01002                         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN, NULL);
01003                         //ED_undo_push(C, "Refresh Drivers"); /* no undo needed - shouldn't have any impact? */
01004                         updateDeps = 1;
01005                         break;
01006                         
01007                 case OUTLINER_ANIMOP_CLEAR_DRV:
01008                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, cleardrivers_animdata_cb);
01009                         
01010                         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN, NULL);
01011                         ED_undo_push(C, "Clear Drivers");
01012                         updateDeps = 1;
01013                         break;
01014                         
01015                 default: // invalid
01016                         break;
01017         }
01018         
01019         /* update dependencies */
01020         if (updateDeps) {
01021                 Main *bmain = CTX_data_main(C);
01022                 Scene *scene = CTX_data_scene(C);
01023                 
01024                 /* rebuild depsgraph for the new deps */
01025                 DAG_scene_sort(bmain, scene);
01026                 
01027                 /* force an update of depsgraph */
01028                 DAG_ids_flush_update(bmain, 0);
01029         }
01030         
01031         return OPERATOR_FINISHED;
01032 }
01033 
01034 
01035 void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
01036 {
01037         /* identifiers */
01038         ot->name= "Outliner Animation Data Operation";
01039         ot->idname= "OUTLINER_OT_animdata_operation";
01040         ot->description= "";
01041         
01042         /* callbacks */
01043         ot->invoke= WM_menu_invoke;
01044         ot->exec= outliner_animdata_operation_exec;
01045         ot->poll= ED_operator_outliner_active;
01046         
01047         ot->flag= 0;
01048         
01049         ot->prop= RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
01050 }
01051 
01052 /* **************************************** */
01053 
01054 static EnumPropertyItem prop_data_op_types[] = {
01055         {1, "SELECT", 0, "Select", ""},
01056         {2, "DESELECT", 0, "Deselect", ""},
01057         {3, "HIDE", 0, "Hide", ""},
01058         {4, "UNHIDE", 0, "Unhide", ""},
01059         {0, NULL, 0, NULL, NULL}
01060 };
01061 
01062 static int outliner_data_operation_exec(bContext *C, wmOperator *op)
01063 {
01064         SpaceOops *soops= CTX_wm_space_outliner(C);
01065         int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0;
01066         int event;
01067         
01068         /* check for invalid states */
01069         if (soops == NULL)
01070                 return OPERATOR_CANCELLED;
01071         
01072         event= RNA_enum_get(op->ptr, "type");
01073         set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
01074         
01075         if(datalevel==TSE_POSE_CHANNEL) {
01076                 if(event>0) {
01077                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb);
01078                         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL);
01079                         ED_undo_push(C, "PoseChannel operation");
01080                 }
01081         }
01082         else if(datalevel==TSE_BONE) {
01083                 if(event>0) {
01084                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb);
01085                         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL);
01086                         ED_undo_push(C, "Bone operation");
01087                 }
01088         }
01089         else if(datalevel==TSE_EBONE) {
01090                 if(event>0) {
01091                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb);
01092                         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL);
01093                         ED_undo_push(C, "EditBone operation");
01094                 }
01095         }
01096         else if(datalevel==TSE_SEQUENCE) {
01097                 if(event>0) {
01098                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, sequence_cb);
01099                 }
01100         }
01101         
01102         return OPERATOR_FINISHED;
01103 }
01104 
01105 
01106 void OUTLINER_OT_data_operation(wmOperatorType *ot)
01107 {
01108         /* identifiers */
01109         ot->name= "Outliner Data Operation";
01110         ot->idname= "OUTLINER_OT_data_operation";
01111         ot->description= "";
01112         
01113         /* callbacks */
01114         ot->invoke= WM_menu_invoke;
01115         ot->exec= outliner_data_operation_exec;
01116         ot->poll= ED_operator_outliner_active;
01117         
01118         ot->flag= 0;
01119         
01120         ot->prop= RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", "");
01121 }
01122 
01123 
01124 /* ******************** */
01125 
01126 
01127 static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, wmEvent *event, const float mval[2])
01128 {
01129         ReportList *reports = CTX_wm_reports(C); // XXX...
01130         
01131         if(mval[1]>te->ys && mval[1]<te->ys+UI_UNIT_Y) {
01132                 int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0;
01133                 TreeStoreElem *tselem= TREESTORE(te);
01134                 
01135                 /* select object that's clicked on and popup context menu */
01136                 if (!(tselem->flag & TSE_SELECTED)) {
01137                         
01138                         if ( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1) )
01139                                 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
01140                         
01141                         tselem->flag |= TSE_SELECTED;
01142                         /* redraw, same as outliner_select function */
01143                         soops->storeflag |= SO_TREESTORE_REDRAW;
01144                         ED_region_tag_redraw(ar);
01145                 }
01146                 
01147                 set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
01148                 
01149                 if(scenelevel) {
01150                         //if(objectlevel || datalevel || idlevel) error("Mixed selection");
01151                         //else pupmenu("Scene Operations%t|Delete");
01152                 }
01153                 else if(objectlevel) {
01154                         WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
01155                 }
01156                 else if(idlevel) {
01157                         if(idlevel==-1 || datalevel) BKE_report(reports, RPT_WARNING, "Mixed selection");
01158                         else {
01159                                 if (idlevel==ID_GR)
01160                                         WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
01161                                 else
01162                                         WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL);
01163                         }
01164                 }
01165                 else if(datalevel) {
01166                         if(datalevel==-1) BKE_report(reports, RPT_WARNING, "Mixed selection");
01167                         else {
01168                                 if (datalevel == TSE_ANIM_DATA)
01169                                         WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL);
01170                                 else if (datalevel == TSE_DRIVER_BASE)
01171                                         /* do nothing... no special ops needed yet */;
01172                                 else
01173                                         WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
01174                         }
01175                 }
01176                 
01177                 return 1;
01178         }
01179         
01180         for(te= te->subtree.first; te; te= te->next) {
01181                 if(do_outliner_operation_event(C, scene, ar, soops, te, event, mval)) 
01182                         return 1;
01183         }
01184         return 0;
01185 }
01186 
01187 
01188 static int outliner_operation(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
01189 {
01190         Scene *scene= CTX_data_scene(C);
01191         ARegion *ar= CTX_wm_region(C);
01192         SpaceOops *soops= CTX_wm_space_outliner(C);
01193         TreeElement *te;
01194         float fmval[2];
01195         
01196         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval+1);
01197         
01198         for(te= soops->tree.first; te; te= te->next) {
01199                 if(do_outliner_operation_event(C, scene, ar, soops, te, event, fmval)) break;
01200         }
01201         
01202         return OPERATOR_FINISHED;
01203 }
01204 
01205 /* Menu only! Calls other operators */
01206 void OUTLINER_OT_operation(wmOperatorType *ot)
01207 {
01208         ot->name= "Execute Operation";
01209         ot->idname= "OUTLINER_OT_operation";
01210         ot->description= "Context menu for item operations";
01211         
01212         ot->invoke= outliner_operation;
01213         
01214         ot->poll= ED_operator_outliner_active;
01215 }
01216 
01217 /* ****************************************************** */