Background Animation
/*
* Copyright (c) 2007, Romain Guy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the TimingFramework project 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.
*/
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* @author Romain Guy
*/
public class BackgroundAnimation_2008 extends JFrame {
private AvatarChooser chooser;
private CurvesPanel curves;
public BackgroundAnimation_2008() throws HeadlessException {
super("Stack Layout");
buildContentPane();
// buildDebugControls();
startAnimation();
setSize(640, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void startAnimation() {
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
curves.animate();
curves.repaint();
}
});
timer.start();
}
private void buildDebugControls() {
JPanel pane = new JPanel(new BorderLayout());
pane.setBackground(Color.WHITE);
pane.add(new JSeparator(), BorderLayout.NORTH);
final GraphPanel grapher = new GraphPanel();
JPanel graphPane = new JPanel(new FlowLayout(FlowLayout.CENTER));
graphPane.setOpaque(false);
graphPane.add(grapher);
JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.CENTER));
buttonsPane.setOpaque(false);
JSlider spacing = new JSlider(JSlider.HORIZONTAL, 0, 100, 40);
spacing.setBackground(Color.WHITE);
spacing.setPreferredSize(new Dimension(95, spacing.getPreferredSize().height));
spacing.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
double spacing = slider.getValue() / 100.0;
chooser.setSpacing(spacing);
grapher.spacing = spacing;
grapher.repaint();
}
});
JSlider sigma = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
sigma.setBackground(Color.WHITE);
sigma.setPreferredSize(new Dimension(95, sigma.getPreferredSize().height));
sigma.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
double sigma = slider.getValue() / 100.0;
chooser.setSigma(sigma);
grapher.sigma = sigma;
grapher.repaint();
}
});
JSlider position = new JSlider(JSlider.HORIZONTAL, -100, 100, 0);
position.setBackground(Color.WHITE);
position.setPreferredSize(new Dimension(95, position.getPreferredSize().height));
position.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
double position = slider.getValue() / 100.0;
chooser.setPosition(position);
grapher.position = position;
grapher.repaint();
}
});
JSlider amount = new JSlider(JSlider.HORIZONTAL, 1, 15, 5);
amount.setBackground(Color.WHITE);
amount.setPreferredSize(new Dimension(95, position.getPreferredSize().height));
amount.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
int amount = slider.getValue();
chooser.setAmount(amount);
grapher.amount = amount;
grapher.repaint();
}
});
buttonsPane.add(new JLabel("Spacing: "));
buttonsPane.add(spacing);
buttonsPane.add(new JLabel("Sigma: "));
buttonsPane.add(sigma);
buttonsPane.add(new JLabel("Position: "));
buttonsPane.add(position);
buttonsPane.add(new JLabel("Amount: "));
buttonsPane.add(amount);
pane.add(buttonsPane, BorderLayout.NORTH);
pane.add(graphPane, BorderLayout.CENTER);
add(pane, BorderLayout.SOUTH);
}
private void buildContentPane() {
JPanel pane = new JPanel();
pane.setLayout(new StackLayout());
GradientPanel gradient = new GradientPanel();
chooser = new AvatarChooser();
curves = new CurvesPanel();
pane.add(gradient, StackLayout.TOP);
pane.add(chooser, StackLayout.TOP);
pane.add(curves, StackLayout.TOP);
add(pane);
}
private class GraphPanel extends JComponent {
private double spacing = 0.4;
private double position = 0.0;
private double sigma = 0.5;
private int amount = 5;
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 60);
}
@Override
public boolean isOpaque() {
return false;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLACK);
g2.drawLine(0, 50, 100, 50);
g2.drawLine(50, 0, 50, 60);
g2.setColor(Color.BLUE);
double lastY = 50.0;
for (int x = 0; x < 100; x++) {
double y = chooser.computeModifier((50.0 - x) / 25.0) * 45.0 + 10;
if (x == 0) {
lastY = y;
}
g2.drawLine(x - 1, 60 - (int) lastY, x, 60 - (int) y);
lastY = y;
}
g2.setColor(Color.RED);
for (int i = 0; i < amount; i++) {
double offset = ((amount / 2) - i) * spacing;
double x = (100.0 - 5.0) / 2.0;
x += 25.0 * (position + offset);
if (x > 100) {
continue;
}
double y = 60.0 - (chooser.computeModifier(position + offset) * 45.0 + 10);
g2.fill(new Rectangle2D.Double(x, y - 1, 5.0, 5.0));
}
g2.setColor(Color.GREEN.darker());
g2.drawLine(25, 0, 25, 60);
g2.drawLine(75, 0, 75, 60);
g2.setColor(Color.DARK_GRAY);
g2.drawString("Sigma: " + sigma, 110.0f, 16.0f);
g2.drawString("Spacing: " + spacing, 110.0f, 30.0f);
g2.drawString("Position: " + position, 110.0f, 44.0f);
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();
} catch (InstantiationException ex) {
ex.printStackTrace();
} catch (UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
BackgroundAnimation_2008 tester = new BackgroundAnimation_2008();
tester.setVisible(true);
}
});
}
}
/*
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * 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. * Neither the name of the
* TimingFramework project 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.
*/
class AvatarChooser extends JPanel {
private static final double ANIM_SCROLL_DELAY = 450;
private List<Image> avatars = null;
private boolean loadingDone = false;
private Thread picturesFinder = null;
private Timer scrollerTimer = null;
private Timer faderTimer = null;
private Timer passwordTimer;
private float veilAlphaLevel = 0.0f;
private float alphaLevel = 0.0f;
private float textAlphaLevel = 0.0f;
private int avatarIndex;
private double avatarPosition = 0.0;
private double avatarSpacing = 0.4;
private int avatarAmount = 5;
private double sigma;
private double rho;
private double exp_multiplier;
private double exp_member;
private boolean damaged = true;
private DrawableAvatar[] drawableAvatars;
private String textAvatar;
private FocusGrabber focusGrabber;
private AvatarScroller avatarScroller;
private CursorChanger cursorChanger;
private MouseWheelScroller wheelScroller;
private KeyScroller keyScroller;
public AvatarChooser() {
GridBagLayout layout = new GridBagLayout();
setLayout(layout);
findAvatars();
setSigma(0.5);
addComponentListener(new DamageManager());
initInputListeners();
addInputListeners();
}
public void setAmount(int amount) {
if (amount > avatars.size()) {
throw new IllegalArgumentException("Too many avatars");
}
this.avatarAmount = amount;
repaint();
}
// XXX package access for debugging purpose only
void setPosition(double position) {
this.avatarPosition = position;
this.damaged = true;
repaint();
}
public void setSigma(double sigma) {
this.sigma = sigma;
this.rho = 1.0;
computeEquationParts();
this.rho = computeModifierUnprotected(0.0);
computeEquationParts();
this.damaged = true;
repaint();
}
public void setSpacing(double avatarSpacing) {
if (avatarSpacing < 0.0 || avatarSpacing > 1.0) {
throw new IllegalArgumentException("Spacing must be < 1.0 and > 0.0");
}
this.avatarSpacing = avatarSpacing;
this.damaged = true;
repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(128 * 3, 128 * 2);
}
@Override
public Dimension getMaximumSize() {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
@Override
public boolean isOpaque() {
return false;
}
@Override
public boolean isFocusable() {
return true;
}
@Override
protected void paintChildren(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Composite oldComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, veilAlphaLevel));
super.paintChildren(g);
g2.setComposite(oldComposite);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (!loadingDone && faderTimer == null) {
return;
}
Insets insets = getInsets();
int x = insets.left;
int y = insets.top;
int width = getWidth() - insets.left - insets.right;
int height = getHeight() - insets.top - insets.bottom;
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Composite oldComposite = g2.getComposite();
if (damaged) {
drawableAvatars = sortAvatarsByDepth(x, y, width, height);
damaged = false;
}
drawAvatars(g2, drawableAvatars);
if (drawableAvatars.length > 0) {
drawAvatarName(g2);
}
g2.setComposite(oldComposite);
}
private void drawAvatars(Graphics2D g2, DrawableAvatar[] drawableAvatars) {
for (DrawableAvatar avatar : drawableAvatars) {
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) avatar
.getAlpha());
g2.setComposite(composite);
g2.drawImage(avatars.get(avatar.getIndex()), (int) avatar.getX(), (int) avatar.getY(), avatar
.getWidth(), avatar.getHeight(), null);
}
}
private DrawableAvatar[] sortAvatarsByDepth(int x, int y, int width, int height) {
List<DrawableAvatar> drawables = new LinkedList<DrawableAvatar>();
for (int i = 0; i < avatars.size(); i++) {
promoteAvatarToDrawable(drawables, x, y, width, height, i - avatarIndex);
}
DrawableAvatar[] drawableAvatars = new DrawableAvatar[drawables.size()];
drawableAvatars = drawables.toArray(drawableAvatars);
Arrays.sort(drawableAvatars);
return drawableAvatars;
}
private void drawAvatarName(Graphics2D g2) {
Composite composite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, textAlphaLevel));
double bulletWidth = 150.0;
double bulletHeight = 30.0;
double x = (getWidth() - bulletWidth) / 2.0;
double y = (getHeight() - 164) / 2.0 - bulletHeight * 1.4;
drawAvatarBullet(g2, x, y, bulletWidth, bulletHeight);
drawAvatarText(g2, y, bulletHeight);
g2.setComposite(composite);
}
private void drawAvatarText(Graphics2D g2, double y, double bulletHeight) {
FontRenderContext context = g2.getFontRenderContext();
Font font = new Font("Dialog", Font.PLAIN, 18);
TextLayout layout = new TextLayout(textAvatar, font, context);
Rectangle2D bounds = layout.getBounds();
float text_x = (float) ((getWidth() - bounds.getWidth()) / 2.0);
float text_y = (float) (y + (bulletHeight - layout.getAscent() - layout.getDescent()) / 2.0)
+ layout.getAscent() - layout.getLeading();
g2.setColor(Color.BLACK);
layout.draw(g2, text_x, text_y + 1);
g2.setColor(Color.WHITE);
layout.draw(g2, text_x, text_y);
}
private void drawAvatarBullet(Graphics2D g2, double x, double y, double bulletWidth,
double bulletHeight) {
RoundRectangle2D bullet = new RoundRectangle2D.Double(0.0, 0.0, bulletWidth, bulletHeight,
bulletHeight, bulletHeight);
Ellipse2D curve = new Ellipse2D.Double(-20.0, bulletHeight / 2.0, bulletWidth + 40.0,
bulletHeight);
g2.translate(x, y);
g2.translate(-1, -2);
g2.setColor(new Color(0, 0, 0, 170));
g2.fill(new RoundRectangle2D.Double(0.0, 0.0, bulletWidth + 2, bulletHeight + 4,
bulletHeight + 4, bulletHeight + 4));
g2.translate(1, 2);
Color startColor = new Color(10, 0, 40);
Color endColor = new Color(175, 165, 225);
Paint paint = g2.getPaint();
g2.setPaint(new GradientPaint(0.0f, 0.0f, startColor, 0.0f, (float) bulletHeight, endColor));
g2.fill(bullet);
startColor = new Color(5, 0, 50);
endColor = new Color(105, 100, 155);
g2.setPaint(new GradientPaint(0.0f, 0.0f, startColor, 0.0f, (float) bulletHeight, endColor));
Area area = new Area(bullet);
area.intersect(new Area(curve));
g2.fill(area);
g2.setPaint(paint);
g2.translate(-x, -y);
}
private void promoteAvatarToDrawable(List<DrawableAvatar> drawables, int x, int y, int width,
int height, int offset) {
double spacing = offset * avatarSpacing;
double avatarPosition = this.avatarPosition + spacing;
if (avatarIndex + offset < 0 || avatarIndex + offset >= avatars.size()) {
return;
}
Image avatar = avatars.get(avatarIndex + offset);
int avatarWidth = avatar.getWidth(null);
int avatarHeight = avatar.getHeight(null);
double result = computeModifier(avatarPosition);
int newWidth = (int) (avatarWidth * result);
if (newWidth == 0) {
return;
}
int newHeight = (int) (avatarHeight * result);
if (newHeight == 0) {
return;
}
double avatar_x = x + (width - newWidth) / 2.0;
double avatar_y = y + (height - newHeight / 2.0) / 2.0;
double semiWidth = width / 2.0;
avatar_x += avatarPosition * semiWidth;
if (avatar_x >= width || avatar_x < -newWidth) {
return;
}
drawables.add(new DrawableAvatar(avatarIndex + offset, avatar_x, avatar_y, newWidth, newHeight,
avatarPosition, result));
}
private void startFader() {
faderTimer = new Timer(35, new FaderAction());
faderTimer.start();
}
private void computeEquationParts() {
exp_multiplier = Math.sqrt(2.0 * Math.PI) / sigma / rho;
exp_member = 4.0 * sigma * sigma;
}
// XXX package access for debug purpose only
double computeModifier(double x) {
double result = computeModifierUnprotected(x);
if (result > 1.0) {
result = 1.0;
} else if (result < -1.0) {
result = -1.0;
}
return result;
}
private double computeModifierUnprotected(double x) {
return exp_multiplier * Math.exp((-x * x) / exp_member);
}
private void addInputListeners() {
addMouseListener(focusGrabber);
addMouseListener(avatarScroller);
addMouseMotionListener(cursorChanger);
addMouseWheelListener(wheelScroller);
addKeyListener(keyScroller);
}
private void initInputListeners() {
// input listeners are all stateless
// hence they can be instantiated once
focusGrabber = new FocusGrabber();
avatarScroller = new AvatarScroller();
cursorChanger = new CursorChanger();
wheelScroller = new MouseWheelScroller();
keyScroller = new KeyScroller();
}
private void removeInputListeners() {
removeMouseListener(focusGrabber);
removeMouseListener(avatarScroller);
removeMouseMotionListener(cursorChanger);
removeMouseWheelListener(wheelScroller);
removeKeyListener(keyScroller);
}
private void findAvatars() {
avatars = new ArrayList<Image>();
picturesFinder = new Thread(new PicturesFinderThread());
picturesFinder.start();
}
private void setAvatarIndex(int index) {
avatarIndex = index;
textAvatar = "Photo " + index;
}
private void scrollBy(int increment) {
if (loadingDone) {
setAvatarIndex(avatarIndex + increment);
if (avatarIndex < 0) {
setAvatarIndex(0);
} else if (avatarIndex >= avatars.size()) {
setAvatarIndex(avatars.size() - 1);
}
damaged = true;
repaint();
}
}
private void scrollAndAnimateBy(int increment) {
if (loadingDone && (scrollerTimer == null || !scrollerTimer.isRunning())) {
int index = avatarIndex + increment;
if (index < 0) {
index = 0;
} else if (index >= avatars.size()) {
index = avatars.size() - 1;
}
DrawableAvatar drawable = null;
for (DrawableAvatar avatar : drawableAvatars) {
if (avatar.index == index) {
drawable = avatar;
break;
}
}
if (drawable != null) {
scrollAndAnimate(drawable);
}
}
}
private void scrollAndAnimate(DrawableAvatar avatar) {
if (loadingDone) {
scrollerTimer = new Timer(10, new AutoScroller(avatar));
scrollerTimer.start();
}
}
private BufferedImage createReflectedPicture(BufferedImage avatar) {
int avatarWidth = avatar.getWidth();
int avatarHeight = avatar.getHeight();
BufferedImage alphaMask = createGradientMask(avatarWidth, avatarHeight);
return createReflectedPicture(avatar, alphaMask);
}
private BufferedImage createReflectedPicture(BufferedImage avatar, BufferedImage alphaMask) {
int avatarWidth = avatar.getWidth();
int avatarHeight = avatar.getHeight();
BufferedImage buffer = createReflection(avatar, avatarWidth, avatarHeight);
applyAlphaMask(buffer, alphaMask, avatarWidth, avatarHeight);
return buffer;
}
private void applyAlphaMask(BufferedImage buffer, BufferedImage alphaMask, int avatarWidth,
int avatarHeight) {
Graphics2D g2 = buffer.createGraphics();
g2.setComposite(AlphaComposite.DstOut);
g2.drawImage(alphaMask, null, 0, avatarHeight);
g2.dispose();
}
private BufferedImage createReflection(BufferedImage avatar, int avatarWidth, int avatarHeight) {
BufferedImage buffer = new BufferedImage(avatarWidth, avatarHeight << 1,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = buffer.createGraphics();
g.drawImage(avatar, null, null);
g.translate(0, avatarHeight << 1);
AffineTransform reflectTransform = AffineTransform.getScaleInstance(1.0, -1.0);
g.drawImage(avatar, reflectTransform, null);
g.translate(0, -(avatarHeight << 1));
g.dispose();
return buffer;
}
private BufferedImage createGradientMask(int avatarWidth, int avatarHeight) {
BufferedImage gradient = new BufferedImage(avatarWidth, avatarHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = gradient.createGraphics();
GradientPaint painter = new GradientPaint(0.0f, 0.0f, new Color(1.0f, 1.0f, 1.0f, 0.5f), 0.0f,
avatarHeight / 2.0f, new Color(1.0f, 1.0f, 1.0f, 1.0f));
g.setPaint(painter);
g.fill(new Rectangle2D.Double(0, 0, avatarWidth, avatarHeight));
g.dispose();
return gradient;
}
private DrawableAvatar getHitAvatar(int x, int y) {
for (DrawableAvatar avatar : drawableAvatars) {
Rectangle hit = new Rectangle((int) avatar.getX(), (int) avatar.getY(), avatar.getWidth(),
avatar.getHeight() / 2);
if (hit.contains(x, y)) {
return avatar;
}
}
return null;
}
private class PicturesFinderThread implements Runnable {
public void run() {
UnixGlobFileFilter allPngs = new UnixGlobFileFilter("*.jpg");
try {
FileTreeWalker walker = new FileTreeWalker(new File("."), allPngs);
PictureLoader loader = new PictureLoader();
walker.walk(loader);
List<File> files = loader.getFilesList();
for (int i = 0; i < files.size(); i++) {
BufferedImage image = ImageIO.read(files.get(i));
avatars.add(createReflectedPicture(image));
if (i == (files.size() / 2) + avatarAmount / 2) {
setAvatarIndex(i - avatarAmount / 2);
startFader();
}
}
} catch (IOException e) {
}
loadingDone = true;
}
private class PictureLoader implements FileTreeWalk {
private List<File> filesList;
private PictureLoader() {
filesList = new ArrayList<File>();
}
private List<File> getFilesList() {
Collections.sort(filesList);
return filesList;
}
public void walk(File path) {
filesList.add(path);
}
}
}
private class FaderAction implements ActionListener {
private long start = 0;
private FaderAction() {
alphaLevel = 0.0f;
textAlphaLevel = 0.0f;
}
public void actionPerformed(ActionEvent e) {
if (start == 0) {
start = System.currentTimeMillis();
}
alphaLevel = (System.currentTimeMillis() - start) / 500.0f;
textAlphaLevel = alphaLevel;
if (alphaLevel > 1.0f) {
alphaLevel = 1.0f;
textAlphaLevel = 1.0f;
faderTimer.stop();
}
repaint();
}
}
private class DrawableAvatar implements Comparable {
private int index;
private double x;
private double y;
private int width;
private int height;
private double zOrder;
private double position;
private DrawableAvatar(int index, double x, double y, int width, int height, double position,
double zOrder) {
this.index = index;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.position = position;
this.zOrder = zOrder;
}
public int compareTo(Object o) {
double zOrder2 = ((DrawableAvatar) o).zOrder;
if (zOrder < zOrder2) {
return -1;
} else if (zOrder > zOrder2) {
return 1;
}
return 0;
}
public double getPosition() {
return position;
}
public double getAlpha() {
return zOrder * alphaLevel;
}
public int getHeight() {
return height;
}
public int getIndex() {
return index;
}
public int getWidth() {
return width;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
private class MouseWheelScroller implements MouseWheelListener {
public void mouseWheelMoved(MouseWheelEvent e) {
int increment = e.getWheelRotation();
scrollAndAnimateBy(increment);
}
}
private class KeyScroller extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_LEFT:
case KeyEvent.VK_UP:
scrollAndAnimateBy(-1);
break;
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_DOWN:
scrollAndAnimateBy(1);
break;
case KeyEvent.VK_END:
scrollBy(avatars.size() - avatarIndex - 1);
break;
case KeyEvent.VK_HOME:
scrollBy(-avatarIndex - 1);
break;
case KeyEvent.VK_PAGE_UP:
scrollAndAnimateBy(-avatarAmount / 2);
break;
case KeyEvent.VK_PAGE_DOWN:
scrollAndAnimateBy(avatarAmount / 2);
break;
}
}
}
private class FocusGrabber extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
requestFocus();
}
}
private class AvatarScroller extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
if ((faderTimer != null && faderTimer.isRunning())
|| (scrollerTimer != null && scrollerTimer.isRunning()) || drawableAvatars == null) {
return;
}
if (e.getButton() == MouseEvent.BUTTON1) {
DrawableAvatar avatar = getHitAvatar(e.getX(), e.getY());
if (avatar != null && avatar.getIndex() != avatarIndex) {
scrollAndAnimate(avatar);
}
}
}
}
private class DamageManager extends ComponentAdapter {
@Override
public void componentResized(ComponentEvent e) {
damaged = true;
}
}
private class AutoScroller implements ActionListener {
private double position;
private int index;
private long start;
private AutoScroller(DrawableAvatar avatar) {
this.index = avatar.getIndex();
this.position = avatar.getPosition();
this.start = System.currentTimeMillis();
}
public void actionPerformed(ActionEvent e) {
long elapsed = System.currentTimeMillis() - start;
if (elapsed < ANIM_SCROLL_DELAY / 2.0) {
textAlphaLevel = (float) (1.0 - 2.0 * (elapsed / ANIM_SCROLL_DELAY));
} else {
textAlphaLevel = (float) (((elapsed / ANIM_SCROLL_DELAY) - 0.5) * 2.0);
if (textAlphaLevel > 1.0f) {
textAlphaLevel = 1.0f;
}
}
if (textAlphaLevel < 0.1f) {
textAlphaLevel = 0.1f;
textAvatar = "LoginName" + index;
}
double newPosition = (elapsed / ANIM_SCROLL_DELAY) * -position;
if (elapsed >= ANIM_SCROLL_DELAY) {
((Timer) e.getSource()).stop();
setAvatarIndex(index);
setPosition(0.0);
return;
}
setPosition(newPosition);
}
}
private class CursorChanger extends MouseMotionAdapter {
@Override
public void mouseMoved(MouseEvent e) {
if ((scrollerTimer != null && scrollerTimer.isRunning()) || drawableAvatars == null) {
return;
}
DrawableAvatar avatar = getHitAvatar(e.getX(), e.getY());
if (avatar != null) {
getParent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
getParent().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
}
/*
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * 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. * Neither the name of the
* TimingFramework project 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.
*/
class CurvesPanel extends JPanel {
protected RenderingHints hints;
protected int counter = 0;
protected Color start = new Color(255, 255, 255, 200);
protected Color end = new Color(255, 255, 255, 0);
public CurvesPanel() {
this(new BorderLayout());
}
public CurvesPanel(LayoutManager manager) {
super(manager);
hints = createRenderingHints();
}
protected RenderingHints createRenderingHints() {
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
return hints;
}
public void animate() {
counter++;
}
@Override
public boolean isOpaque() {
return false;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints oldHints = g2.getRenderingHints();
g2.setRenderingHints(hints);
float width = getWidth();
float height = getHeight();
g2.translate(0, -30);
drawCurve(g2, 20.0f, -10.0f, 20.0f, -10.0f, width / 2.0f - 40.0f, 10.0f, 0.0f, -5.0f,
width / 2.0f + 40, 1.0f, 0.0f, 5.0f, 50.0f, 5.0f, false);
g2.translate(0, 30);
g2.translate(0, height - 60);
drawCurve(g2, 30.0f, -15.0f, 50.0f, 15.0f, width / 2.0f - 40.0f, 1.0f, 15.0f, -25.0f,
width / 2.0f, 1.0f / 2.0f, 0.0f, 25.0f, 15.0f, 9.0f, false);
g2.translate(0, -height + 60);
drawCurve(g2, height - 35.0f, -5.0f, height - 50.0f, 10.0f, width / 2.0f - 40.0f, 1.0f,
height - 35.0f, -25.0f, width / 2.0f, 1.0f / 2.0f, height - 20.0f, 25.0f, 25.0f, 7.0f, true);
g2.setRenderingHints(oldHints);
}
protected void drawCurve(Graphics2D g2, float y1, float y1_offset, float y2, float y2_offset,
float cx1, float cx1_offset, float cy1, float cy1_offset, float cx2, float cx2_offset,
float cy2, float cy2_offset, float thickness, float speed, boolean invert) {
float width = getWidth();
float offset = (float) Math.sin(counter / (speed * Math.PI));
float start_x = 0.0f;
float start_y = offset * y1_offset + y1;
float end_x = width;
float end_y = offset * y2_offset + y2;
float ctrl1_x = offset * cx1_offset + cx1;
float ctrl1_y = offset * cy1_offset + cy1;
float ctrl2_x = offset * cx2_offset + cx2;
float ctrl2_y = offset * cy2_offset + cy2;
GeneralPath thickCurve = new GeneralPath();
thickCurve.moveTo(start_x, start_y);
thickCurve.curveTo(ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, end_x, end_y);
thickCurve.lineTo(end_x, end_y + thickness);
thickCurve.curveTo(ctrl2_x, ctrl2_y + thickness, ctrl1_x, ctrl1_y + thickness, start_x, start_y
+ thickness);
thickCurve.lineTo(start_x, start_y);
Rectangle bounds = thickCurve.getBounds();
if (!bounds.intersects(g2.getClipBounds())) {
return;
}
GradientPaint painter = new GradientPaint(0, bounds.y, invert ? end : start, 0, bounds.y
+ bounds.height, invert ? start : end);
Paint oldPainter = g2.getPaint();
g2.setPaint(painter);
g2.fill(thickCurve);
g2.setPaint(oldPainter);
}
}
/*
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * 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. * Neither the name of the
* TimingFramework project 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.
*/
class GradientPanel extends JPanel {
protected BufferedImage gradientImage;
protected Color gradientStart = new Color(204, 249, 124);
protected Color gradientEnd = new Color(174, 222, 94);
public GradientPanel() {
this(new BorderLayout());
}
public GradientPanel(LayoutManager layout) {
super(layout);
addComponentListener(new GradientCacheManager());
}
@Override
protected void paintComponent(Graphics g) {
createImageCache();
if (gradientImage != null) {
g.drawImage(gradientImage, 0, 0, getWidth(), getHeight(), null);
}
}
protected void createImageCache() {
int width = 2;
int height = getHeight();
if (width == 0 || height == 0) {
return;
}
if (gradientImage == null || width != gradientImage.getWidth()
|| height != gradientImage.getHeight()) {
gradientImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = gradientImage.createGraphics();
GradientPaint painter = new GradientPaint(0, 0, gradientEnd, 0, height / 2, gradientStart);
g2.setPaint(painter);
Rectangle2D rect = new Rectangle2D.Double(0, 0, width, height / 2.0);
g2.fill(rect);
painter = new GradientPaint(0, height / 2, gradientStart, 0, height, gradientEnd);
g2.setPaint(painter);
rect = new Rectangle2D.Double(0, (height / 2.0) - 1.0, width, height);
g2.fill(rect);
g2.dispose();
}
}
private void disposeImageCache() {
synchronized (gradientImage) {
gradientImage.flush();
gradientImage = null;
}
}
private class GradientCacheManager implements ComponentListener {
public void componentResized(ComponentEvent e) {
}
public void componentMoved(ComponentEvent e) {
}
public void componentShown(ComponentEvent e) {
}
public void componentHidden(ComponentEvent e) {
disposeImageCache();
}
}
}
/*
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * 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. * Neither the name of the
* TimingFramework project 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.
*/
/**
*
* @author Romain Guy <romain.guy@mac.com>
*/
class StackLayout implements LayoutManager2 {
public static final String BOTTOM = "bottom";
public static final String TOP = "top";
private List<Component> components = new LinkedList<Component>();
public void addLayoutComponent(Component comp, Object constraints) {
synchronized (comp.getTreeLock()) {
if (BOTTOM.equals(constraints)) {
components.add(0, comp);
} else if (TOP.equals(constraints)) {
components.add(comp);
} else {
components.add(comp);
}
}
}
public void addLayoutComponent(String name, Component comp) {
addLayoutComponent(comp, TOP);
}
public void removeLayoutComponent(Component comp) {
synchronized (comp.getTreeLock()) {
components.remove(comp);
}
}
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
public void invalidateLayout(Container target) {
}
public Dimension preferredLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
int width = 0;
int height = 0;
for (Component comp : components) {
Dimension size = comp.getPreferredSize();
width = Math.max(size.width, width);
height = Math.max(size.height, height);
}
Insets insets = parent.getInsets();
width += insets.left + insets.right;
height += insets.top + insets.bottom;
return new Dimension(width, height);
}
}
public Dimension minimumLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
int width = 0;
int height = 0;
for (Component comp : components) {
Dimension size = comp.getMinimumSize();
width = Math.max(size.width, width);
height = Math.max(size.height, height);
}
Insets insets = parent.getInsets();
width += insets.left + insets.right;
height += insets.top + insets.bottom;
return new Dimension(width, height);
}
}
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
public void layoutContainer(Container parent) {
synchronized (parent.getTreeLock()) {
int width = parent.getWidth();
int height = parent.getHeight();
Rectangle bounds = new Rectangle(0, 0, width, height);
int componentsCount = components.size();
for (int i = 0; i < componentsCount; i++) {
Component comp = components.get(i);
comp.setBounds(bounds);
parent.setComponentZOrder(comp, componentsCount - i - 1);
}
}
}
}
/*
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * 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. * Neither the name of the
* TimingFramework project 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.
*/
class FileTreeWalker {
private File path;
private static final FileFilter directoryFilter = new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory();
}
};
private FileFilter filter;
public FileTreeWalker(File path) throws IOException {
this(path, new FileFilter() {
public boolean accept(File pathname) {
return pathname.isFile();
}
});
}
public FileTreeWalker(File path, FileFilter filter) throws IOException {
if (path == null || !path.exists() || path.isFile()) {
throw new IOException("Path " + path + " is not a valid directory.");
}
this.path = path;
this.filter = filter;
}
public void walk(FileTreeWalk walk) {
walkDirectory(walk, path);
}
private void walkDirectory(FileTreeWalk walk, File dir) {
File[] files = dir.listFiles(filter);
for (File file : files) {
walk.walk(file);
}
File[] dirs = dir.listFiles(directoryFilter);
for (File subDir : dirs) {
walkDirectory(walk, subDir);
}
}
}
/*
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * 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. * Neither the name of the
* TimingFramework project 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.
*/
interface FileTreeWalk {
public void walk(File path);
}
/*
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * 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. * Neither the name of the
* TimingFramework project 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.
*/
/**
* @author Romain Guy
*/
class UnixGlobFileFilter implements FileFilter {
private Pattern pattern;
public UnixGlobFileFilter(String filter) {
pattern = Pattern.compile(globToRegex(filter));
}
public boolean accept(File file) {
String path = file.getName();
Matcher matcher = pattern.matcher(path);
return matcher.matches();
}
private String globToRegex(String glob) {
char c = '\0';
boolean escape = false;
boolean enclosed = false;
StringBuffer buffer = new StringBuffer(glob.length());
for (int i = 0; i < glob.length(); i++) {
c = glob.charAt(i);
if (escape) {
buffer.append('\\');
buffer.append(c);
escape = false;
continue;
}
switch (c) {
case '*':
buffer.append('.').append('*');
break;
case '?':
buffer.append('.');
break;
case '\\':
escape = true;
break;
case '.':
buffer.append('\\').append('.');
break;
case '{':
buffer.append('(');
enclosed = true;
break;
case '}':
buffer.append(')');
enclosed = false;
break;
case ',':
if (enclosed)
buffer.append('|');
else
buffer.append(',');
break;
default:
buffer.append(c);
}
}
return buffer.toString();
}
}
Related examples in the same category