All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jvnet.lafwidget.utils.FadeTracker Maven / Gradle / Ivy

Go to download

Laf-Widget provides support for common "feel" widgets in look-and-feel libraries

There is a newer version: 5.0
Show newest version
/*
 * Copyright (c) 2005-2006 Laf-Widget Kirill Grouchnikov. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *  o Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *     
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *     
 *  o Neither the name of Laf-Widget Kirill Grouchnikov nor the names of 
 *    its contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package org.jvnet.lafwidget.utils;

import java.awt.Component;
import java.util.*;

import javax.swing.SwingUtilities;

import org.jvnet.lafwidget.LafWidgetUtilities;
import org.jvnet.lafwidget.utils.LafConstants.AnimationKind;

/**
 * Tracker class for fade animations.
 * 
 * @author Kirill Grouchnikov
 */
public class FadeTracker {
	/**
	 * Max value for fade cycle.
	 */
	public static final int END_VALUE = 10;

	/**
	 * Single instance of this class.
	 */
	private static FadeTracker instance;

	/**
	 * All currently tracked components. Only components that are being animated
	 * (fade-in or fade-out) are in this map. Key is
	 * {@link ComponentId}, value is map from {@link FadeKind} to
	 * {@link FadeState}.
	 */
	private Map trackedComponents;

	/**
	 * All currently executing fade instances. Key is {@link Long} (corresponds
	 * to the {@link FadeState#id}, value is {@link ComponentId} - which is a
	 * key in {@link #trackedComponents}.
	 */
	private Map fadeInstances;

	/**
	 * Fade animation kind.
	 * 
	 * @author Kirill Grouchnikov.
	 */
	public static class FadeKind {
		/**
		 * Fade kind ID.
		 */
		protected String id;

		/**
		 * Creates a new fade kind.
		 * 
		 * @param id
		 *            Fade kind ID.
		 */
		public FadeKind(String id) {
			this.id = id;
		}

		/**
		 * Arming a component.
		 */
		public static final FadeKind ARM = new FadeKind("lafwidgets.core.arm");

		/**
		 * Pressing a component.
		 */
		public static final FadeKind PRESS = new FadeKind(
				"lafwidgets.core.press");

		/**
		 * Focusing a component.
		 */
		public static final FadeKind FOCUS = new FadeKind(
				"lafwidgets.core.focus");

		/**
		 * Enabling a component.
		 */
		public static final FadeKind ENABLE = new FadeKind(
				"lafwidgets.core.enable");

		/**
		 * Rollover a component.
		 */
		public static final FadeKind ROLLOVER = new FadeKind(
				"lafwidgets.core.rollover");

		/**
		 * Selecting a component.
		 */
		public static final FadeKind SELECTION = new FadeKind(
				"lafwidgets.core.selection");

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#hashCode()
		 */
		public int hashCode() {
			return this.id.hashCode();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		public boolean equals(Object obj) {
			if (obj instanceof FadeKind) {
				return this.id.equals(((FadeKind) obj).id);
			}
			return false;
		}

		// /**
		// * Marking a component as modified.
		// */
		// public static final FadeKind MARKED_MODIFIED = new FadeKind(
		// "lafwidgets.core.arm");
	}

	/**
	 * Information on a single component under fade.
	 * 
	 * @author Kirill Grouchnikov
	 */
	protected static class ComponentId {
		/**
		 * UI component itself.
		 */
		public Component component;

		/**
		 * ID to distinguish between different sub-components of the UI
		 * component. For example, the tabbed pane uses this field to make
		 * tab-specific animations.
		 */
		// public int id;
		public Comparable id;

		/**
		 * Creates a new component ID.
		 * 
		 * @param component
		 *            UI component itself.
		 * @param id
		 *            ID to distinguish between different sub-components of the
		 *            UI component.
		 */
		public ComponentId(Component component, Comparable id) {
			this.component = component;
			this.id = id;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#hashCode()
		 */
		public int hashCode() {
			int result = this.component.hashCode();
			result &= (this.id.hashCode());
			return result;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		public boolean equals(Object obj) {
			if (obj instanceof ComponentId) {
				ComponentId cid = (ComponentId) obj;
				try {
					return ((this.component == cid.component) && (this.id
							.compareTo(cid.id) == 0));
				} catch (Exception exc) {
					return false;
				}
			}
			return false;
		}
	}

	/**
	 * Callback for the fade tracker. Is used when the application (some UI
	 * delegate) wishes to execute some code on the fade.
	 * 
	 * @author Kirill Grouchnikov
	 */
	public static interface FadeTrackerCallback {
		/**
		 * Indicates that a single cycle of fade has been performed. Can be used
		 * in order to repaint specific portion of the component.
		 * 
		 * @param fadeKind
		 *            Fade animation kind.
		 * @param fadeCycle10
		 *            The current fade cycle. Is guaranteed to be in 0.0-10.0
		 *            range.
		 */
		public void fadePerformed(FadeKind fadeKind, float fadeCycle10);

		/**
		 * Indicates that the fade sequence has ended. Can be used in order to
		 * repaint specific portion of the component.
		 * 
		 * @param fadeKind
		 *            Fade animation kind.
		 */
		public void fadeEnded(FadeKind fadeKind);
	}

	/**
	 * Information on the state of the faded component.
	 * 
	 * @author Kirill Grouchnikov
	 */
	private static class FadeState {
		/**
		 * Is used to create unique value for the {@link #id} field.
		 */
		protected static long counter;

		/**
		 * Unique ID.
		 */
		protected long id;

		/**
		 * Fade cycle.
		 */
		public float fadePosition;

		/**
		 * Indication whether it's a fade-in or fade-out.
		 */
		public boolean isFadingIn;

		/**
		 * Indication whether it's looping (infinite).
		 */
		public boolean isLooping;

		/**
		 * Indication whether the looping fade starts fading out after reaching
		 * the maximum value. Relevant only when {@link #isLooping} is
		 * true.
		 */
		public boolean isLoopingReverse;

		/**
		 * Indication whether the looping fade should stop at reaching the end
		 * of the fade-out cycle. Relevant only when {@link #isLooping} is
		 * true.
		 */
		public boolean toStopAtCycleBreak;

		/**
		 * Indication whether the component parent should be repainted on each
		 * fade cycle.
		 */
		public boolean toRepaintParent;

		/**
		 * The optional callback to be called on each fade cycle.
		 */
		public FadeTrackerCallback callback;

		/**
		 * Fade animation step.
		 */
		public FadeStep fadeStep;

		/**
		 * Fade animation kind.
		 */
		public FadeKind fadeKind;

		/**
		 * Simple constructor.
		 * 
		 * @param fadeKind
		 *            Fade animation kind.
		 * @param fadePosition
		 *            Fade cycle.
		 * @param isFadingIn
		 *            Indication whether it's a fade-in or fade-out.
		 * @param toRepaintParent
		 *            Indication whether the component parent should be
		 *            repainted on each fade cycle.
		 */
		public FadeState(FadeKind fadeKind, float fadePosition,
				boolean isFadingIn, boolean toRepaintParent) {
			super();
			this.fadeKind = fadeKind;
			this.fadePosition = fadePosition;
			this.isFadingIn = isFadingIn;
			this.toRepaintParent = toRepaintParent;
			this.id = FadeState.getId();
			this.isLooping = false;
			this.toStopAtCycleBreak = false;
		}

		/**
		 * Sets the looping indication.
		 * 
		 * @param isLooping
		 *            New value for the looping indication.
		 */
		public void setLooping(boolean isLooping) {
			this.isLooping = isLooping;
		}

		/**
		 * Sets indication that looping fade should stop at the end of the
		 * fade-out cycle.
		 */
		public void toStopAtCycleBreak() {
			if (!this.isLooping)
				throw new IllegalArgumentException(
						"Supported only on looping fades");
			this.toStopAtCycleBreak = true;
		}

		/**
		 * Returns a unique ID.
		 * 
		 * @return Unique ID.
		 */
		protected static synchronized long getId() {
			return counter++;
		}
	}

	// private static List[] trackerValues = initializeLists();
	//	
	// static List[]

	/**
	 * The fade thread.
	 */
	private FadeTrackerThread trackerThread;

	/**
	 * The fade thread class.
	 * 
	 * @author Kirill Grouchnikov
	 */
	private class FadeTrackerThread extends TrackableThread {
		/**
		 * Fade thread delay.
		 */
		public static final int DELAY = 40;

		/**
		 * Indication whether a stop request has been issued on
		 * this thread.
		 */
		private boolean stopRequested;

		/**
		 * Simple constructor. Defined private for singleton.
		 * 
		 * @see #getInstance()
		 */
		public FadeTrackerThread() {
			super();
			this.setName("Laf-Widget fade tracker");
			this.stopRequested = false;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Thread#run()
		 */
		public void run() {
			while (!this.stopRequested) {
				try {
					Thread.sleep(FadeTrackerThread.DELAY);
				} catch (InterruptedException ie) {
					ie.printStackTrace();
				}
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						FadeTracker.this.updateComponents();
					}
				});
			}
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.jvnet.substance.utils.SubstanceThread#requestStop()
		 */
		protected void requestStop() {
			this.stopRequested = true;
			FadeTracker.this.trackerThread = null;
		}
	}

	/**
	 * Simple constructor. Defined private for singleton.
	 * 
	 * @see #getInstance()
	 */
	private FadeTracker() {
		this.trackerThread = this.getThread();
		this.trackedComponents = new HashMap();
		this.fadeInstances = new HashMap();
		// this.sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS");
		// this.int2comp = new ArrayList>();
	}

	/**
	 * Gets singleton instance.
	 * 
	 * @return Singleton instance.
	 */
	public synchronized static FadeTracker getInstance() {
		if (FadeTracker.instance == null) {
			FadeTracker.instance = new FadeTracker();
		}
		return FadeTracker.instance;
	}

	/**
	 * Updates all components that are currently registered with
	 * this tracker. The update include repaint (based on the
	 * {@link FadeState#toRepaintParent}) and optional call to the callback.
	 */
	private synchronized void updateComponents() {
		// if (this.comp2int.size() > 0)
		// System.out.println("Periodic update");
		Set parents = new HashSet();
		for (Iterator itComp = this.trackedComponents.entrySet().iterator(); itComp
				.hasNext();) {
			Map.Entry entryComp = (Map.Entry) itComp.next();
			Map mapComp = (Map) entryComp.getValue();
			for (Iterator itKind = mapComp.entrySet().iterator(); itKind
					.hasNext();) {
				Map.Entry entryKind = (Map.Entry) itKind.next();
				FadeState state = (FadeState) entryKind.getValue();
				boolean hasEnded = false;
				// Component comp = entry.getKey();
				if (state.isFadingIn) {
					state.fadePosition += state.fadeStep.getNextStep(
							state.fadeKind, state.fadePosition,
							state.isFadingIn, state.isLooping);
					if (state.fadePosition > FadeTracker.END_VALUE) {
						state.fadePosition = FadeTracker.END_VALUE;
						if (state.isLooping) {
							if (state.isLoopingReverse) {
								state.isFadingIn = false;
							} else {
								state.fadePosition = 0.0f;
								if (state.toStopAtCycleBreak) {
									this.fadeInstances
											.remove(new Long(state.id));
									hasEnded = true;
									itKind.remove();
								}
							}
						} else {
							this.fadeInstances.remove(new Long(state.id));
							hasEnded = true;
							itKind.remove();
						}
					}
				} else {
					state.fadePosition -= state.fadeStep.getNextStep(
							state.fadeKind, state.fadePosition,
							state.isFadingIn, state.isLooping);
					if (state.fadePosition < 0) {
						if (state.isLooping && !state.toStopAtCycleBreak) {
							state.fadePosition = 0.0f;
							state.isFadingIn = true;
						} else {
							this.fadeInstances.remove(new Long(state.id));
							hasEnded = true;
							itKind.remove();
						}
					}
				}
				if (state.callback != null) {
					if (hasEnded) {
						state.callback.fadeEnded(state.fadeKind);
					} else {
						state.callback.fadePerformed(state.fadeKind,
								state.fadePosition);
					}
					continue;
				}
				if (state.toRepaintParent)
					parents.add(((ComponentId) entryComp.getKey()).component
							.getParent());
				else
					((ComponentId) entryComp.getKey()).component.repaint();
			}
			if (mapComp.size() == 0)
				itComp.remove();
			// System.out.println("\tState of " + comp.hashCode() + " is "
			// + state.fadePosition + " fading "
			// + (state.isFadingIn ? "in" : "out"));
			// long time0 = System.nanoTime();

			// long time1 = System.nanoTime();
			// if (entry.getKey() instanceof JButton) {
			// System.out.println(((JButton) entry.getKey()).getText() + " [" +
			// state.isFadingIn + "]: "
			// + (time1 - time0));
			// }
		}
		for (Iterator itParent = parents.iterator(); itParent.hasNext();) {
			Component parent = (Component) itParent.next();
			parent.repaint();
		}
	}

	/**
	 * Returns the state of the component under the specified fade kind.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param comp
	 *            Component.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @return Component state under the specified fade kind.
	 */
	private synchronized FadeState getState(FadeKind fadeKind, Component comp,
			Comparable componentId) {
		ComponentId cid = new ComponentId(comp, componentId);
		Map map = (Map) this.trackedComponents.get(cid);
		if (map == null) {
			map = new HashMap();
			this.trackedComponents.put(cid, map);
		}
		return (FadeState) map.get(fadeKind);
	}

	/**
	 * Adds new fade state for the specified component.
	 * 
	 * @param comp
	 *            Component.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param fadeKind
	 *            Fade kind.
	 * @param fadeState
	 *            Fade state object.
	 */
	private synchronized void addState(Component comp, Comparable componentId,
			FadeKind fadeKind, FadeState fadeState) {
		ComponentId cid = new ComponentId(comp, componentId);
		Map map = (Map) this.trackedComponents.get(cid);
		if (map == null) {
			map = new HashMap();
			this.trackedComponents.put(cid, map);
		}
		map.put(fadeKind, fadeState);
		this.fadeInstances.put(new Long(fadeState.id), cid);
	}

	/**
	 * Requests start of fade-in tracking on the specified component.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param comp
	 *            The component to track.
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFadeIn(FadeKind fadeKind, Component comp,
			boolean toRepaintParent, FadeTrackerCallback callback) {
		return this.trackFadeIn(fadeKind, comp, 0, toRepaintParent, callback);
	}

	/**
	 * Requests start of fade-in tracking on the specified component.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param comp
	 *            The component to track.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFadeIn(FadeKind fadeKind, Component comp,
			int componentId, boolean toRepaintParent,
			FadeTrackerCallback callback) {
		return this.trackFadeIn(fadeKind, comp, new Integer(componentId),
				toRepaintParent, callback);
	}

	/**
	 * Requests start of fade-in tracking on the specified component.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param comp
	 *            The component to track.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFadeIn(FadeKind fadeKind, Component comp,
			Comparable componentId, boolean toRepaintParent,
			FadeTrackerCallback callback) {
		if (!comp.isDisplayable())
			return -1;

		this.getThread();

		// see if it's already tracked
		FadeState fadeState = this.getState(fadeKind, comp, componentId);
		if (fadeState == null) {
			fadeState = new FadeState(fadeKind, 0, true, toRepaintParent);
			fadeState.fadeStep = LafWidgetUtilities.getAnimationKind(comp)
					.getStep();
			if (fadeKind == FadeKind.SELECTION)
				fadeState.fadeStep = new FadeAccelerationStep(
						fadeState.fadeStep, 2.0f);
			this.addState(comp, componentId, fadeKind, fadeState);
		} else {
			fadeState.isFadingIn = true;
		}
		fadeState.callback = callback;
		return fadeState.id;
		// System.out.println(sdf.format(new Date())
		// + " : starting tracking fade in on "
		// + comp.getClass().getName() + " [" + comp.hashCode()
		// + "] from " + fadeState.fadePosition);
	}

	/**
	 * Requests start of fade-out tracking on the specified component.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param comp
	 *            The component to track.
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFadeOut(FadeKind fadeKind, Component comp,
			boolean toRepaintParent, FadeTrackerCallback callback) {
		return this.trackFadeOut(fadeKind, comp, 0, toRepaintParent, callback);
	}

	/**
	 * Requests start of fade-out tracking on the specified component.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param comp
	 *            The component to track.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFadeOut(FadeKind fadeKind, Component comp,
			int componentId, boolean toRepaintParent,
			FadeTrackerCallback callback) {
		return this.trackFadeOut(fadeKind, comp, new Integer(componentId),
				toRepaintParent, callback);
	}

	/**
	 * Requests start of fade-out tracking on the specified component.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param comp
	 *            The component to track.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFadeOut(FadeKind fadeKind, Component comp,
			Comparable componentId, boolean toRepaintParent,
			FadeTrackerCallback callback) {
		if (!comp.isDisplayable())
			return -1;

		this.getThread();

		// see if it's already tracked
		FadeState fadeState = this.getState(fadeKind, comp, componentId);
		if (fadeState == null) {
			fadeState = new FadeState(fadeKind, FadeTracker.END_VALUE, false,
					toRepaintParent);
			fadeState.fadeStep = LafWidgetUtilities.getAnimationKind(comp)
					.getStep();
			if (fadeKind == FadeKind.SELECTION)
				fadeState.fadeStep = new FadeAccelerationStep(
						fadeState.fadeStep, 2.0f);
			this.addState(comp, componentId, fadeKind, fadeState);
		} else {
			fadeState.isFadingIn = false;
		}
		fadeState.callback = callback;
		return fadeState.id;
		// System.out.println(sdf.format(new Date())
		// + " : starting tracking fade out on "
		// + comp.getClass().getName() + " [" + comp.hashCode()
		// + "] from " + fadeState.fadePosition);
	}

	/**
	 * Requests start of fade tracking on the specified component.
	 * 
	 * @param comp
	 *            The component to track.
	 * @param fadeKind
	 *            Fade kind.
	 * @param isFadeIn
	 *            Indication whether fade-in or fade-out should be commenced.
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFade(Component comp, FadeKind fadeKind,
			boolean isFadeIn, boolean toRepaintParent) {
		return this.trackFade(comp, fadeKind, isFadeIn, toRepaintParent, null);
	}

	/**
	 * Requests start of fade tracking on the specified component.
	 * 
	 * @param comp
	 *            The component to track.
	 * @param fadeKind
	 *            Fade kind.
	 * @param isFadeIn
	 *            Indication whether fade-in or fade-out should be commenced.
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFade(Component comp, FadeKind fadeKind,
			boolean isFadeIn, boolean toRepaintParent,
			FadeTrackerCallback callback) {
		if (isFadeIn)
			return this.trackFadeIn(fadeKind, comp, toRepaintParent, callback);
		else
			return this.trackFadeOut(fadeKind, comp, toRepaintParent, callback);
	}

	/**
	 * Requests start of looping fade tracking on the specified component.
	 * 
	 * @param fadeKind
	 *            Fade kind.
	 * @param animationKind
	 *            Animation kind.
	 * @param comp
	 *            The component to track.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param toRepaintParent
	 *            Indication whether the component parent should be repainted.
	 * @param callback
	 *            Optional callback to be called on each fade cycle.
	 * @param loopStepFactor
	 *            Loop step factor. Is used to make the animation slower /
	 *            faster. Values less than 1.0 will make the animation slower,
	 *            values greater than 1.0 will make the animation faster.
	 * @param isLoopingReverse
	 *            If true, when the fade value gets to the
	 *            maximal value, the fade cycle will begin fade-out. Otherwise
	 *            the fade cycle will begin from 0, continuing to fade-in.
	 * @return ID of the fade instance. Guaranteed to be unique. Value
	 *         -1 signifies that there was no fade instance
	 *         created (this may happen when the specified component is not
	 *         visible).
	 */
	public synchronized long trackFadeLooping(FadeKind fadeKind,
			AnimationKind animationKind, Component comp,
			Comparable componentId, boolean toRepaintParent,
			FadeTrackerCallback callback, boolean isLoopingReverse) {
		if (!comp.isDisplayable())
			return -1;

		this.getThread();

		// see if it's already tracked
		FadeState fadeState = this.getState(fadeKind, comp, componentId);
		if (fadeState == null) {
			fadeState = new FadeState(fadeKind, 0, true, toRepaintParent);
			fadeState.fadeStep = animationKind.getStep();
			fadeState.isLooping = true;
			fadeState.isLoopingReverse = isLoopingReverse;
			this.addState(comp, componentId, fadeKind, fadeState);
		} else {
			fadeState.isLooping = true;
			fadeState.isLoopingReverse = isLoopingReverse;
		}
		fadeState.callback = callback;
		return fadeState.id;
	}

	/**
	 * Checks whether the specified component is being tracked by
	 * this tracker. Effectively returns indication whether the
	 * specified component is in fade-in or fade-out animation of the specified
	 * kind.
	 * 
	 * @param comp
	 *            Component.
	 * @param fadeKind
	 *            Fade kind.
	 * @return true if the specified component is being tracked
	 *         by this tracker, false otherwise.
	 */
	public boolean isTracked(Component comp, FadeKind fadeKind) {
		return this.isTracked(comp, 0, fadeKind);
	}

	/**
	 * Checks whether the specified component is being tracked by
	 * this tracker. Effectively returns indication whether the
	 * specified component is in fade-in or fade-out animation of the specified
	 * kind.
	 * 
	 * @param comp
	 *            Component.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param fadeKind
	 *            Fade kind.
	 * @return true if the specified component is being tracked
	 *         by this tracker, false otherwise.
	 */
	public boolean isTracked(Component comp, int componentId, FadeKind fadeKind) {
		return this.isTracked(comp, new Integer(componentId), fadeKind);
	}

	/**
	 * Checks whether the specified component is being tracked by
	 * this tracker. Effectively returns indication whether the
	 * specified component is in fade-in or fade-out animation of the specified
	 * kind.
	 * 
	 * @param comp
	 *            Component.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param fadeKind
	 *            Fade kind.
	 * @return true if the specified component is being tracked
	 *         by this tracker, false otherwise.
	 */
	public boolean isTracked(Component comp, Comparable componentId,
			FadeKind fadeKind) {
		ComponentId cid = new ComponentId(comp, componentId);
		Map map = (Map) this.trackedComponents.get(cid);
		if (map == null)
			return false;

		if (fadeKind == null)
			return (map.size() > 0);

		return map.containsKey(fadeKind);
	}

	/**
	 * Returns the fade cycle for the specified component. The result will be in
	 * 0.0-10.0 range.
	 * 
	 * @param comp
	 *            Component.
	 * @param fadeKind
	 *            Fade kind.
	 * @return The fade cycle for the specified component. For components that
	 *         are not tracked (when
	 *         {@link #isTracked(Component, org.jvnet.lafwidget.utils.FadeTracker.FadeKind)}
	 *         returns false), value 0 (zero) is returned.
	 */
	public synchronized float getFade10(Component comp, FadeKind fadeKind) {
		return this.getFade10(comp, 0, fadeKind);
	}

	/**
	 * Returns the fade cycle for the specified component. The result will be in
	 * 0.0-10.0 range.
	 * 
	 * @param comp
	 *            Component.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param fadeKind
	 *            Fade kind.
	 * @return The fade cycle for the specified component. For components that
	 *         are not tracked (when
	 *         {@link #isTracked(Component, org.jvnet.lafwidget.utils.FadeTracker.FadeKind)}
	 *         returns false), value 0 (zero) is returned.
	 */
	public synchronized float getFade10(Component comp, int componentId,
			FadeKind fadeKind) {
		return this.getFade10(comp, new Integer(componentId), fadeKind);
	}

	/**
	 * Returns the fade cycle for the specified component. The result will be in
	 * 0.0-10.0 range.
	 * 
	 * @param comp
	 *            Component.
	 * @param componentId
	 *            Component id. Relevant for such components as tabbed panes
	 *            (where fade is performed on component "sub" parts).
	 * @param fadeKind
	 *            Fade kind.
	 * @return The fade cycle for the specified component. For components that
	 *         are not tracked (when
	 *         {@link #isTracked(Component, org.jvnet.lafwidget.utils.FadeTracker.FadeKind)}
	 *         returns false), value 0 (zero) is returned.
	 */
	public synchronized float getFade10(Component comp, Comparable componentId,
			FadeKind fadeKind) {
		ComponentId cid = new ComponentId(comp, componentId);
		Map map = (Map) this.trackedComponents.get(cid);
		if ((map == null) || (map.size() == 0))
			return 0;

		if (fadeKind == null) {
			// take the first entry
			for (Iterator it = map.values().iterator(); it.hasNext();) {
				FadeState fs = (FadeState) it.next();
				return fs.fadePosition;
			}
		}

		FadeState state = (FadeState) map.get(fadeKind);
		if (state == null)
			return 0;
		return state.fadePosition;
	}

	/**
	 * Stops tracking of all components. Note that this function does not
	 * stop the fade thread ({@link #trackerThread}).
	 */
	public synchronized void stopAllTimers() {
		for (Iterator itComp = this.trackedComponents.entrySet().iterator(); itComp
				.hasNext();) {
			Map.Entry entryComp = (Map.Entry) itComp.next();
			Map mapComp = (Map) entryComp.getValue();
			for (Iterator itKind = mapComp.entrySet().iterator(); itKind
					.hasNext();) {
				Map.Entry entryKind = (Map.Entry) itKind.next();
				FadeState state = (FadeState) entryKind.getValue();
				if (state.callback != null)
					state.callback.fadeEnded(state.fadeKind);
			}
		}
		this.trackedComponents.clear();
		this.fadeInstances.clear();
	}

	/**
	 * Returns an instance of the tracker thread.
	 * 
	 * @return The tracker thread.
	 */
	private synchronized FadeTrackerThread getThread() {
		if (this.trackerThread == null) {
			this.trackerThread = new FadeTrackerThread();
			this.trackerThread.start();
		}
		return this.trackerThread;
	}

	/**
	 * Cancels the specified fade instance.
	 * 
	 * @param fadeInstanceId
	 *            Fade instance ID.
	 */
	public synchronized void cancelFadeInstance(long fadeInstanceId) {
		ComponentId cid = (ComponentId) this.fadeInstances.get(new Long(
				fadeInstanceId));
		if (cid != null) {
			Map compFades = (Map) this.trackedComponents.get(cid);
			for (Iterator itKind = compFades.entrySet().iterator(); itKind
					.hasNext();) {
				Map.Entry entryKind = (Map.Entry) itKind.next();
				FadeState state = (FadeState) entryKind.getValue();
				if (fadeInstanceId == state.id) {
					itKind.remove();
					state.callback.fadeEnded(state.fadeKind);
				}
			}
			if (compFades.size() == 0) {
				this.trackedComponents.remove(cid);
			}

			this.fadeInstances.remove(new Long(fadeInstanceId));
		}
	}

	/**
	 * Requests that the specified fade instance should stop at the end of the
	 * fade-out. This method should be called only on looping fades.
	 * 
	 * @param fadeInstanceId
	 *            Fade instance ID.
	 */
	public synchronized void requestStopOnCycleBreak(long fadeInstanceId) {
		ComponentId cid = (ComponentId) this.fadeInstances.get(new Long(
				fadeInstanceId));
		if (cid != null) {
			Map compFades = (Map) this.trackedComponents.get(cid);
			for (Iterator itKind = compFades.entrySet().iterator(); itKind
					.hasNext();) {
				Map.Entry entryKind = (Map.Entry) itKind.next();
				FadeState state = (FadeState) entryKind.getValue();
				if (fadeInstanceId == state.id) {
					state.toStopAtCycleBreak();
				}
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy