All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
it.tidalwave.swing.FadingPanel Maven / Gradle / Ivy
/***********************************************************************************************************************
*
* OpenBlueSky - NetBeans Platform Enhancements
* Copyright (C) 2006-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
*
***********************************************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
***********************************************************************************************************************
*
* WWW: http://openbluesky.kenai.com
* SCM: https://kenai.com/hg/openbluesky~src
*
**********************************************************************************************************************/
package it.tidalwave.swing;
import it.tidalwave.swing.layout.CenterLayout;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;
import java.awt.CardLayout;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
//class AveragingKernel extends Kernel
// {
// public AveragingKernel (int size)
// {
// super(size, size, getData(size * size));
// }
//
// private static float[] getData (int size)
// {
// float[] data = new float[size];
//
// for (int i = 0; i < size; i++)
// {
// data[i] = 1.0f / size;
// }
//
// return data;
// }
// }
/*******************************************************************************
*
* @author Fabrizio Giudici
* @version $Id$
*
******************************************************************************/
public class FadingPanel extends JPanel
{
private static final String CLASS = FadingPanel.class.getName();
private static final Logger logger = Logger.getLogger(CLASS);
/** How many frames per second are painted. */
private static final int DEFAULT_TRANSITON_DURATION = 500;
/** The overall duration of the transition. */
private static final int FRAMES_PER_SECOND = 15;
private static final String CONTENTS = "contents";
private static final String TRANSITION = "transition";
private int transitionDuration = DEFAULT_TRANSITON_DURATION;
/** The contained component. */
private JComponent content;
/** The image which contains the snapshot of the previous contents. */
private Image oldSnapshotImage;
/** The image which contains the snapshot of the new contents. */
private Image newSnapshotImage;
/** The timer for the transition effect. */
private Timer transitionTimer;
/** The alpha component: 0.0 means the old snapshot is shown, 1.0 means the new contents are shown. */
private float alpha = 1f;
/** The alpha composite to blend the contents. */
private AlphaComposite alphaComposite;
/** The start time of the latest transition. */
private long startTime;
private CardLayout cardLayout = new CardLayout();
private boolean locked;
private boolean transitioning;
private Timer waitingLabelDelayTimer;
private int delayForWaitingLabel = 150;
private final TransitionPanel transitionComponent = new TransitionPanel();
private WaitingComponent waitingComponent;
/***************************************************************************
*
*
**************************************************************************/
public static interface Unlocker
{
public void run()
throws Exception;
}
/***************************************************************************
*
* This component is able to paint a blend of the old and new snapshot image,
* according to the current alphaComposite.
*
**************************************************************************/
class TransitionPanel extends JPanel
{
public TransitionPanel()
{
setLayout(new CenterLayout());
}
@Override
public void paint (final Graphics g)
{
final Graphics2D g2 = (Graphics2D)g;
if (oldSnapshotImage == null)
{
content.paint(g);
}
else
{
g2.drawImage(oldSnapshotImage, 0, 0, null);
}
if ((newSnapshotImage != null) && (alphaComposite != null))
{
final Composite compositeSave = g2.getComposite();
g2.setComposite(alphaComposite);
g2.drawImage(newSnapshotImage, 0, 0, null);
g2.setComposite(compositeSave);
}
super.paintComponents(g);
}
};
/***************************************************************************
*
*
**************************************************************************/
private final ActionListener transitionTimerListener = new ActionListener()
{
public void actionPerformed (final ActionEvent event)
{
computeAlpha();
logger.finer(">>>> Painting alpha = " + alpha);
long time = System.currentTimeMillis();
paintImmediately(getBounds());
time = System.currentTimeMillis() - time;
logger.finest(">>>>>>>> paintImmediately() took " + time + " msec");
}
};
/***************************************************************************
*
*
**************************************************************************/
public FadingPanel (final JComponent content)
{
this.content = content;
transitionTimer = new Timer(0, transitionTimerListener);
transitionTimer.setCoalesce(true);
transitionTimer.setDelay(1000 / FRAMES_PER_SECOND);
setLayout(cardLayout);
add(content, CONTENTS);
add(transitionComponent, TRANSITION);
setDoubleBuffered(true);
setOpaque(false);
}
public void setTransitionDuration (final int transitionDuration)
{
this.transitionDuration = transitionDuration;
}
public int getTransitionDuration()
{
return transitionDuration;
}
/***************************************************************************
*
* Sets the initial delay before a "waiting" label is painted. If set to 0,
* the label is painted immediately.
*
* @param delayForWaitingLabel the delay
*
**************************************************************************/
public void setDelayForWaitingLabel (final int delayForWaitingLabel)
{
this.delayForWaitingLabel = delayForWaitingLabel;
}
/***************************************************************************
*
* Returns the initial delay.
*
* @return the initial delay
*
**************************************************************************/
public int getDelayForWaitingLabel()
{
return delayForWaitingLabel;
}
/***************************************************************************
*
*
**************************************************************************/
public void lock()
{
lock("Please wait...");
}
/***************************************************************************
*
*
**************************************************************************/
public void lock (final String message)
{
lock(createWaitingComponent(message));
}
/***************************************************************************
*
* Unlocks the component, taking a snapshot of the new contents and starting
* an animated transition. This method is thread-safe: can be called in any
* thread.
*
**************************************************************************/
public void lock (final JComponent overlay)
{
if (!isVisible())
{
return;
}
if (SwingUtilities.isEventDispatchThread())
{
doLock(overlay);
}
else
{
try
{
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
doLock(overlay);
}
});
}
catch (InvocationTargetException e)
{
logger.throwing(CLASS, "lock()", e);
}
catch (InterruptedException e)
{
logger.throwing(CLASS, "lock()", e);
}
}
}
/***************************************************************************
*
*
**************************************************************************/
public void prepareUnlock()
{
if (!isVisible())
{
return;
}
mustBeAWTThread();
logger.finer(">>>> taking a snapshot of old content: " + content);
oldSnapshotImage = takeSnapshot();
paintImmediately(getBounds());
}
/***************************************************************************
*
* Unlocks the component, taking a snapshot of the new contents and starting
* an animated transition.
*
**************************************************************************/
public void unlock()
{
if (!isVisible())
{
return;
}
mustBeAWTThread();
doUnlock();
}
/***************************************************************************
*
* Unlocks the component, taking a snapshot of the new contents and starting
* an animated transition.
*
**************************************************************************/
public void unlock (final Unlocker unlocker)
{
mustBeAWTThread();
try
{
prepareUnlock();
unlocker.run();
}
catch (Exception e)
{
logger.throwing(CLASS, "unlock()", e);
}
finally
{
doUnlock();
}
}
// public void unlock()
// {
// if (SwingUtilities.isEventDispatchThread())
// {
// doUnlock();
// }
//
// else
// {
// try
// {
// SwingUtilities.invokeAndWait(new Runnable()
// {
// public void run()
// {
// doUnlock();
// }
// });
// }
// catch (InvocationTargetException e)
// {
// logger.throwing(CLASS, "unlock()", e);
// }
// catch (InterruptedException e)
// {
// logger.throwing(CLASS, "unlock()", e);
// }
// }
// }
/***************************************************************************
*
*
**************************************************************************/
public boolean isLocked()
{
return locked;
}
/***************************************************************************
*
*
**************************************************************************/
@Override
public void paint (final Graphics g)
{
super.paint(g);
logger.fine("paint() - " + getBounds());
}
/***************************************************************************
*
*
**************************************************************************/
protected JComponent createWaitingComponent (final String message)
{
if (waitingComponent == null)
{
waitingComponent = new WaitingComponent();
}
waitingComponent.setText(message);
return waitingComponent;
}
/***************************************************************************
*
*
**************************************************************************/
private void doLock (final JComponent overlay)
{
logger.fine("doLock() - " + this);
locked = true;
if (delayForWaitingLabel == 0)
{
if (overlay != null)
{
overlay.setVisible(true);
}
}
//
// After a certain delay show the overlay.
//
else
{
if (overlay != null)
{
overlay.setVisible(false);
}
waitingLabelDelayTimer = new Timer(delayForWaitingLabel, new ActionListener()
{
public void actionPerformed (ActionEvent e)
{
if (locked) // still locked?
{
overlay.setVisible(true);
//// paintImmediately(getBounds());
}
}
});
waitingLabelDelayTimer.setRepeats(false);
waitingLabelDelayTimer.start();
}
if (transitionTimer.isRunning())
{
transitionTimer.stop();
}
transitionComponent.removeAll();
if (overlay != null)
{
transitionComponent.add(overlay);
}
cardLayout.show(this, TRANSITION);
}
/***************************************************************************
*
*
**************************************************************************/
private void doUnlock()
{
logger.fine("doUnlock()");
// if (!locked) // FIXME
// {
// startTransition();
// }
locked = false;
startTime = System.currentTimeMillis();
// computeAlpha();
if ((waitingLabelDelayTimer != null) && waitingLabelDelayTimer.isRunning())
{
waitingLabelDelayTimer.stop();
}
repaint();
final Timer ttt = new Timer(0, new ActionListener()
{
public void actionPerformed (final ActionEvent event)
{
logger.finer(">>>> taking a snapshot of new content: " + content);
newSnapshotImage = takeSnapshot();
transitioning = true;
transitionTimer.start();
}
});
ttt.setRepeats(false);
ttt.setInitialDelay(100);
ttt.start();
}
/***************************************************************************
*
*
**************************************************************************/
private void computeAlpha()
{
logger.finer("computeAlpha()");
final long deltaTime = System.currentTimeMillis() - startTime;
alpha = (float)Math.max(0.0, Math.min(1.0, (double)deltaTime / transitionDuration));
alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
if (alpha == 1.0)
{
logger.fine(">>>> alpha is 1.0, stopping transitionTimer, restoring contents");
transitionTimer.stop();
oldSnapshotImage = null;
newSnapshotImage = null;
alphaComposite = null;
transitioning = false;
// content.setIgnoreRepaint(false);
cardLayout.show(this, CONTENTS);
transitionComponent.removeAll();
}
}
/***************************************************************************
*
* Takes a snapshot of the current contents, with the given overlay.
*
* @param overlay the overlay (null if none)
* @return
*
**************************************************************************/
private Image takeSnapshot()
{
logger.fine("takeSnapshot()");
if (!isValid())
{
logger.warning("Something is wrong, takeSnapshot() but I'm not valid");
}
final int width = content.getWidth();
final int height = content.getHeight();
logger.finest(">>>> snapshot size: " + width + " x " + height);
final BufferedImage image = createCompatibleImage(Math.max(1, width), Math.max(1, height));
// TODO: use VolatileImage?
final Graphics g = image.getGraphics();
try
{
//content.doLayout();
content.paint(g);
}
finally
{
g.dispose();
}
return image;
}
/***************************************************************************
*
*
**************************************************************************/
private static BufferedImage createCompatibleImage (final int width, final int height)
{
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice gs = ge.getDefaultScreenDevice();
final GraphicsConfiguration gc = gs.getDefaultConfiguration();
return gc.createCompatibleImage(width, height);
}
/***************************************************************************
*
*
**************************************************************************/
private void mustBeAWTThread()
{
if (!SwingUtilities.isEventDispatchThread())
{
throw new IllegalStateException("Must be called by the AWT-Thread");
}
}
}