Mega Code Archive

 
Categories / Java / Advanced Graphics
 

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();   } }