package org.greenstone.gatherer.feedback; import java.awt.image.*; import javax.swing.*; import java.awt.event.*; import java.awt.*; import javax.swing.event.*; import java.io.*; import java.util.ResourceBundle; import java.text.MessageFormat; import javax.swing.text.NumberFormatter; import java.text.NumberFormat; import java.beans.*; import java.util.ArrayList; /** * This is the class to generate a animation type from a list of ImageIcon. * It will display a JDialog window and then user can specify the frames * per second rate that the user want to use to view the list of the ImageIcon. * @author Veronica Liesaputra */ public class Movie extends JDialog implements ActionListener,ChangeListener,PropertyChangeListener { /** * This variable will hold the resource of the words that is stored in Messages.properties file. * The calling using messages.getString(someString) will caused someString to be translated * into some other string that is hold in that file.usually it will caused it to be translated * to the language that the user use or choose to have as stated in Locale. */ private static ResourceBundle messages; /** * This is the label that we use to display the ImageIcon. */ private JLabel picture; /** * This is a textField where user can set how many frames per second they want to view the * ImageIcon.If user enter value that is bigger than the FPS_MAX then it will beep and user * will need to enter new valid value or it will stay as the previous valid value. * If user enter 0 then it will stop the animation. */ private JFormattedTextField textField; /** * This is a slider where user can set how many frames per second they want to view the * ImageIcon.If user slide to 0 then animation stop. */ private JSlider framesPerSecond; /** * This is the minimum frame per second value. */ private int FPS_MIN = 0; /** * This is the maximum frame per second value. The value is the twice the amount of * ImageIcon in the list. */ private int FPS_MAX; /** * This is the initial frame per second value to view the ImageIcon. */ private int FPS_INIT = 1; /** * This is the ImageIcon index that are currently showing in the label. */ private int frameNumber; /** * This is the total number of ImageIcon in the list. */ private int NUM_FRAMES; /** * This hold the list of the ImageIcon that are to be displayed. */ private ArrayList images; /** * This is telling how long is the delay for each frame to be refreshed. */ private int delay; /** * This is the timer that generate the animation of the list of ImageIcon. * The animation will be paused twice per cycle by restarting the timer. * If the the prame per second chosen by the user is 0 then the timer * will be stop. */ private Timer timer; /** * This the flag to say when the animation should stop. * If frozen = true then the animation should stop otherwise the animation * should keep running. */ private boolean frozen = false; /** * This will sho a modal-dialog and set up the value for the animation to run properly * according to the list of ImageIcon passed in. * @param msg hold the resource of the words that is stored in Messages.properties file. * @param img hold the list of ImageIcon to be displayed. */ public Movie (ResourceBundle msg,ArrayList img) { super(); images = img; NUM_FRAMES = img.size(); FPS_MAX = img.size() * 2; messages = msg; setTitle(messages.getString("GenerateMovie")); setModal(true); setBackground(new Color (176,208,176)); } /** * This method will seeting up the content pane of the dialog window. * It also setting up the timer and the delay. * @return the content pane of the window. */ public JPanel create_UI() { JPanel cont; cont = new JPanel(); cont.setOpaque(true); cont.setBackground(new Color (176,208,176)); JButton cls; cls = new JButton(messages.getString("Close")); cls.addActionListener(new ActionListener () { public void actionPerformed (ActionEvent e) { dispose(); if (timer != null) timer.stop(); } }); cls.setDefaultCapable(true); cls.setActionCommand(messages.getString("Close")); cls.setBackground(new Color(176,208,176)); if (images.size() <= 0) { JLabel empty_lbl; empty_lbl = new JLabel ("No Image to be displayed "); cont.add(empty_lbl); cont.add(cls); return cont; } cont.setLayout(new BoxLayout(cont, BoxLayout.PAGE_AXIS)); delay = 1000 / FPS_INIT; JLabel sliderLabel; sliderLabel = new JLabel(messages.getString("FramesPerSecond") + ": ", JLabel.CENTER); sliderLabel.setBackground(new Color(176,208,176)); sliderLabel.setAlignmentX(Component.CENTER_ALIGNMENT); NumberFormat numberFormat; numberFormat = NumberFormat.getIntegerInstance(); NumberFormatter formatter; formatter = new NumberFormatter(numberFormat); formatter.setMinimum(new Integer(FPS_MIN)); formatter.setMaximum(new Integer(FPS_MAX)); textField = new JFormattedTextField(formatter); textField.setBackground(new Color(224,240,224)); textField.setValue(new Integer(FPS_INIT)); textField.setColumns(5); textField.addPropertyChangeListener(this); textField.getInputMap().put(KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0), "check"); textField.getActionMap().put("check", new AbstractAction() { public void actionPerformed(ActionEvent e) { if (!textField.isEditValid()) { Toolkit.getDefaultToolkit().beep(); textField.selectAll(); } else { try { textField.commitEdit(); } catch (java.text.ParseException exc) { } } } }); framesPerSecond = new JSlider(JSlider.HORIZONTAL, FPS_MIN, FPS_MAX, FPS_INIT); framesPerSecond.addChangeListener(this); framesPerSecond.setBackground(new Color(176,208,176)); framesPerSecond.setMajorTickSpacing(10); framesPerSecond.setMinorTickSpacing(1); framesPerSecond.setPaintTicks(true); framesPerSecond.setPaintLabels(true); framesPerSecond.setBorder(BorderFactory.createEmptyBorder(0,0,10,0)); picture = new JLabel(); Dimension dim; int iw,ih; dim = Toolkit.getDefaultToolkit().getScreenSize(); iw = (int) (dim.width - 30); ih = (int) (dim.height * 0.75); picture.setPreferredSize(new Dimension(iw,ih)); picture.setHorizontalAlignment(JLabel.CENTER); picture.setAlignmentX(Component.CENTER_ALIGNMENT); picture.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLoweredBevelBorder(), BorderFactory.createEmptyBorder(10,10,10,10))); picture.setBackground(new Color(176,208,176)); updatePicture(0); JPanel labelAndTextField; labelAndTextField = new JPanel(); labelAndTextField.add(sliderLabel); labelAndTextField.add(textField); labelAndTextField.add(cls); labelAndTextField.setBackground(new Color(176,208,176)); cont.add(picture); cont.add(framesPerSecond); cont.add(labelAndTextField); cont.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); timer = new Timer(delay, this); timer.setInitialDelay(delay * 7); timer.setCoalesce(true); timer.start(); return cont; } /** * This method will tell what should happen when the slider's arrow * change its position. *
If user adjusting the frame per second value using the slider * then it will set the Textfield to have the value that slider point * to at the moment.If the value is 0 then it will stop the animation * otherwise it will keep animate with the new frame per second value. * @param e is the slider when the slider's arrow change its position. */ public void stateChanged(ChangeEvent e) { JSlider source; source = (JSlider)e.getSource(); int fps; fps = (int)source.getValue(); if (!source.getValueIsAdjusting()) { textField.setValue(new Integer(fps)); if (fps == 0) { if (!frozen) stopAnimation(); } else { delay = 1000 / fps; timer.setDelay(delay); timer.setInitialDelay(delay * 10); if (frozen) startAnimation(); } } else { textField.setText(String.valueOf(fps)); } } /** * This method will set the slider value when the user adjusting * the frame per second value using the textfield. *
If user adjusting the frame per second value using text field, the * slider's arrow position will be changed into that value. * @param e the text field */ public void propertyChange(PropertyChangeEvent e) { if ("value".equals(e.getPropertyName())) { Number value; value = (Number)e.getNewValue(); if (framesPerSecond != null && value != null) { framesPerSecond.setValue(value.intValue()); } } } /** * This method will start the timer. */ public void startAnimation() { timer.start(); frozen = false; } /** * This method will stop the timer. */ public void stopAnimation() { timer.stop(); frozen = true; } /** * This method will tell what should happen when the timer is start. * When the timer start it will increase the framenumber and will * update the label with the new image icon. * If the timer already display all the image icon in the list, it * will restart the timer and reanimate the image icon again. * @param e fires when the timer start. */ public void actionPerformed(ActionEvent e) { if (frameNumber == (NUM_FRAMES - 1)) frameNumber = 0; else frameNumber++; updatePicture(frameNumber); if ((frameNumber == (NUM_FRAMES - 1)) || (frameNumber==(NUM_FRAMES/2 - 1))) timer.restart(); } /** * This will update the label with the new ImageIcon. * If the ImageIcon is null then the label will display an error message * instead of the picture. * @param frameNum this is the index of the ImageIcon to be displayed. */ protected void updatePicture(int frameNum) { if (images.get(frameNumber) != null) { picture.setIcon((ImageIcon) images.get(frameNumber)); } else { picture.setText(messages.getString("image")+" #" + frameNumber + " " + messages.getString("notfound")); } } }