1 7 8 package com.sun.java.swing.plaf.windows; 9 10 import java.security.AccessController ; 11 import sun.security.action.GetBooleanAction; 12 13 import java.util.*; 14 import java.beans.PropertyChangeListener ; 15 import java.beans.PropertyChangeEvent ; 16 import java.awt.*; 17 import java.awt.event.*; 18 import javax.swing.*; 19 20 21 22 import sun.swing.UIClientPropertyKey; 23 import com.sun.java.swing.plaf.windows.TMSchema.State; 24 import static com.sun.java.swing.plaf.windows.TMSchema.State.*; 25 import com.sun.java.swing.plaf.windows.TMSchema.Part; 26 import com.sun.java.swing.plaf.windows.TMSchema.Prop; 27 import com.sun.java.swing.plaf.windows.XPStyle.Skin; 28 29 import sun.awt.AppContext; 30 31 53 class AnimationController implements ActionListener, PropertyChangeListener { 54 55 private final static boolean VISTA_ANIMATION_DISABLED = 56 AccessController.doPrivileged(new GetBooleanAction("swing.disablevistaanimation")); 57 58 59 private final static Object ANIMATION_CONTROLLER_KEY = 60 new StringBuilder ("ANIMATION_CONTROLLER_KEY"); 61 62 private final Map<JComponent, Map<Part, AnimationState>> animationStateMap = 63 new WeakHashMap<JComponent, Map<Part, AnimationState>>(); 64 65 private final javax.swing.Timer timer = 68 new javax.swing.Timer (1000/30, this); 69 70 private static synchronized AnimationController getAnimationController() { 71 AppContext appContext = AppContext.getAppContext(); 72 Object obj = appContext.get(ANIMATION_CONTROLLER_KEY); 73 if (obj == null) { 74 obj = new AnimationController(); 75 appContext.put(ANIMATION_CONTROLLER_KEY, obj); 76 } 77 return (AnimationController) obj; 78 } 79 80 private AnimationController() { 81 timer.setRepeats(true); 82 timer.setCoalesce(true); 83 UIManager.addPropertyChangeListener(this); 85 } 86 87 private static void triggerAnimation(JComponent c, 88 Part part, State newState) { 89 if (c instanceof javax.swing.JTabbedPane 90 || part == Part.TP_BUTTON) { 91 return; 97 } 98 AnimationController controller = 99 AnimationController.getAnimationController(); 100 State oldState = controller.getState(c, part); 101 if (oldState != newState) { 102 controller.putState(c, part, newState); 103 if (newState == State.DEFAULTED) { 104 oldState = State.HOT; 107 } 108 if (oldState != null) { 109 long duration; 110 if (newState == State.DEFAULTED) { 111 duration = 1000; 115 } else { 116 duration = XPStyle.getXP().getThemeTransitionDuration( 117 c, part, 118 normalizeState(oldState), 119 normalizeState(newState), 120 Prop.TRANSITIONDURATIONS); 121 } 122 controller.startAnimation(c, part, oldState, newState, duration); 123 } 124 } 125 } 126 127 private static State normalizeState(State state) { 131 State rv; 132 switch (state) { 133 case DOWNPRESSED: 134 135 case LEFTPRESSED: 136 137 case RIGHTPRESSED: 138 rv = UPPRESSED; 139 break; 140 141 case DOWNDISABLED: 142 143 case LEFTDISABLED: 144 145 case RIGHTDISABLED: 146 rv = UPDISABLED; 147 break; 148 149 case DOWNHOT: 150 151 case LEFTHOT: 152 153 case RIGHTHOT: 154 rv = UPHOT; 155 break; 156 157 case DOWNNORMAL: 158 159 case LEFTNORMAL: 160 161 case RIGHTNORMAL: 162 rv = UPNORMAL; 163 break; 164 165 default : 166 rv = state; 167 break; 168 } 169 return rv; 170 } 171 172 private synchronized State getState(JComponent component, Part part) { 173 State rv = null; 174 Object tmpObject = 175 component.getClientProperty(PartUIClientPropertyKey.getKey(part)); 176 if (tmpObject instanceof State) { 177 rv = (State) tmpObject; 178 } 179 return rv; 180 } 181 182 private synchronized void putState(JComponent component, Part part, 183 State state) { 184 component.putClientProperty(PartUIClientPropertyKey.getKey(part), 185 state); 186 } 187 188 private synchronized void startAnimation(JComponent component, 189 Part part, 190 State startState, 191 State endState, 192 long millis) { 193 boolean isForwardAndReverse = false; 194 if (endState == State.DEFAULTED) { 195 isForwardAndReverse = true; 196 } 197 Map<Part, AnimationState> map = animationStateMap.get(component); 198 if (millis <= 0) { 199 if (map != null) { 200 map.remove(part); 201 if (map.size() == 0) { 202 animationStateMap.remove(component); 203 } 204 } 205 return; 206 } 207 if (map == null) { 208 map = new EnumMap<Part, AnimationState>(Part.class); 209 animationStateMap.put(component, map); 210 } 211 map.put(part, 212 new AnimationState(startState, millis, isForwardAndReverse)); 213 if (! timer.isRunning()) { 214 timer.start(); 215 } 216 } 217 218 static void paintSkin(JComponent component, Skin skin, 219 Graphics g, int dx, int dy, int dw, int dh, State state) { 220 if (VISTA_ANIMATION_DISABLED) { 221 skin.paintSkinRaw(g, dx, dy, dw, dh, state); 222 return; 223 } 224 triggerAnimation(component, skin.part, state); 225 AnimationController controller = getAnimationController(); 226 synchronized (controller) { 227 AnimationState animationState = null; 228 Map<Part, AnimationState> map = 229 controller.animationStateMap.get(component); 230 if (map != null) { 231 animationState = map.get(skin.part); 232 } 233 if (animationState != null) { 234 animationState.paintSkin(skin, g, dx, dy, dw, dh, state); 235 } else { 236 skin.paintSkinRaw(g, dx, dy, dw, dh, state); 237 } 238 } 239 } 240 241 public synchronized void propertyChange(PropertyChangeEvent e) { 242 if ("lookAndFeel" == e.getPropertyName() 243 && ! (e.getNewValue() instanceof WindowsLookAndFeel) ) { 244 dispose(); 245 } 246 } 247 248 public synchronized void actionPerformed(ActionEvent e) { 249 java.util.List <JComponent> componentsToRemove = null; 250 java.util.List <Part> partsToRemove = null; 251 for (JComponent component : animationStateMap.keySet()) { 252 component.repaint(); 253 if (partsToRemove != null) { 254 partsToRemove.clear(); 255 } 256 Map<Part, AnimationState> map = animationStateMap.get(component); 257 if (! component.isShowing() 258 || map == null 259 || map.size() == 0) { 260 if (componentsToRemove == null) { 261 componentsToRemove = new ArrayList<JComponent>(); 262 } 263 componentsToRemove.add(component); 264 continue; 265 } 266 for (Part part : map.keySet()) { 267 if (map.get(part).isDone()) { 268 if (partsToRemove == null) { 269 partsToRemove = new ArrayList<Part>(); 270 } 271 partsToRemove.add(part); 272 } 273 } 274 if (partsToRemove != null) { 275 if (partsToRemove.size() == map.size()) { 276 if (componentsToRemove == null) { 278 componentsToRemove = new ArrayList<JComponent>(); 279 } 280 componentsToRemove.add(component); 281 } else { 282 for (Part part : partsToRemove) { 283 map.remove(part); 284 } 285 } 286 } 287 } 288 if (componentsToRemove != null) { 289 for (JComponent component : componentsToRemove) { 290 animationStateMap.remove(component); 291 } 292 } 293 if (animationStateMap.size() == 0) { 294 timer.stop(); 295 } 296 } 297 298 private synchronized void dispose() { 299 timer.stop(); 300 UIManager.removePropertyChangeListener(this); 301 synchronized (AnimationController.class) { 302 AppContext.getAppContext() 303 .put(ANIMATION_CONTROLLER_KEY, null); 304 } 305 } 306 307 private static class AnimationState { 308 private final State startState; 309 310 private final long duration; 312 313 private long startTime; 315 316 private boolean isForward = true; 320 321 private boolean isForwardAndReverse; 325 326 private float progress; 327 328 AnimationState(final State startState, 329 final long milliseconds, 330 boolean isForwardAndReverse) { 331 assert startState != null && milliseconds > 0; 332 assert SwingUtilities.isEventDispatchThread(); 333 334 this.startState = startState; 335 this.duration = milliseconds * 1000000; 336 this.startTime = System.nanoTime(); 337 this.isForwardAndReverse = isForwardAndReverse; 338 progress = 0f; 339 } 340 private void updateProgress() { 341 assert SwingUtilities.isEventDispatchThread(); 342 343 if (isDone()) { 344 return; 345 } 346 long currentTime = System.nanoTime(); 347 348 progress = ((float) (currentTime - startTime)) 349 / duration; 350 progress = Math.max(progress, 0); if (progress >= 1) { 352 progress = 1; 353 if (isForwardAndReverse) { 354 startTime = currentTime; 355 progress = 0; 356 isForward = ! isForward; 357 } 358 } 359 } 360 void paintSkin(Skin skin, Graphics _g, 361 int dx, int dy, int dw, int dh, State state) { 362 assert SwingUtilities.isEventDispatchThread(); 363 364 updateProgress(); 365 if (! isDone()) { 366 Graphics2D g = (Graphics2D) _g.create(); 367 skin.paintSkinRaw(g, dx, dy, dw, dh, startState); 368 float alpha; 369 if (isForward) { 370 alpha = progress; 371 } else { 372 alpha = 1 - progress; 373 } 374 g.setComposite(AlphaComposite.SrcOver.derive(alpha)); 375 skin.paintSkinRaw(g, dx, dy, dw, dh, state); 376 g.dispose(); 377 } else { 378 skin.paintSkinRaw(_g, dx, dy, dw, dh, state); 379 } 380 } 381 boolean isDone() { 382 assert SwingUtilities.isEventDispatchThread(); 383 384 return progress >= 1; 385 } 386 } 387 388 private static class PartUIClientPropertyKey 389 implements UIClientPropertyKey { 390 391 private static final Map<Part, PartUIClientPropertyKey> map = 392 new EnumMap<Part, PartUIClientPropertyKey>(Part.class); 393 394 static synchronized PartUIClientPropertyKey getKey(Part part) { 395 PartUIClientPropertyKey rv = map.get(part); 396 if (rv == null) { 397 rv = new PartUIClientPropertyKey(part); 398 map.put(part, rv); 399 } 400 return rv; 401 } 402 403 private final Part part; 404 private PartUIClientPropertyKey(Part part) { 405 this.part = part; 406 } 407 public String toString() { 408 return part.toString(); 409 } 410 } 411 } 412 | Popular Tags |