feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* 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.XPStyle.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 AnimationController 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 AnimationController getAnimationController() {
|
||||
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 AnimationController() {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
XPStyle xp = XPStyle.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);
|
||||
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 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 (AnimationController.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user