Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / animation / anim_channels_edit.c
index 341e27a12bf5587f511308f620e8e97136c44fbf..20e5bec44a37b188e19d4c9aed57ee5b60b59849 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "BKE_depsgraph.h"
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
 #include "BLI_listbase.h"
@@ -49,6 +50,7 @@
 #include "RNA_access.h"
 #include "RNA_define.h"
 
+#include "BKE_animsys.h"
 #include "BKE_action.h"
 #include "BKE_fcurve.h"
 #include "BKE_gpencil.h"
@@ -74,7 +76,7 @@
 
 /* Set the given animation-channel as the active one for the active context */
 // TODO: extend for animdata types...
-void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
+void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type)
 {
        ListBase anim_data = {NULL, NULL};
        bAnimListElem *ale;
@@ -100,6 +102,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                                break;
                        }
                        case ANIMTYPE_FCURVE:
+                       case ANIMTYPE_NLACURVE:
                        {
                                FCurve *fcu = (FCurve *)ale->data;
                                
@@ -117,10 +120,10 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                        case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                        case ANIMTYPE_DSLAM:
                        case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCACHEFILE:
                        case ANIMTYPE_DSCUR:
                        case ANIMTYPE_DSSKEY:
                        case ANIMTYPE_DSWOR:
-                       case ANIMTYPE_DSPART:
                        case ANIMTYPE_DSMBALL:
                        case ANIMTYPE_DSARM:
                        case ANIMTYPE_DSMESH:
@@ -128,6 +131,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                        case ANIMTYPE_DSLAT:
                        case ANIMTYPE_DSLINESTYLE:
                        case ANIMTYPE_DSSPK:
+                       case ANIMTYPE_DSGPENCIL:
                        {
                                /* need to verify that this data is valid for now */
                                if (ale->adt) {
@@ -135,6 +139,13 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                                }
                                break;
                        }
+                       case ANIMTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl = (bGPDlayer *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE);
+                               break;
+                       }
                }
        }
        
@@ -148,6 +159,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                                break;
                        }
                        case ANIMTYPE_FCURVE:
+                       case ANIMTYPE_NLACURVE:
                        {
                                FCurve *fcu = (FCurve *)channel_data;
                                fcu->flag |= FCURVE_ACTIVE;
@@ -163,16 +175,19 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                        case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                        case ANIMTYPE_DSLAM:
                        case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCACHEFILE:
                        case ANIMTYPE_DSCUR:
                        case ANIMTYPE_DSSKEY:
                        case ANIMTYPE_DSWOR:
-                       case ANIMTYPE_DSPART:
                        case ANIMTYPE_DSMBALL:
                        case ANIMTYPE_DSARM:
                        case ANIMTYPE_DSMESH:
                        case ANIMTYPE_DSLAT:
                        case ANIMTYPE_DSLINESTYLE:
                        case ANIMTYPE_DSSPK:
+                       case ANIMTYPE_DSNTREE:
+                       case ANIMTYPE_DSTEX:
+                       case ANIMTYPE_DSGPENCIL:
                        {
                                /* need to verify that this data is valid for now */
                                if (ale && ale->adt) {
@@ -180,11 +195,28 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                                }
                                break;
                        }
+                       
+                       case ANIMTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl = (bGPDlayer *)channel_data;
+                               gpl->flag |= GP_LAYER_ACTIVE;
+                               break;
+                       }
+                       
+                       /* unhandled currently, but may be interesting */
+                       case ANIMTYPE_MASKLAYER:
+                       case ANIMTYPE_SHAPEKEY:
+                       case ANIMTYPE_NLAACTION:
+                               break;
+                       
+                       /* other types */
+                       default:
+                               break;
                }
        }
        
        /* clean up */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
 }
 
 /* Deselect all animation channels 
@@ -193,7 +225,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
  *     - test: check if deselecting instead of selecting
  *     - sel: eAnimChannels_SetFlag;
  */
-void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, short test, short sel)
+void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types datatype, bool test, eAnimChannels_SetFlag sel)
 {
        ListBase anim_data = {NULL, NULL};
        bAnimListElem *ale;
@@ -226,6 +258,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                                                sel = ACHANNEL_SETFLAG_CLEAR;
                                        break;
                                case ANIMTYPE_FCURVE:
+                               case ANIMTYPE_NLACURVE:
                                        if (ale->flag & FCURVE_SELECTED)
                                                sel = ACHANNEL_SETFLAG_CLEAR;
                                        break;
@@ -242,10 +275,10 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                                case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                                case ANIMTYPE_DSLAM:
                                case ANIMTYPE_DSCAM:
+                               case ANIMTYPE_DSCACHEFILE:
                                case ANIMTYPE_DSCUR:
                                case ANIMTYPE_DSSKEY:
                                case ANIMTYPE_DSWOR:
-                               case ANIMTYPE_DSPART:
                                case ANIMTYPE_DSMBALL:
                                case ANIMTYPE_DSARM:
                                case ANIMTYPE_DSMESH:
@@ -254,6 +287,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                                case ANIMTYPE_DSLAT:
                                case ANIMTYPE_DSLINESTYLE:
                                case ANIMTYPE_DSSPK:
+                               case ANIMTYPE_DSGPENCIL:
                                {
                                        if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
                                                sel = ACHANNEL_SETFLAG_CLEAR;
@@ -309,6 +343,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                                break;
                        }
                        case ANIMTYPE_FCURVE:
+                       case ANIMTYPE_NLACURVE:
                        {
                                FCurve *fcu = (FCurve *)ale->data;
                                
@@ -335,10 +370,10 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                        case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                        case ANIMTYPE_DSLAM:
                        case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCACHEFILE:
                        case ANIMTYPE_DSCUR:
                        case ANIMTYPE_DSSKEY:
                        case ANIMTYPE_DSWOR:
-                       case ANIMTYPE_DSPART:
                        case ANIMTYPE_DSMBALL:
                        case ANIMTYPE_DSARM:
                        case ANIMTYPE_DSMESH:
@@ -347,6 +382,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                        case ANIMTYPE_DSLAT:
                        case ANIMTYPE_DSLINESTYLE:
                        case ANIMTYPE_DSSPK:
+                       case ANIMTYPE_DSGPENCIL:
                        {
                                /* need to verify that this data is valid for now */
                                if (ale->adt) {
@@ -373,7 +409,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
        }
        
        /* Cleanup */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
 }
 
 /* ---------------------------- Graph Editor ------------------------------------- */
@@ -387,7 +423,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
  *     - setting: type of setting to set
  *     - on: whether the visibility setting has been enabled or disabled 
  */
-void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short on)
+void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
 {
        bAnimListElem *ale, *match = NULL;
        int prevLevel = 0, matchLevel = 0;
@@ -413,7 +449,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
                return;
        }
        else {
-               bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
+               const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
                
                if (acf == NULL) {
                        printf("ERROR: no channel info for the changed channel\n");
@@ -437,12 +473,12 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
         *      - only flush up if the current state is now disabled (negative 'off' state is default)
         *        (otherwise, it's too much work to force the parents to be active too)
         */
-       if ( ((setting == ACHANNEL_SETTING_VISIBLE) && on) ||
-            ((setting != ACHANNEL_SETTING_VISIBLE) && on == 0) )
+       if ( ((setting == ACHANNEL_SETTING_VISIBLE) && (mode != ACHANNEL_SETFLAG_CLEAR)) ||
+            ((setting != ACHANNEL_SETTING_VISIBLE) && (mode == ACHANNEL_SETFLAG_CLEAR)))
        {
                /* go backwards in the list, until the highest-ranking element (by indention has been covered) */
                for (ale = match->prev; ale; ale = ale->prev) {
-                       bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+                       const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
                        int level;
                        
                        /* if no channel info was found, skip, since this type might not have any useful info */
@@ -461,7 +497,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
                         */
                        if (level < prevLevel) {
                                /* flush the new status... */
-                               ANIM_channel_setting_set(ac, ale, setting, on);
+                               ANIM_channel_setting_set(ac, ale, setting, mode);
                                
                                /* store this level as the 'old' level now */
                                prevLevel = level;
@@ -486,7 +522,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
        {
                /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
                for (ale = match->next; ale; ale = ale->next) {
-                       bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+                       const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
                        int level;
                        
                        /* if no channel info was found, skip, since this type might not have any useful info */
@@ -502,7 +538,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
                         * flush the new status...
                         */
                        if (level > matchLevel)
-                               ANIM_channel_setting_set(ac, ale, setting, on);
+                               ANIM_channel_setting_set(ac, ale, setting, mode);
                        /* however, if the level is 'less than or equal to' the channel that was changed,
                         * (i.e. the current channel is as important if not more important than the changed channel)
                         * then we should stop, since we've found the last one of the children we should flush
@@ -591,7 +627,7 @@ static int animedit_poll_channels_active(bContext *C)
        if (ELEM(NULL, sa, CTX_wm_region(C)))
                return 0;
        /* animation editor test */
-       if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
+       if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
                return 0;
 
        return 1;
@@ -608,7 +644,7 @@ static int animedit_poll_channels_nla_tweakmode_off(bContext *C)
        if (ELEM(NULL, sa, CTX_wm_region(C)))
                return 0;
        /* animation editor test */
-       if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
+       if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
                return 0;
        
        /* NLA TweakMode test */
@@ -623,13 +659,13 @@ static int animedit_poll_channels_nla_tweakmode_off(bContext *C)
 /* ****************** Rearrange Channels Operator ******************* */
 
 /* constants for channel rearranging */
-/* WARNING: don't change exising ones without modifying rearrange func accordingly */
-enum {
+/* WARNING: don't change existing ones without modifying rearrange func accordingly */
+typedef enum eRearrangeAnimChan_Mode {
        REARRANGE_ANIMCHAN_TOP = -2,
        REARRANGE_ANIMCHAN_UP = -1,
        REARRANGE_ANIMCHAN_DOWN = 1,
        REARRANGE_ANIMCHAN_BOTTOM = 2
-};
+} eRearrangeAnimChan_Mode;
 
 /* defines for rearranging channels */
 static EnumPropertyItem prop_animchannel_rearrange_types[] = {
@@ -733,13 +769,13 @@ static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
                                /* push it down */
                                BLI_insertlinkafter(list, next, island);
                                
-                               return 1;
+                               return true;
                        }
                }
                /* else: no next channel, so we're at the bottom already, so can't move */
        }
        
-       return 0;
+       return false;
 }
 
 static bool rearrange_island_bottom(ListBase *list, tReorderChannelIsland *island)
@@ -761,23 +797,25 @@ static bool rearrange_island_bottom(ListBase *list, tReorderChannelIsland *islan
                        
                }
                
-               return 1;
+               return true;
        }
        
-       return 0;
+       return false;
 }
 
 /* ............................. */
 
-/* typedef for channel rearranging function 
- * < list: list that channels belong to
- * < island: island to be moved
- * > return[0]: whether operation was a success
+/**
+ * typedef for channel rearranging function
+ *
+ * \param list List of tReorderChannelIsland's that channels belong to
+ * \param island Island to be moved
+ * \return Whether operation was a success
  */
 typedef bool (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island);
 
 /* get rearranging function, given 'rearrange' mode */
-static AnimChanRearrangeFp rearrange_get_mode_func(short mode)
+static AnimChanRearrangeFp rearrange_get_mode_func(eRearrangeAnimChan_Mode mode)
 {
        switch (mode) {
                case REARRANGE_ANIMCHAN_TOP:
@@ -796,7 +834,9 @@ static AnimChanRearrangeFp rearrange_get_mode_func(short mode)
 /* Rearrange Islands Generics ------------------------------------- */
 
 /* add channel into list of islands */
-static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList, Link *channel, short type, const bool is_hidden)
+static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList,
+                                                 Link *channel, eAnim_ChannelType type,
+                                                 const bool is_hidden)
 {
        tReorderChannelIsland *island = islands->last;  /* always try to add to last island if possible */
        bool is_sel = false, is_untouchable = false;
@@ -812,6 +852,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
                        break;
                }
                case ANIMTYPE_FCURVE:
+               case ANIMTYPE_NLACURVE:
                {
                        FCurve *fcu = (FCurve *)channel;
                        
@@ -825,8 +866,15 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
                        is_sel = SEL_NLT(nlt);
                        break;
                }
+               case ANIMTYPE_GPLAYER:
+               {
+                       bGPDlayer *gpl = (bGPDlayer *)channel;
+                       
+                       is_sel = SEL_GPL(gpl);
+                       break;
+               }
                default:
-                       printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
+                       printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", type);
                        return;
        }
        
@@ -839,7 +887,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
            (is_sel == 0) ||
            /* 4) hidden status changes */
            ((island->flag & REORDER_ISLAND_HIDDEN) != is_hidden)
-          )
+           )
        {
                /* create a new island now */
                island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland");
@@ -878,16 +926,33 @@ static void rearrange_animchannel_flatten_islands(ListBase *islands, ListBase *s
 
 /* ............................. */
 
-static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, short type)
+/* get a list of all bAnimListElem's of a certain type which are currently visible */
+static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, eAnim_ChannelType type)
 {
-    int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
-
-    ANIM_animdata_filter(ac, anim_data_visible, filter, ac->data, type);
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale, *ale_next;
+       int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+       
+       /* get all visible channels */
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* now, only keep the ones that are of the types we are interested in */
+       for (ale = anim_data.first; ale; ale = ale_next) {
+               ale_next = ale->next;
+               
+               if (ale->type != type) {
+                       BLI_freelinkN(&anim_data, ale);
+               }
+       }
+       
+       /* return cleaned up list */
+       *anim_data_visible = anim_data;
 }
 
 /* performing rearranging of channels using islands */
 static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp rearrange_func,
-                                          short mode, short type, ListBase *anim_data_visible)
+                                          eRearrangeAnimChan_Mode mode, eAnim_ChannelType type,
+                                          ListBase *anim_data_visible)
 {
        ListBase islands = {NULL, NULL};
        Link *channel, *chanNext = NULL;
@@ -937,7 +1002,7 @@ static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp re
  * ! NLA tracks are displayed in opposite order, so directions need care
  *     mode: REARRANGE_ANIMCHAN_*  
  */
-static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, short mode)
+static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
 {
        AnimChanRearrangeFp rearrange_func;
        ListBase anim_data_visible = {NULL, NULL};
@@ -950,10 +1015,6 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, short mode)
        if (rearrange_func == NULL)
                return;
        
-       /* only consider NLA data if it's accessible */
-       //if (EXPANDED_DRVD(adt) == 0)
-       //      return;
-       
        /* Filter visible data. */
        rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK);
        
@@ -969,7 +1030,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, short mode)
 /* Change the order drivers within AnimData block
  *     mode: REARRANGE_ANIMCHAN_*  
  */
-static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, short mode)
+static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
 {
        /* get rearranging function */
        AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
@@ -1035,6 +1096,13 @@ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp)
                fcu->next = NULL;
                tgrp->channels.last = fcu;
                act->curves.last = NULL;
+               
+               /* ensure that all of these get their group set to this temp group 
+                * (so that visibility filtering works)
+                */
+               for (fcu = tgrp->channels.first; fcu; fcu = fcu->next) {
+                       fcu->grp = tgrp;
+               }
        }
        
        /* Add temp-group to list */
@@ -1057,8 +1125,17 @@ static void join_groups_action_temp(bAction *act)
                /* clear moved flag */
                agrp->flag &= ~AGRP_MOVED;
                
-               /* if temp-group... remove from list (but don't free as it's on the stack!) */
+               /* if group was temporary one:
+                * - unassign all FCurves which were temporarily added to it
+                * - remove from list (but don't free as it's on the stack!)
+                */
                if (agrp->flag & AGRP_TEMP) {
+                       FCurve *fcu;
+                       
+                       for (fcu = agrp->channels.first; fcu; fcu = fcu->next) {
+                               fcu->grp = NULL;
+                       }
+                       
                        BLI_remlink(&act->groups, agrp);
                        break;
                }
@@ -1068,7 +1145,7 @@ static void join_groups_action_temp(bAction *act)
 /* Change the order of anim-channels within action 
  *     mode: REARRANGE_ANIMCHAN_*  
  */
-static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode)
+static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrangeAnimChan_Mode mode)
 {
        bActionGroup tgrp;
        ListBase anim_data_visible = {NULL, NULL};
@@ -1120,10 +1197,85 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode
 
 /* ------------------- */
 
+static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
+{
+       ListBase anim_data_visible = {NULL, NULL};
+       
+       NlaTrack *nlt;
+       NlaStrip *strip;
+       
+       /* get rearranging function */
+       AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+       
+       if (rearrange_func == NULL)
+               return;
+               
+       /* skip if these curves aren't being shown */
+       if (adt->flag & ADT_NLA_SKEYS_COLLAPSED)
+               return;
+       
+       /* Filter visible data. */
+       rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE);
+       
+       /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
+       for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+               for (strip = nlt->strips.first; strip; strip = strip->next) {
+                       rearrange_animchannel_islands(&strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE,
+                                                         &anim_data_visible);
+               }
+       }
+       
+       /* free temp data */
+       BLI_freelistN(&anim_data_visible);
+}
+
+/* ------------------- */
+
+static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* get rearranging function */
+       AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+       
+       if (rearrange_func == NULL)
+               return;
+       
+       /* get Grease Pencil datablocks */
+       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       for (ale = anim_data.first; ale; ale = ale->next) {
+               ListBase anim_data_visible = {NULL, NULL};
+               bGPdata *gpd = ale->data;
+               
+               /* only consider layers if this datablock is open */
+               BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK);
+               if ((gpd->flag & GP_DATA_EXPAND) == 0)
+                       continue;
+               
+               /* Filter visible data. */
+               rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER);
+               
+               /* rearrange datablock's layers */
+               rearrange_animchannel_islands(&gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible);
+               
+               /* free visible layers data */
+               BLI_freelistN(&anim_data_visible);
+       }
+       
+       /* free GPD channel data */
+       ANIM_animdata_freelist(&anim_data);
+}
+
+/* ------------------- */
+
 static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
-       short mode;
+       eRearrangeAnimChan_Mode mode;
        
        /* get editor data */
        if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1135,7 +1287,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
        /* method to move channels depends on the editor */
        if (ac.datatype == ANIMCONT_GPENCIL) {
                /* Grease Pencil channels */
-               printf("Grease Pencil not supported for moving yet\n");
+               rearrange_gpencil_channels(&ac, mode);
        }
        else if (ac.datatype == ANIMCONT_MASK) {
                /* Grease Pencil channels */
@@ -1166,18 +1318,34 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
                                        rearrange_driver_channels(&ac, adt, mode);
                                        break;
                                
+                               case ANIMCONT_ACTION: /* Single Action only... */
                                case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
-                               default: /* some collection of actions */
+                               {
+                                       if (adt->action)
+                                               rearrange_action_channels(&ac, adt->action, mode);
+                                       else if (G.debug & G_DEBUG)
+                                               printf("Animdata has no action\n");
+                                       break;
+                               }
+                               
+                               default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
+                               {
+                                       /* NLA Control Curves */
+                                       if (adt->nla_tracks.first)
+                                               rearrange_nla_control_channels(&ac, adt, mode);
+                                       
+                                       /* Action */
                                        if (adt->action)
                                                rearrange_action_channels(&ac, adt->action, mode);
                                        else if (G.debug & G_DEBUG)
                                                printf("Animdata has no action\n");
                                        break;
+                               }
                        }
                }
                
                /* free temp data */
-               BLI_freelistN(&anim_data);
+               ANIM_animdata_freelist(&anim_data);
        }
        
        /* send notifier that things have changed */
@@ -1228,9 +1396,9 @@ static int animchannels_grouping_poll(bContext *C)
                        /* dopesheet and action only - all others are for other datatypes or have no groups */
                        if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0)
                                return 0;
-               }
+
                        break;
-                       
+               }
                case SPACE_IPO:
                {
                        SpaceIpo *sipo = (SpaceIpo *)sl;
@@ -1238,9 +1406,9 @@ static int animchannels_grouping_poll(bContext *C)
                        /* drivers can't have groups... */
                        if (sipo->mode != SIPO_MODE_ANIMATION)
                                return 0;
-               }
+
                        break;
-                       
+               }
                /* unsupported... */
                default:
                        return 0;
@@ -1290,7 +1458,7 @@ static void animchannels_group_channels(bAnimContext *ac, bAnimListElem *adt_ref
                }
                
                /* cleanup */
-               BLI_freelistN(&anim_data);
+               ANIM_animdata_freelist(&anim_data);
        }
 }
 
@@ -1321,7 +1489,7 @@ static int animchannels_group_exec(bContext *C, wmOperator *op)
                }
                
                /* free temp data */
-               BLI_freelistN(&anim_data);
+               ANIM_animdata_freelist(&anim_data);
                
                /* updatss */
                WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1393,7 +1561,7 @@ static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op))
        }
        
        /* cleanup */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
        
        /* updates */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1470,7 +1638,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
                }
                
                /* cleanup */
-               BLI_freelistN(&anim_data);
+               ANIM_animdata_freelist(&anim_data);
        }
        
        /* filter data */
@@ -1490,6 +1658,27 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
                                ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
                                break;
                        }
+                       case ANIMTYPE_NLACURVE:
+                       {
+                               /* NLA Control Curve - Deleting it should disable the corresponding setting... */
+                               NlaStrip *strip = (NlaStrip *)ale->owner;
+                               FCurve *fcu = (FCurve *)ale->data;
+                               
+                               if (STREQ(fcu->rna_path, "strip_time")) {
+                                       strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
+                               }
+                               else if (STREQ(fcu->rna_path, "influence")) {
+                                       strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
+                               }
+                               else {
+                                       printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path);
+                               }
+                               
+                               /* unlink and free the F-Curve */
+                               BLI_remlink(&strip->fcurves, fcu);
+                               free_fcurve(fcu);
+                               break;
+                       }
                        case ANIMTYPE_GPLAYER:
                        {
                                /* Grease Pencil layer */
@@ -1497,7 +1686,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
                                bGPDlayer *gpl = (bGPDlayer *)ale->data;
                                
                                /* try to delete the layer's data and the layer itself */
-                               free_gpencil_frames(gpl);
+                               BKE_gpencil_free_frames(gpl);
                                BLI_freelinkN(&gpd->layers, gpl);
                                break;
                        }
@@ -1515,11 +1704,12 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
        }
        
        /* cleanup */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-       
+       DAG_relations_tag_update(CTX_data_main(C));
+
        return OPERATOR_FINISHED;
 }
  
@@ -1538,175 +1728,6 @@ static void ANIM_OT_channels_delete(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
-/* ******************** Set Channel Visibility Operator *********************** */
-/* NOTE: this operator is only valid in the Graph Editor channels region */
-
-static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op))
-{
-       bAnimContext ac;
-       ListBase anim_data = {NULL, NULL};
-       ListBase all_data = {NULL, NULL};
-       bAnimListElem *ale;
-       int filter;
-       
-       /* get editor data */
-       if (ANIM_animdata_get_context(C, &ac) == 0)
-               return OPERATOR_CANCELLED;
-       
-       /* get list of all channels that selection may need to be flushed to 
-        * - hierarchy mustn't affect what we have access to here...
-        */
-       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
-       ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
-               
-       /* hide all channels not selected
-        * - hierarchy matters if we're doing this from the channels region
-        *   since we only want to apply this to channels we can "see", 
-        *   and have these affect their relatives
-        * - but for Graph Editor, this gets used also from main region
-        *   where hierarchy doesn't apply, as for [#21276]
-        */
-       if ((ac.spacetype == SPACE_IPO) && (ac.regiontype != RGN_TYPE_CHANNELS)) {
-               /* graph editor (case 2) */
-               filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
-       }
-       else {
-               /* standard case */
-               filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS);
-       }
-       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-       
-       for (ale = anim_data.first; ale; ale = ale->next) {
-               /* clear setting first */
-               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
-               
-               /* now also flush selection status as appropriate 
-                * NOTE: in some cases, this may result in repeat flushing being performed
-                */
-               ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
-       }
-       
-       BLI_freelistN(&anim_data);
-       
-       /* make all the selected channels visible */
-       filter = (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
-       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
-       for (ale = anim_data.first; ale; ale = ale->next) {
-               /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
-               /* TODO: find out why this is the case, and fix that */
-               if (ale->type == ANIMTYPE_OBJECT)
-                       continue;
-               
-               /* enable the setting */
-               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
-               
-               /* now, also flush selection status up/down as appropriate */
-               ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
-       }
-       
-       BLI_freelistN(&anim_data);
-       BLI_freelistN(&all_data);
-       
-       
-       /* send notifier that things have changed */
-       WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-       
-       return OPERATOR_FINISHED;
-}
-
-static void ANIM_OT_channels_visibility_set(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name = "Set Visibility";
-       ot->idname = "ANIM_OT_channels_visibility_set";
-       ot->description = "Make only the selected animation channels visible in the Graph Editor";
-       
-       /* api callbacks */
-       ot->exec = animchannels_visibility_set_exec;
-       ot->poll = ED_operator_graphedit_active;
-       
-       /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* ******************** Toggle Channel Visibility Operator *********************** */
-/* NOTE: this operator is only valid in the Graph Editor channels region */
-
-static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
-       bAnimContext ac;
-       ListBase anim_data = {NULL, NULL};
-       ListBase all_data = {NULL, NULL};
-       bAnimListElem *ale;
-       int filter;
-       short vis = ACHANNEL_SETFLAG_ADD;
-       
-       /* get editor data */
-       if (ANIM_animdata_get_context(C, &ac) == 0)
-               return OPERATOR_CANCELLED;
-               
-       /* get list of all channels that selection may need to be flushed to 
-        * - hierarchy mustn't affect what we have access to here...
-        */
-       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
-       ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
-               
-       /* filter data
-        * - restrict this to only applying on settings we can get to in the list
-        */
-       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
-       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-       
-       /* See if we should be making showing all selected or hiding */
-       for (ale = anim_data.first; ale; ale = ale->next) {
-               /* set the setting in the appropriate way (if available) */
-               if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) {
-                       vis = ACHANNEL_SETFLAG_CLEAR;
-                       break;
-               }
-       }
-
-       /* Now set the flags */
-       for (ale = anim_data.first; ale; ale = ale->next) {
-               /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
-               /* TODO: find out why this is the case, and fix that */
-               if (ale->type == ANIMTYPE_OBJECT)
-                       continue;
-               
-               /* change the setting */
-               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
-               
-               /* now, also flush selection status up/down as appropriate */
-               ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
-       }
-       
-       /* cleanup */
-       BLI_freelistN(&anim_data);
-       BLI_freelistN(&all_data);
-       
-       /* send notifier that things have changed */
-       WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-       
-       return OPERATOR_FINISHED;
-}
-
-static void ANIM_OT_channels_visibility_toggle(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name = "Toggle Visibility";
-       ot->idname = "ANIM_OT_channels_visibility_toggle";
-       ot->description = "Toggle visibility in Graph Editor of all selected animation channels";
-       
-       /* api callbacks */
-       ot->exec = animchannels_visibility_toggle_exec;
-       ot->poll = ED_operator_graphedit_active;
-       
-       /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
 /* ********************** Set Flags Operator *********************** */
 
 /* defines for setting animation-channel flags */
@@ -1735,7 +1756,7 @@ static EnumPropertyItem prop_animchannel_settings_types[] = {
  *     onlysel: only selected channels get the flag set
  */
 // TODO: enable a setting which turns flushing on/off?
-static void setflag_anim_channels(bAnimContext *ac, short setting, short mode, short onlysel, short flush)
+static void setflag_anim_channels(bAnimContext *ac, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode, bool onlysel, bool flush)
 {
        ListBase anim_data = {NULL, NULL};
        ListBase all_data = {NULL, NULL};
@@ -1799,7 +1820,7 @@ static void setflag_anim_channels(bAnimContext *ac, short setting, short mode, s
                        ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
        }
        
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
        BLI_freelistN(&all_data);
 }
 
@@ -1808,8 +1829,9 @@ static void setflag_anim_channels(bAnimContext *ac, short setting, short mode, s
 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
-       short mode, setting;
-       short flush = 1;
+       eAnimChannel_Settings setting;
+       eAnimChannels_SetFlag mode;
+       bool flush = true;
        
        /* get editor data */
        if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1821,12 +1843,12 @@ static int animchannels_setflag_exec(bContext *C, wmOperator *op)
        
        /* check if setting is flushable */
        if (setting == ACHANNEL_SETTING_EXPAND)
-               flush = 0;
+               flush = false;
        
        /* modify setting 
         *      - only selected channels are affected
         */
-       setflag_anim_channels(&ac, setting, mode, 1, flush);
+       setflag_anim_channels(&ac, setting, mode, true, flush);
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1939,7 +1961,7 @@ static void ANIM_OT_channels_editable_toggle(wmOperatorType *ot)
 static int animchannels_expand_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
-       short onlysel = 1;
+       bool onlysel = true;
        
        /* get editor data */
        if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1947,10 +1969,10 @@ static int animchannels_expand_exec(bContext *C, wmOperator *op)
                
        /* only affect selected channels? */
        if (RNA_boolean_get(op->ptr, "all"))
-               onlysel = 0;
+               onlysel = false;
        
        /* modify setting */
-       setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, 0);
+       setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, false);
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1981,7 +2003,7 @@ static void ANIM_OT_channels_expand(wmOperatorType *ot)
 static int animchannels_collapse_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
-       short onlysel = 1;
+       bool onlysel = true;
        
        /* get editor data */
        if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1989,10 +2011,10 @@ static int animchannels_collapse_exec(bContext *C, wmOperator *op)
                
        /* only affect selected channels? */
        if (RNA_boolean_get(op->ptr, "all"))
-               onlysel = 0;
+               onlysel = false;
        
        /* modify setting */
-       setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, 0);
+       setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, false);
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -2015,7 +2037,114 @@ static void ANIM_OT_channels_collapse(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
        /* props */
-       ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)");
+       ot->prop = RNA_def_boolean(ot->srna, "all", true, "All", "Collapse all channels (not just selected ones)");
+}
+
+/* ************ Remove All "Empty" AnimData Blocks Operator ********* */
+/* We define "empty" AnimData blocks here as those which have all 3 of criteria:
+ *  1) No active action OR that active actions are empty
+ *     Assuming that all legitimate entries will have an action,
+ *     and that empty actions
+ *  2) No NLA Tracks + NLA Strips
+ *     Assuming that users haven't set up any of these as "placeholders"
+ *     for convenience sake, and that most that exist were either unintentional
+ *     or are no longer wanted
+ *  3) No drivers
+ */
+static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bAnimContext ac;
+       
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       
+       /* get animdata blocks */
+       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       for (ale = anim_data.first; ale; ale = ale->next) {
+               ID *id = ale->id;
+               AnimData *adt = ale->data;
+               
+               bool action_empty  = false;
+               bool nla_empty     = false;
+               bool drivers_empty = false;
+               
+               /* sanity checks */
+               BLI_assert((id != NULL) && (adt != NULL));
+               
+               /* check if this is "empty" and can be deleted */
+               /* (For now, there are only these 3 criteria) */
+               
+               /* 1) Active Action is missing or empty */
+               if (ELEM(NULL, adt->action, adt->action->curves.first)) {
+                       action_empty = true;
+               }
+               else {
+                       /* TODO: check for keyframe + fmodifier data on these too */
+               }
+               
+               /* 2) No NLA Tracks and/or NLA Strips */
+               if (adt->nla_tracks.first == NULL) {
+                       nla_empty = true;
+               }
+               else {
+                       NlaTrack *nlt;
+                       
+                       /* empty tracks? */
+                       for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+                               if (nlt->strips.first) {
+                                       /* stop searching, as we found one that actually had stuff we don't want lost 
+                                        * NOTE: nla_empty gets reset to false, as a previous track may have been empty
+                                        */
+                                       nla_empty = false;
+                                       break;
+                               }
+                               else if (nlt->strips.first == NULL) {
+                                       /* this track is empty, but another one may still have stuff in it, so can't break yet */
+                                       nla_empty = true;
+                               }
+                       }
+               }
+               
+               /* 3) Drivers */
+               drivers_empty = (adt->drivers.first == NULL);
+               
+               
+               /* remove AnimData? */
+               if (action_empty && nla_empty && drivers_empty) {
+                       BKE_animdata_free(id, true);
+               }
+       }
+       
+       /* free temp data */
+       ANIM_animdata_freelist(&anim_data);
+       
+       /* send notifier that things have changed */
+       WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Remove Empty Animation Data";
+       ot->idname = "ANIM_OT_channels_clean_empty";
+       ot->description = "Delete all empty animation data containers from visible datablocks";
+       
+       /* api callbacks */
+       ot->exec = animchannels_clean_empty_exec;
+       ot->poll = animedit_poll_channels_nla_tweakmode_off;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
 /* ******************* Reenable Disabled Operator ******************* */
@@ -2023,7 +2152,7 @@ static void ANIM_OT_channels_collapse(wmOperatorType *ot)
 static int animchannels_enable_poll(bContext *C)
 {
        ScrArea *sa = CTX_wm_area(C);
-
+       
        /* channels region test */
        /* TODO: could enhance with actually testing if channels region? */
        if (ELEM(NULL, sa, CTX_wm_region(C)))
@@ -2064,11 +2193,11 @@ static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
                        fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
                        
                /* tag everything for updates - in particular, this is needed to get drivers working again */
-               ANIM_list_elem_update(ac.scene, ale);
+               ale->update |= ANIM_UPDATE_DEPS;
        }
        
-       /* free temp data */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_update(&ac, &anim_data);
+       ANIM_animdata_freelist(&anim_data);
                
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -2091,6 +2220,82 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/* ****************** Find / Set Filter Operator ******************** */
+
+/* XXX: make this generic? */
+static int animchannels_find_poll(bContext *C)
+{
+       ScrArea *sa = CTX_wm_area(C);
+       
+       if (sa == NULL)
+               return 0;
+       
+       /* animation editor with dopesheet */
+       return ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA);
+}
+
+/* find_invoke() - Get initial channels */
+static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+{
+       bAnimContext ac;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       
+       /* set initial filter text, and enable filter */
+       RNA_string_set(op->ptr, "query", ac.ads->searchstr);
+       
+       /* defer to popup */
+       return WM_operator_props_popup(C, op, evt);
+}
+
+/* find_exec() -  Called to set the value */
+static int animchannels_find_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       
+       /* update filter text, and ensure that filter is enabled if there's something there
+        * NOTE: we turn the filter off if there's nothing (this is a quick shortcut for dismissing)
+        */
+       RNA_string_get(op->ptr, "query", ac.ads->searchstr);
+       
+       if (ac.ads->searchstr[0]) {
+               ac.ads->filterflag |= ADS_FILTER_BY_FCU_NAME;
+       }
+       else {
+               ac.ads->filterflag &= ~ADS_FILTER_BY_FCU_NAME;
+       }
+       
+       /* redraw */
+       WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_channels_find(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Find Channels";
+       ot->idname = "ANIM_OT_channels_find";
+       ot->description = "Filter the set of channels shown to only include those with matching names";
+       
+       /* callbacks */
+       ot->invoke = animchannels_find_invoke;
+       ot->exec = animchannels_find_exec;
+       ot->poll = animchannels_find_poll;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+       
+       /* properties */
+       ot->prop = RNA_def_string(ot->srna, "query", "Query", sizeof(((bDopeSheet *)NULL)->searchstr), "", "Text to search for in channel names");
+}
+
 /* ********************** Select All Operator *********************** */
 
 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
@@ -2103,9 +2308,9 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
                
        /* 'standard' behavior - check if selected, then apply relevant selection */
        if (RNA_boolean_get(op->ptr, "invert"))
-               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
+               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
        else
-               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
+               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
@@ -2128,7 +2333,7 @@ static void ANIM_OT_channels_select_all_toggle(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
        /* props */
-       ot->prop = RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
+       ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "");
 }
 
 /* ******************** Borderselect Operator *********************** */
@@ -2151,7 +2356,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
        }
        else {
                ymin = 0.0f;
-               ymax = (float)(-ACHANNEL_HEIGHT);
+               ymax = (float)(-ACHANNEL_HEIGHT(ac));
        }
        
        /* convert border-region to view coordinates */
@@ -2167,7 +2372,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
                if (ac->datatype == ANIMCONT_NLA)
                        ymin = ymax - NLACHANNEL_STEP(snla);
                else
-                       ymin = ymax - ACHANNEL_STEP;
+                       ymin = ymax - ACHANNEL_STEP(ac);
                
                /* if channel is within border-select region, alter it */
                if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
@@ -2228,7 +2433,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
        }
        
        /* cleanup */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
 }
 
 /* ------------------- */
@@ -2252,7 +2457,7 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
        extend = RNA_boolean_get(op->ptr, "extend");
 
        if (!extend)
-               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_CLEAR);
+               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_CLEAR);
 
        if (gesture_mode == GESTURE_MODAL_SELECT)
                selectmode = ACHANNEL_SETFLAG_ADD;
@@ -2293,12 +2498,13 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
 /* ******************* Rename Operator ***************************** */
 /* Allow renaming some channels by clicking on them */
 
-static void rename_anim_channels(bAnimContext *ac, int channel_index)
+static bool rename_anim_channels(bAnimContext *ac, int channel_index)
 {
        ListBase anim_data = {NULL, NULL};
-       bAnimChannelType *acf;
+       const bAnimChannelType *acf;
        bAnimListElem *ale;
        int filter;
+       bool success = false;
        
        /* get the channel that was clicked on */
        /* filter channels */
@@ -2312,8 +2518,8 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
                if (G.debug & G_DEBUG)
                        printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
                
-               BLI_freelistN(&anim_data);
-               return;
+               ANIM_animdata_freelist(&anim_data);
+               return false;
        }
        
        /* check that channel can be renamed */
@@ -2333,29 +2539,26 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
                         */
                        if (ac->ads) {
                                ac->ads->renameIndex = channel_index + 1;
+                               success = true;
                        }
                }
        }
        
        /* free temp data and tag for refresh */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
        ED_region_tag_redraw(ac->ar);
+       return success;
 }
 
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
 {
-       bAnimContext ac;
        ARegion *ar;
        View2D *v2d;
        int channel_index;
        float x, y;
        
-       /* get editor data */
-       if (ANIM_animdata_get_context(C, &ac) == 0)
-               return OPERATOR_CANCELLED;
-               
        /* get useful pointers from animation context data */
-       ar = ac.ar;
+       ar = ac->ar;
        v2d = &ar->v2d;
        
        /* figure out which channel user clicked in 
@@ -2363,20 +2566,36 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const
         *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
         *              ACHANNEL_HEIGHT_HALF.
         */
-       UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
+       UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
        
-       if (ac.datatype == ANIMCONT_NLA) {
-               SpaceNla *snla = (SpaceNla *)ac.sl;
+       if (ac->datatype == ANIMCONT_NLA) {
+               SpaceNla *snla = (SpaceNla *)ac->sl;
                UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
        }
        else {
-               UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+               UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index);
        }
-       
+
+       return channel_index;
+}
+
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+       bAnimContext ac;
+       int channel_index;
+
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+
+       channel_index = animchannels_channel_get(&ac, event->mval);
+
        /* handle click */
-       rename_anim_channels(&ac, channel_index);
-       
-       return OPERATOR_FINISHED;
+       if (rename_anim_channels(&ac, channel_index))
+               return OPERATOR_FINISHED;
+       else
+               /* allow event to be handled by selectall operator */
+               return OPERATOR_PASS_THROUGH;
 }
 
 static void ANIM_OT_channels_rename(wmOperatorType *ot)
@@ -2413,7 +2632,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                if (G.debug & G_DEBUG)
                        printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n", channel_index);
                
-               BLI_freelistN(&anim_data);
+               ANIM_animdata_freelist(&anim_data);
                return 0;
        }
 
@@ -2421,7 +2640,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
        /* TODO: should this feature be extended to work with other channel types too? */
        if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
                /* normal channels should not behave normally in this case */
-               BLI_freelistN(&anim_data);
+               ANIM_animdata_freelist(&anim_data);
                return 0;
        }
 
@@ -2486,6 +2705,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        if ((adt) && (adt->flag & ADT_UI_SELECTED))
                                adt->flag |= ADT_UI_ACTIVE;
                        
+                       /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
+                       if (ob != sce->obedit)
+                               ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+                       
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
                }
@@ -2493,10 +2716,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                case ANIMTYPE_DSLAM:
                case ANIMTYPE_DSCAM:
+               case ANIMTYPE_DSCACHEFILE:
                case ANIMTYPE_DSCUR:
                case ANIMTYPE_DSSKEY:
                case ANIMTYPE_DSWOR:
-               case ANIMTYPE_DSPART:
                case ANIMTYPE_DSMBALL:
                case ANIMTYPE_DSARM:
                case ANIMTYPE_DSMESH:
@@ -2505,6 +2728,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                case ANIMTYPE_DSLAT:
                case ANIMTYPE_DSLINESTYLE:
                case ANIMTYPE_DSSPK:
+               case ANIMTYPE_DSGPENCIL:
                {
                        /* sanity checking... */
                        if (ale->adt) {
@@ -2515,7 +2739,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                                }
                                else {
                                        /* select AnimData block by itself */
-                                       ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                                       ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
                                        ale->adt->flag |= ADT_UI_SELECTED;
                                }
                                
@@ -2570,8 +2794,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                                FCurve *fcu;
                                
                                /* deselect all other channels */
-                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
-                               if (pchan) ED_pose_deselectall(ob, 0);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
+                               if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
                                
                                /* only select channels in group and group itself */
                                for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next)
@@ -2580,8 +2804,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        }
                        else {
                                /* select group by itself */
-                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
-                               if (pchan) ED_pose_deselectall(ob, 0);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
+                               if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
                                
                                agrp->flag |= AGRP_SELECTED;
                        }
@@ -2599,7 +2823,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
                }
-               case ANIMTYPE_FCURVE: 
+               case ANIMTYPE_FCURVE:
+               case ANIMTYPE_NLACURVE:
                {
                        FCurve *fcu = (FCurve *)ale->data;
                        
@@ -2610,13 +2835,13 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        }
                        else {
                                /* select F-Curve by itself */
-                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
                                fcu->flag |= FCURVE_SELECTED;
                        }
                        
                        /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
                        if (fcu->flag & FCURVE_SELECTED)
-                               ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+                               ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
                                
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
@@ -2632,13 +2857,26 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        }
                        else {
                                /* select ShapeKey by itself */
-                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
                                kb->flag |= KEYBLOCK_SEL;
                        }
                                
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
                }
+               case ANIMTYPE_NLACONTROLS:
+               {
+                       AnimData *adt = (AnimData *)ale->data;
+                       
+                       /* toggle expand
+                        *   - Although the triangle widget already allows this, since there's nothing else that can be done here now,
+                        *     let's just use it for easier expand/collapse for now
+                        */
+                       adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
+                       
+                       notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+                       break;
+               }
                case ANIMTYPE_GPDATABLOCK:
                {
                        bGPdata *gpd = (bGPdata *)ale->data;
@@ -2662,11 +2900,17 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        }
                        else {
                                /* select layer by itself */
-                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
                                gpl->flag |= GP_LAYER_SELECT;
                        }
                        
-                       notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+                       /* change active layer, if this is selected (since we must always have an active layer) */
+                       if (gpl->flag & GP_LAYER_SELECT) {
+                               ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
+                       }
+                       
+                       WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* Grease Pencil updates */
+                       notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Ediotrs updates */
                        break;
                }
                case ANIMTYPE_MASKDATABLOCK:
@@ -2692,7 +2936,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        }
                        else {
                                /* select layer by itself */
-                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
                                masklay->flag |= MASK_LAYERFLAG_SELECT;
                        }
                        
@@ -2706,7 +2950,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
        }
        
        /* free channels */
-       BLI_freelistN(&anim_data);
+       ANIM_animdata_freelist(&anim_data);
        
        /* return notifier flags */
        return notifierFlags;
@@ -2748,7 +2992,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE
         *              ACHANNEL_HEIGHT_HALF.
         */
        UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
-       UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+       UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(&ac), 0, (float)ACHANNEL_HEIGHT_HALF(&ac), x, y, NULL, &channel_index);
        
        /* handle mouse-click in the relevant channel then */
        notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode);
@@ -2777,10 +3021,109 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
        
        /* properties */
        /* NOTE: don't save settings, otherwise, can end up with some weird behaviour (sticky extend) */
-       prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
+       prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", ""); // SHIFTKEY
        RNA_def_property_flag(prop, PROP_SKIP_SAVE);
        
-       prop = RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
+       prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
+       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       bool success = false;
+       FCurve *fcu;
+       int i;
+
+       /* get the channel that was clicked on */
+       /* filter channels */
+       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+       /* get channel from index */
+       ale = BLI_findlink(&anim_data, channel_index);
+       if (ale == NULL) {
+               /* channel not found */
+               if (G.debug & G_DEBUG)
+                       printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
+
+               ANIM_animdata_freelist(&anim_data);
+               return false;
+       }
+
+       fcu = (FCurve *)ale->key_data;
+       success = (fcu != NULL);
+
+       ANIM_animdata_freelist(&anim_data);
+
+       /* F-Curve may not have any keyframes */
+       if (fcu && fcu->bezt) {
+               BezTriple *bezt;
+
+               if (!extend) {
+                       filter = (ANIMFILTER_DATA_VISIBLE);
+                       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+                       for (ale = anim_data.first; ale; ale = ale->next) {
+                               FCurve *fcu_inner = (FCurve *)ale->key_data;
+
+                               if (fcu_inner) {
+                                       for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
+                                               bezt->f2 = bezt->f1 = bezt->f3 = 0;
+                                       }
+                               }
+                       }
+
+                       ANIM_animdata_freelist(&anim_data);
+               }
+
+               for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+                       bezt->f2 = bezt->f1 = bezt->f3 = SELECT;
+               }
+       }
+
+       /* free temp data and tag for refresh */
+       ED_region_tag_redraw(ac->ar);
+       return success;
+}
+
+static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       bAnimContext ac;
+       int channel_index;
+       bool extend = RNA_boolean_get(op->ptr, "extend");
+
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+
+       channel_index = animchannels_channel_get(&ac, event->mval);
+
+       /* handle click */
+       if (select_anim_channel_keys(&ac, channel_index, extend)) {
+               WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+               return OPERATOR_FINISHED;
+       }
+       else
+               /* allow event to be handled by selectall operator */
+               return OPERATOR_PASS_THROUGH;
+}
+
+static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* identifiers */
+       ot->name = "Select Channel keyframes";
+       ot->idname = "ANIM_OT_channel_select_keys";
+       ot->description = "Select all keyframes of channel under mouse";
+
+       /* api callbacks */
+       ot->invoke = animchannels_channel_select_keys_invoke;
+       ot->poll = animedit_poll_channels_active;
+
+       prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
        RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 }
 
@@ -2793,7 +3136,10 @@ void ED_operatortypes_animchannels(void)
        WM_operatortype_append(ANIM_OT_channels_select_border);
        
        WM_operatortype_append(ANIM_OT_channels_click);
+       WM_operatortype_append(ANIM_OT_channel_select_keys);
        WM_operatortype_append(ANIM_OT_channels_rename);
+
+       WM_operatortype_append(ANIM_OT_channels_find);
        
        WM_operatortype_append(ANIM_OT_channels_setting_enable);
        WM_operatortype_append(ANIM_OT_channels_setting_disable);
@@ -2809,11 +3155,10 @@ void ED_operatortypes_animchannels(void)
        WM_operatortype_append(ANIM_OT_channels_expand);
        WM_operatortype_append(ANIM_OT_channels_collapse);
        
-       WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
-       WM_operatortype_append(ANIM_OT_channels_visibility_set);
-       
        WM_operatortype_append(ANIM_OT_channels_fcurves_enable);
        
+       WM_operatortype_append(ANIM_OT_channels_clean_empty);
+       
        WM_operatortype_append(ANIM_OT_channels_group);
        WM_operatortype_append(ANIM_OT_channels_ungroup);
 }
@@ -2823,8 +3168,7 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
 {
        wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0);
        wmKeyMapItem *kmi;
-
-       /* selection */
+       
        /* click-select */
        /* XXX for now, only leftmouse.... */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
@@ -2833,6 +3177,12 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
 
        /* rename */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
+
+       /* find (i.e. a shortcut for setting the name filter) */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
        
        /* deselect all */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
@@ -2872,10 +3222,6 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
        /* grouping */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_group", GKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "ANIM_OT_channels_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
-       
-       /* Graph Editor only */
-       WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
-       WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);
 }
 
 /* ************************************************************************** */