FileDocCategorySizeDatePackage
AnimationController.javaAPI DocJava SE 6 API14568Tue Jun 10 00:21:58 BST 2008com.sun.java.swing.plaf.windows

AnimationController

public class AnimationController extends Object implements ActionListener, PropertyChangeListener
A class to help mimic Vista theme animations. The only kind of animation it handles for now is 'transition' animation (this seems to be the only animation which Vista theme can do). This is when one picture fadein over another one in some period of time. According to https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=86852&SiteID=4 The animations are all linear. This class has a number of responsibilities.
  • It trigger rapaint for the UI components involved in the animation
  • It tracks the animation state for every UI component involved in the animation and paints {@code Skin} in new {@code State} over the {@code Skin} in last {@code State} using {@code AlphaComposite.SrcOver.derive(alpha)} where {code alpha} depends on the state of animation
version
1.1 08/17/06
author
Igor Kushnirskiy

Fields Summary
private static final boolean
VISTA_ANIMATION_DISABLED
private static final Object
ANIMATION_CONTROLLER_KEY
private final Map
animationStateMap
private final Timer
timer
Constructors Summary
private AnimationController()

        timer.setRepeats(true);
        timer.setCoalesce(true);
        //we need to dispose the controller on l&f change
        UIManager.addPropertyChangeListener(this);
    
Methods Summary
public synchronized voidactionPerformed(java.awt.event.ActionEvent e)

        java.util.List<JComponent> componentsToRemove = null;
        java.util.List<Part> partsToRemove = null;
        for (JComponent component : animationStateMap.keySet()) {
            component.repaint();
            if (partsToRemove != null) {
                partsToRemove.clear();
            }
            Map<Part, AnimationState> map = animationStateMap.get(component);
            if (! component.isShowing()
                  || map == null
                  || map.size() == 0) {
                if (componentsToRemove == null) {
                    componentsToRemove = new ArrayList<JComponent>();
                }
                componentsToRemove.add(component);
                continue;
            }
            for (Part part : map.keySet()) {
                if (map.get(part).isDone()) {
                    if (partsToRemove == null) {
                        partsToRemove = new ArrayList<Part>();
                    }
                    partsToRemove.add(part);
                }
            }
            if (partsToRemove != null) {
                if (partsToRemove.size() == map.size()) {
                    //animation is done for the component
                    if (componentsToRemove == null) {
                        componentsToRemove = new ArrayList<JComponent>();
                    }
                    componentsToRemove.add(component);
                } else {
                    for (Part part : partsToRemove) {
                        map.remove(part);
                    }
                }
            }
        }
        if (componentsToRemove != null) {
            for (JComponent component : componentsToRemove) {
                animationStateMap.remove(component);
            }
        }
        if (animationStateMap.size() == 0) {
            timer.stop();
        }
    
private synchronized voiddispose()

        timer.stop();
        UIManager.removePropertyChangeListener(this);
        synchronized (AnimationController.class) {
            AppContext.getAppContext()
                .put(ANIMATION_CONTROLLER_KEY, null);
        }
    
private static synchronized com.sun.java.swing.plaf.windows.AnimationControllergetAnimationController()

    
         
        AppContext appContext = AppContext.getAppContext();
        Object obj = appContext.get(ANIMATION_CONTROLLER_KEY);
        if (obj == null) {
            obj = new AnimationController();
            appContext.put(ANIMATION_CONTROLLER_KEY, obj);
        }
        return (AnimationController) obj;
    
private synchronized com.sun.java.swing.plaf.windows.TMSchema.StategetState(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.TMSchema.Part part)

        State rv = null;
        Object tmpObject = 
            component.getClientProperty(PartUIClientPropertyKey.getKey(part));
        if (tmpObject instanceof State) {
            rv = (State) tmpObject;
        }
        return rv;
    
private static com.sun.java.swing.plaf.windows.TMSchema.StatenormalizeState(com.sun.java.swing.plaf.windows.TMSchema.State state)

        State rv;
        switch (state) {
        case DOWNPRESSED:  
            /* falls through */
        case LEFTPRESSED:
            /* falls through */
        case RIGHTPRESSED: 
            rv = UPPRESSED; 
            break;

        case DOWNDISABLED:
            /* falls through */
        case LEFTDISABLED:
            /* falls through */
        case RIGHTDISABLED:
            rv = UPDISABLED; 
            break;
            
        case DOWNHOT:
            /* falls through */
        case LEFTHOT:
            /* falls through */
        case RIGHTHOT:
            rv = UPHOT; 
            break;
            
        case DOWNNORMAL:
            /* falls through */
        case LEFTNORMAL:
            /* falls through */
        case RIGHTNORMAL:
            rv = UPNORMAL;
            break;

        default :
            rv = state;
            break;
        }
        return rv;
    
static voidpaintSkin(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.XPStyle.Skin skin, java.awt.Graphics g, int dx, int dy, int dw, int dh, com.sun.java.swing.plaf.windows.TMSchema.State state)

        if (VISTA_ANIMATION_DISABLED) {
            skin.paintSkinRaw(g, dx, dy, dw, dh, state);
            return;
        }
        triggerAnimation(component, skin.part, state);
        AnimationController controller = getAnimationController();
        synchronized (controller) {
            AnimationState animationState = null;
            Map<Part, AnimationState> map = 
                controller.animationStateMap.get(component);
            if (map != null) {
                animationState = map.get(skin.part);
            }
            if (animationState != null) {
                animationState.paintSkin(skin, g, dx, dy, dw, dh, state);
            } else {
                skin.paintSkinRaw(g, dx, dy, dw, dh, state);
            }
        }
    
public synchronized voidpropertyChange(java.beans.PropertyChangeEvent e)

        if ("lookAndFeel" == e.getPropertyName()  
            && ! (e.getNewValue() instanceof WindowsLookAndFeel) ) {
            dispose();
        }
    
private synchronized voidputState(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.TMSchema.Part part, com.sun.java.swing.plaf.windows.TMSchema.State state)

        component.putClientProperty(PartUIClientPropertyKey.getKey(part), 
                                    state);
    
private synchronized voidstartAnimation(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.TMSchema.Part part, com.sun.java.swing.plaf.windows.TMSchema.State startState, com.sun.java.swing.plaf.windows.TMSchema.State endState, long millis)

        boolean isForwardAndReverse = false;
        if (endState == State.DEFAULTED) {
            isForwardAndReverse = true;
        }
        Map<Part, AnimationState> map = animationStateMap.get(component);
        if (millis <= 0) {
            if (map != null) {
                map.remove(part);
                if (map.size() == 0) {
                    animationStateMap.remove(component);
                }
            }
            return;
        }
        if (map == null) {
            map = new EnumMap<Part, AnimationState>(Part.class);
            animationStateMap.put(component, map);
        }
        map.put(part, 
                new AnimationState(startState, millis, isForwardAndReverse));
        if (! timer.isRunning()) {
            timer.start();
        }
    
private static voidtriggerAnimation(javax.swing.JComponent c, com.sun.java.swing.plaf.windows.TMSchema.Part part, com.sun.java.swing.plaf.windows.TMSchema.State newState)

        if (c instanceof javax.swing.JTabbedPane
            || part == Part.TP_BUTTON) {
            //idk: we can not handle tabs animation because 
            //the same (component,part) is used to handle all the tabs
            //and we can not track the states
            //Vista theme might have transition duration for toolbar buttons 
            //but native application does not seem to animate them
            return;
        }
        AnimationController controller = 
            AnimationController.getAnimationController();
        State oldState = controller.getState(c, part);
        if (oldState != newState) {
            controller.putState(c, part, newState);
            if (newState == State.DEFAULTED) {
                // it seems for DEFAULTED button state Vista does animation from 
                // HOT 
                oldState = State.HOT;
            }
            if (oldState != null) {
                long duration;
                if (newState == State.DEFAULTED) {
                    //Only button might have DEFAULTED state
                    //idk: do not know how to get the value from Vista
                    //one second seems plausible value
                    duration = 1000;
                } else {
                     duration = XPStyle.getXP().getThemeTransitionDuration(
                           c, part, 
                           normalizeState(oldState), 
                           normalizeState(newState), 
                           Prop.TRANSITIONDURATIONS);
                }
                controller.startAnimation(c, part, oldState, newState, duration);
            }
        }