private synchronized void startAnimation(
     JComponent component, Part part, State startState, 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 synchronized void dispose() {
   timer.stop();
   UIManager.removePropertyChangeListener(this);
   synchronized (AnimationController.class) {
     AppContext.getAppContext().put(ANIMATION_CONTROLLER_KEY, null);
   }
 }
 public synchronized void actionPerformed(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 AnimationController() {
   timer.setRepeats(true);
   timer.setCoalesce(true);
   // we need to dispose the controller on l&f change
   UIManager.addPropertyChangeListener(this);
 }