/* * org.openmicroscopy.shoola.util.ui.AnimatedJFrame * *------------------------------------------------------------------------------ * Copyright (C) 2006-2008 University of Dundee. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.util.ui; //Java imports import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Box; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; //Third-party libraries //Application-internal dependencies import org.openmicroscopy.shoola.util.ui.border.OneLineBorder; /** * Animated frame. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author Donald MacDonald      * <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a> * @version 3.0 * <small> * (<b>Internal version:</b> $Revision: $Date: $) * </small> * @since 3.0-Beta4 */ public class AnimatedJFrame extends JFrame implements ActionListener { /** The default value of the duration of the animation. */ public static final float DURATION = 300f; /** The default value of the animation waiting time. */ public static final int SLEEP = 20; /** Animation direction's constants. */ private static final int INCOMING = 1; /** Animation direction's constants. */ public static final int OUTGOING = -1; /** Orientation of the animation .*/ public static final int UP_MIDDLE = 0; /** Orientation of the animation .*/ public static final int DOWN = 1; /** Orientation of the animation .*/ public static final int UP_RIGHT = 2; /** Orientation of the animation .*/ public static final int UP_LEFT = 3; /** The color of the line's border. */ private static final Color LINE_COLOR = Color.black; /** The duration of the animation, default value is {@link #DURATION}. */ private float duration; /** The value of the animation waiting time. */ private int sleep; /** The glass pane. */ private JPanel glass; /** Flag indicating if the animations is started or stopped. */ private boolean animating; /** * The direction of the animation either {@link #INCOMING} or * {@link #OUTGOING}. */ private int animationDir; /** The component displaying the animation. */ private AnimatedPane animatingPane; /** The time at which the animation started. */ private long animationStart; /** The timer controlling the animation. */ private Timer animationTimer; /** The content pane of the dialog to show. */ private JComponent sheet; /** One of the constants orientation. */ private int orientation; /** The partial line border, the value depends on the orientation. */ private OneLineBorder border; /** Flag indicating to close the application after a given time. */ private boolean closeAfter; /** * The timer used to hide the animation after a given time, * only used if the flag {@link #closeAfter} is <code>true</code>. */ private Timer timer; /** The extra space to remove. */ //private int bottomSpace; /** Where to show the sheet, default is a <code>(0, 0)</code>. */ private Point location; /** Initializes the components. */ private void initialize() { location = new Point(0, 0); duration = DURATION; sleep = SLEEP; animatingPane = new AnimatedPane(this); animatingPane.requestFocus(); glass = (JPanel) getGlassPane(); glass.setLayout(new GridBagLayout()); setOrientation(DOWN); } /** Starts the animation. */ private void startAnimation() { glass.remove(animatingPane); glass.remove(sheet); glass.validate(); glass.repaint(); animatingPane.setSource(sheet); GridBagConstraints c = new GridBagConstraints(); c.gridy = 0; int h, w; Dimension d; switch (orientation) { case DOWN: c.anchor = GridBagConstraints.NORTH; glass.add(animatingPane, c); c.gridy++; c.weighty = Integer.MAX_VALUE; glass.add(Box.createGlue(), c); break; case UP_MIDDLE: //c.anchor = GridBagConstraints.SOUTHWEST; h = glass.getHeight()-sheet.getHeight()-location.y; if (glass.getLayout() == null) { d = getSize(); w = (d.width-sheet.getPreferredSize().width)/2; animatingPane.setLocation(w, h); glass.add(animatingPane); } else { glass.add(Box.createVerticalStrut(h), c); c.weightx = 0.5; c.gridy++; glass.add(animatingPane, c); } break; case UP_RIGHT: c.anchor = GridBagConstraints.SOUTHEAST; h = glass.getHeight()-sheet.getHeight()-location.y; glass.add(Box.createVerticalStrut(h), c); c.weightx = 0.9; c.gridy++; glass.add(animatingPane, c); break; case UP_LEFT: h = glass.getHeight()-sheet.getHeight()-location.y; if (glass.getLayout() == null) { animatingPane.setLocation(0, h); glass.add(animatingPane); } else { c.anchor = GridBagConstraints.SOUTHWEST; glass.add(Box.createVerticalStrut(h), c); c.weightx = 0.1; c.gridy++; glass.add(animatingPane, c); } } glass.setVisible(true); animationStart = System.currentTimeMillis(); if (animationTimer == null) animationTimer = new Timer(sleep, this); animating = true; animationTimer.start(); } /** Stops the animation. */ private void stopAnimation() { animationTimer.stop(); animating = false; } /** Stops the display of the dialog. */ private void finish() { glass.remove(animatingPane); glass.remove(sheet); GridBagConstraints c = new GridBagConstraints(); c.gridy = 0; c.gridx = 0; int h, w; c.anchor = GridBagConstraints.SOUTHWEST; Dimension d; switch (orientation) { case DOWN: c.anchor = GridBagConstraints.NORTH; glass.add(sheet, c); c.gridy++; c.weighty = Integer.MAX_VALUE; glass.add(Box.createGlue(), c); break; case UP_MIDDLE: h = glass.getHeight()-sheet.getHeight()-location.y; if (glass.getLayout() == null) { d = getSize(); w = (d.width-sheet.getPreferredSize().width)/2; sheet.setLocation(w, h); glass.add(sheet); } else { glass.add(Box.createVerticalStrut(h), c); c.gridy++; glass.add(sheet, c); } break; case UP_RIGHT: h = glass.getHeight()-sheet.getHeight()-location.y; glass.add(Box.createVerticalStrut(h), c); c.gridy++; d = getSize(); w = d.width-sheet.getPreferredSize().width; glass.add(Box.createHorizontalStrut(w), c); c.gridx++; glass.add(sheet, c); break; case UP_LEFT: h = glass.getHeight()-sheet.getHeight()-location.y; if (glass.getLayout() == null) { sheet.setLocation(0, h); glass.add(sheet); } else { glass.add(Box.createVerticalStrut(h), c); c.gridy++; c.weightx = 0.1; //glass.add(Box.createHorizontalStrut(5), c); c.gridx++; glass.add(sheet, c); } } glass.revalidate(); glass.repaint(); if (closeAfter) { if (timer == null) { timer = new Timer(500, new ActionListener() { public void actionPerformed(ActionEvent e) { hideAnimation(); } }); //fire every half second timer.setInitialDelay(2000); //first delay 2 seconds timer.setRepeats(false); } timer.start(); } } /** * Creates a new instance. * * @param title The title of the frame. */ public AnimatedJFrame(String title) { super(title); initialize(); } /** * Indicates to close after a set number of seconds. * @param closeAfter The value to set. */ public void setCloseAfter(boolean closeAfter) { this.closeAfter = closeAfter; } /** * Returns the orientation selected. * * @return See above. */ public int getOrientation() { return orientation; } /** * Sets the duration of the animation. * * @param duration The value to set. */ public void setDuration(float duration) { if (duration <= 0) duration = DURATION; this.duration = duration; } /** * Sets the animation waiting time. * * @param sleep The value to set. */ public void setSleep(int sleep) { this.sleep = sleep; } /** * Sets the orientation and builds the border accordingly. * * @param orientation One of the orientation constants defined by this * class. */ public void setOrientation(int orientation) { switch (orientation) { case UP_MIDDLE: case UP_RIGHT: case UP_LEFT: this.orientation = orientation; border = new OneLineBorder(OneLineBorder.BOTTOM, LINE_COLOR); break; case DOWN: default: this.orientation = DOWN; border = new OneLineBorder(OneLineBorder.TOP, LINE_COLOR); break; } if (sheet != null) sheet.setBorder(border); animatingPane.setBorder(border); } /** * Shows the passed dialog as a sheet. * * @param dialog The dialog to show. * @param location The point where to show the sheet. * @return See above. */ public JComponent showJDialogAsSheet(JDialog dialog, Point location) { return showJDialogAsSheet(dialog, location, DOWN); } /** * Shows the passed dialog as a sheet. * * @param dialog The dialog to show. * @param location The point where to show the sheet. * @param orientation One of the orientation constants defined by this * class. * @return See above. */ public JComponent showJDialogAsSheet(JDialog dialog, Point location, int orientation) { if (dialog == null) return null; this.location = location; sheet = (JComponent) dialog.getContentPane(); if (glass.getLayout() == null) { animatingPane.setSize(dialog.getSize()); animatingPane.setPreferredSize(dialog.getPreferredSize()); sheet.setSize(dialog.getSize()); sheet.setPreferredSize(dialog.getPreferredSize()); glass.remove(animatingPane); glass.remove(sheet); } else { glass.removeAll(); } setOrientation(orientation); glass.validate(); glass.repaint(); animationDir = INCOMING; startAnimation(); return sheet; } /** Stops the animation and hides the components. * * @param visible Pass <code>true</code> to keep the glass pane visible, * <code>false</code> otherwise. */ public void hideAnimation(boolean visible) { animationDir = OUTGOING; //glass.removeAll(); glass.remove(animatingPane); glass.remove(sheet); glass.validate(); glass.repaint(); stopAnimation(); glass.setVisible(visible); if (timer != null && closeAfter) timer.stop(); } /** Stops the animation and hides the components. */ public void hideAnimation() { hideAnimation(false); } /** * Starts or ends the animation. * @see ActionListener#actionPerformed(ActionEvent) */ public void actionPerformed(ActionEvent e) { if (!animating) return; if (sheet == null) { if (timer != null) timer.stop(); return; } float percent = System.currentTimeMillis()-animationStart; percent = percent/DURATION; percent = Math.min(1.0f, percent); int h = 0; if (animationDir == INCOMING) h = (int) (percent*sheet.getHeight()); else h = (int) ((1.0f- percent)*sheet.getHeight()); animatingPane.setAnimatingHeight(h); animatingPane.repaint(); if (percent >= 1.0f) { stopAnimation(); if (animationDir == INCOMING) finish(); else { glass.removeAll(); glass.setVisible(false); } } } }