Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
- package com.sun.java.swing.plaf.windows;
- import java.security.AccessController;
- import sun.security.action.GetBooleanAction;
- import java.util.*;
- import java.beans.PropertyChangeListener;
- import java.beans.PropertyChangeEvent;
- import java.awt.*;
- import java.awt.event.*;
- import javax.swing.*;
- import sun.swing.UIClientPropertyKey;
- import com.sun.java.swing.plaf.windows.TMSchema.State;
- import static com.sun.java.swing.plaf.windows.TMSchema.State.*;
- import com.sun.java.swing.plaf.windows.TMSchema.Part;
- import com.sun.java.swing.plaf.windows.TMSchema.Prop;
- import com.sun.java.swing.plaf.windows.XPStyle2.Skin;
- import sun.awt.AppContext;
- /**
- * 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.
- * <ul>
- * <li> It trigger rapaint for the UI components involved in the animation
- * <li> 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
- * </ul>
- *
- * @author Igor Kushnirskiy
- */
- class AnimationController2 implements ActionListener, PropertyChangeListener {
- private final static boolean VISTA_ANIMATION_DISABLED =
- AccessController.doPrivileged(new GetBooleanAction("swing.disablevistaanimation"));
- private final static Object ANIMATION_CONTROLLER_KEY =
- new StringBuilder("ANIMATION_CONTROLLER_KEY");
- private final Map<JComponent, Map<Part, AnimationState>> animationStateMap =
- new WeakHashMap<JComponent, Map<Part, AnimationState>>();
- //this timer is used to cause repaint on animated components
- //30 repaints per second should give smooth animation affect
- private final javax.swing.Timer timer =
- new javax.swing.Timer(1000/30, this);
- private static synchronized AnimationController2 getAnimationController() {
- AppContext appContext = AppContext.getAppContext();
- Object obj = appContext.get(ANIMATION_CONTROLLER_KEY);
- if (obj == null) {
- obj = new AnimationController2();
- appContext.put(ANIMATION_CONTROLLER_KEY, obj);
- }
- return (AnimationController2) obj;
- }
- private AnimationController2() {
- timer.setRepeats(true);
- timer.setCoalesce(true);
- //we need to dispose the controller on l&f change
- UIManager.addPropertyChangeListener(this);
- }
- private static void triggerAnimation(JComponent c,
- Part part, 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;
- }
- AnimationController2 controller =
- AnimationController2.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 {
- XPStyle2 xp = XPStyle2.getXP();
- duration = (xp != null)
- ? xp.getThemeTransitionDuration(
- c, part,
- normalizeState(oldState),
- normalizeState(newState),
- Prop.TRANSITIONDURATIONS)
- : 1000;
- }
- controller.startAnimation(c, part, oldState, newState, duration);
- }
- }
- }
- // for scrollbar up, down, left and right button pictures are
- // defined by states. It seems that theme has duration defined
- // only for up button states thus we doing this translation here.
- private static State normalizeState(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;
- }
- private synchronized State getState(JComponent component, Part part) {
- State rv = null;
- Object tmpObject =
- component.getClientProperty(PartUIClientPropertyKey.getKey(part));
- if (tmpObject instanceof State) {
- rv = (State) tmpObject;
- }
- return rv;
- }
- private synchronized void putState(JComponent component, Part part,
- State state) {
- component.putClientProperty(PartUIClientPropertyKey.getKey(part),
- state);
- }
- 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();
- }
- }
- static void paintSkin(JComponent component, Skin skin,
- Graphics g, int dx, int dy, int dw, int dh, State state) {
- if (VISTA_ANIMATION_DISABLED) {
- skin.paintSkinRaw(g, dx, dy, dw, dh, state);
- return;
- }
- triggerAnimation(component, skin.part, state);
- AnimationController2 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 void propertyChange(PropertyChangeEvent e) {
- if ("lookAndFeel" == e.getPropertyName()
- && ! (e.getNewValue() instanceof WindowsLookAndFeel) ) {
- dispose();
- }
- }
- 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 synchronized void dispose() {
- timer.stop();
- UIManager.removePropertyChangeListener(this);
- synchronized (AnimationController2.class) {
- AppContext.getAppContext()
- .put(ANIMATION_CONTROLLER_KEY, null);
- }
- }
- private static class AnimationState {
- private final State startState;
- //animation duration in nanoseconds
- private final long duration;
- //animatin start time in nanoseconds
- private long startTime;
- //direction the alpha value is changing
- //forward - from 0 to 1
- //!forward - from 1 to 0
- private boolean isForward = true;
- //if isForwardAndReverse the animation continually goes
- //forward and reverse. alpha value is changing from 0 to 1 then
- //from 1 to 0 and so forth
- private boolean isForwardAndReverse;
- private float progress;
- AnimationState(final State startState,
- final long milliseconds,
- boolean isForwardAndReverse) {
- assert startState != null && milliseconds > 0;
- assert SwingUtilities.isEventDispatchThread();
- this.startState = startState;
- this.duration = milliseconds * 1000000;
- this.startTime = System.nanoTime();
- this.isForwardAndReverse = isForwardAndReverse;
- progress = 0f;
- }
- private void updateProgress() {
- assert SwingUtilities.isEventDispatchThread();
- if (isDone()) {
- return;
- }
- long currentTime = System.nanoTime();
- progress = ((float) (currentTime - startTime))
- / duration;
- progress = Math.max(progress, 0); //in case time was reset
- if (progress >= 1) {
- progress = 1;
- if (isForwardAndReverse) {
- startTime = currentTime;
- progress = 0;
- isForward = ! isForward;
- }
- }
- }
- void paintSkin(Skin skin, Graphics _g,
- int dx, int dy, int dw, int dh, State state) {
- assert SwingUtilities.isEventDispatchThread();
- updateProgress();
- if (! isDone()) {
- Graphics2D g = (Graphics2D) _g.create();
- skin.paintSkinRaw(g, dx, dy, dw, dh, startState);
- float alpha;
- if (isForward) {
- alpha = progress;
- } else {
- alpha = 1 - progress;
- }
- g.setComposite(AlphaComposite.SrcOver.derive(alpha));
- skin.paintSkinRaw(g, dx, dy, dw, dh, state);
- g.dispose();
- } else {
- skin.paintSkinRaw(_g, dx, dy, dw, dh, state);
- }
- }
- boolean isDone() {
- assert SwingUtilities.isEventDispatchThread();
- return progress >= 1;
- }
- }
- private static class PartUIClientPropertyKey
- implements UIClientPropertyKey {
- private static final Map<Part, PartUIClientPropertyKey> map =
- new EnumMap<Part, PartUIClientPropertyKey>(Part.class);
- static synchronized PartUIClientPropertyKey getKey(Part part) {
- PartUIClientPropertyKey rv = map.get(part);
- if (rv == null) {
- rv = new PartUIClientPropertyKey(part);
- map.put(part, rv);
- }
- return rv;
- }
- private final Part part;
- private PartUIClientPropertyKey(Part part) {
- this.part = part;
- }
- public String toString() {
- return part.toString();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement