001    /////////////////////////////////////////////////
002    // This file is part of Sears project.
003    // Subtitle Editor And Re-Synch
004    // A tool to easily modify and resynch movies subtitles.
005    /////////////////////////////////////////////////
006    //This program is free software; 
007    //you can redistribute it and/or modify it under the terms 
008    //of the GNU General Public License 
009    //as published by the Free Software Foundation; 
010    //either version 2 of the License, or (at your option) any later version.
011    /////////////////////////////////////////////////
012    //Sears project is available under sourceforge
013    // at adress: http://sourceforge.net/projects/sears/
014    //Copyright (C) 2005 Booba Skaya
015    //Mail: booba.skaya@gmail.com
016    ////////////////////////////////////////////////
017    
018    package sears.gui;
019    
020    import java.awt.BorderLayout;
021    import java.awt.GridBagConstraints;
022    import java.awt.GridBagLayout;
023    import java.awt.event.ActionEvent;
024    import java.awt.event.ActionListener;
025    import java.awt.event.FocusEvent;
026    import java.awt.event.FocusListener;
027    
028    import javax.swing.JLabel;
029    import javax.swing.JOptionPane;
030    import javax.swing.JPanel;
031    import javax.swing.JSlider;
032    import javax.swing.JTextField;
033    import javax.swing.event.ChangeEvent;
034    import javax.swing.event.ChangeListener;
035    
036    import sears.tools.SearsResourceBundle;
037    import sears.tools.Trace;
038    
039    /**
040     * Class DelayDialog.
041     * <br><b>Summary:</b><br>
042     * This class is a Dialog which permits to delay some subtitles.
043     */
044    public class DelayDialog extends SearsJDialog {
045    
046        private static final long serialVersionUID = -365612092452966123L;
047    
048        private JPanel mainPanel = null;
049    
050        private JPanel delayPanel = null;
051    
052        private JLabel labelDelay = null;
053    
054        private JTextField textDelay = null;
055    
056        private JSlider jSliderDelay;
057    
058        /**
059         * This is the default constructor
060         */
061        public DelayDialog() {
062            super(SearsResourceBundle.getResource("delay_title"));
063            this.setContentPane(getMainPanel());
064            configureSize();
065        }
066         
067        /**
068         * This method initializes jContentPane
069         * 
070         * @return javax.swing.JPanel
071         */
072        private JPanel getMainPanel() {
073            if (mainPanel == null) {
074                mainPanel = new JPanel();
075                mainPanel.setLayout(new BorderLayout());
076                mainPanel.setBorder(super.createEmptyBorder());
077                mainPanel.add(getDelayPanel(), java.awt.BorderLayout.CENTER);
078                mainPanel.add(getJPanelButtons(), java.awt.BorderLayout.SOUTH);
079            }
080            return mainPanel;
081        }
082    
083        /**
084         * This method initializes jPanel   
085         *  
086         * @return javax.swing.JPanel       
087         */
088        private JPanel getDelayPanel() {
089            if (delayPanel == null) {
090                labelDelay = new JLabel();
091                labelDelay.setText(SearsResourceBundle.getResource("delay_label"));
092                delayPanel = new JPanel();
093                delayPanel.setLayout(new GridBagLayout());
094                GridBagConstraints gbc1 = new GridBagConstraints();
095                gbc1.gridx = 0;
096                gbc1.gridy = 0;
097                gbc1.ipadx = 4;
098                delayPanel.add(labelDelay, gbc1);
099                GridBagConstraints gbc2 = new GridBagConstraints();
100                gbc2.gridx = 1;
101                gbc2.gridy = 0;
102                gbc2.fill = GridBagConstraints.HORIZONTAL;
103                gbc2.weightx = 1;
104                delayPanel.add(getTextDelay(), gbc2);
105                GridBagConstraints gbc3 = new GridBagConstraints();
106                gbc3.gridx = 0;
107                gbc3.gridy = 1;
108                gbc3.gridwidth = 2;
109                gbc3.fill = GridBagConstraints.HORIZONTAL;
110                gbc3.weightx = 1;
111                delayPanel.add(getJSliderDelay(), gbc3);
112            }
113            return delayPanel;
114        }
115    
116        /**
117         * Method getJSpinnerDelay.
118         * <br><b>Summary:</b><br>
119         * This method creates the JSpinner to control the delay
120         * @return  JSpinner.
121         */
122        private JSlider getJSliderDelay() {
123            if(jSliderDelay == null){
124                jSliderDelay = new JSlider(-100, 100);
125                jSliderDelay.setValue(10);
126                jSliderDelay.addChangeListener(new ChangeListener() {
127                    public void stateChanged(ChangeEvent e) {
128                        valueChanged(e.getSource());
129                    }
130                });
131            }
132            return jSliderDelay;
133        }
134    
135        /**
136         * Method valueChanged.
137         * <br><b>Summary:</b><br>
138         * This method is called when textField changed, or when JSpinner changed.
139         * @param source    The one which change the first.
140         */
141        protected void valueChanged(Object source) {
142            //If the slider triggered the change, update the textField (if necessary).
143            if (source.equals(jSliderDelay)) {
144                //by default we will not update the textField value.
145                boolean updateTextField = false;
146                //retrieve the slider delay value
147                double sliderDelayValue = ((double) jSliderDelay.getValue()) / 10;
148                updateTextField = true;
149                try {
150                    //  retrieve the TextField value.
151                    double delay = getDoubleTextDelayValue();
152                    if (delay != sliderDelayValue) {
153                        updateTextField = true;
154                    }
155                } catch (NumberFormatException e) {
156                    //TextField value is not valid : update !
157                    updateTextField = true;
158                }
159                //update textField if necessary
160                if (updateTextField) {
161                    getTextDelay().setText("" + sliderDelayValue);
162                }
163            } else if (source.equals(textDelay)) {
164                //If the textDelay triggered the event, update the slider if necessary.
165                //Source is the TextDelay
166                try {
167                    //  retrieve the TextField value.
168                    double delay = getDoubleTextDelayValue();
169                    double sliderDelayValue = ((double) jSliderDelay.getValue()) / 10;
170                    if (delay != sliderDelayValue) {
171                        // Udate slider.
172                        //Beware if textField value is bigger than slider max
173                        int newSliderValue =  (int) (delay * 10);
174                        if(Math.abs(newSliderValue) > jSliderDelay.getMaximum()){
175                            jSliderDelay.setMaximum(Math.abs(newSliderValue));
176                            jSliderDelay.setMinimum(-Math.abs(newSliderValue));
177                        }
178                        jSliderDelay.setValue(newSliderValue);
179                    }
180                } catch (NumberFormatException e) {
181                    //TextField value is not valid : do not update slider!
182                }
183            }
184        }
185    
186        
187        /**
188         * Method getDoubleTextDelayValue.
189         * <br><b>Summary:</b><br>
190         * This method returns the double value of the delay in the textfield.
191         * @return double   The double value of the delay in the textfield.
192         * @throws NumberFormatException
193         */
194        public double getDoubleTextDelayValue() throws NumberFormatException{
195            //the result of the method.
196            double result = 0;
197            String delayString = getTextDelay().getText();
198            if (delayString != null && !delayString.equals("")) {
199                    result = Double.parseDouble(delayString);
200            }else{
201                result = 0;
202            }
203            //return the result;
204            return result;
205        }
206        /**
207         * Method okAction.
208         * <br><b>Summary:</b><br>
209         * This method is called when user validate the dialog.
210         */
211        protected void okAction() {
212            //Just have to check parameters validity, if valids, dispose dialog,and set validation status to true.
213            String error = checkParameters();
214            if (error != null && !error.equals("")) {
215                //Show error message.
216                JOptionPane.showMessageDialog(this, error, SearsResourceBundle.getResource("error_delayConfigurationError"), JOptionPane.ERROR_MESSAGE);
217                Trace.trace("Error in Delay parameters:" + error, Trace.WARNING_PRIORITY);
218            } else {
219                //else split configuration is valid, release dialog.
220                validationStatus = true;
221                dispose();
222            }
223        }
224    
225        /**
226         * Method checkParameters.
227         * <br><b>Summary:</b><br>
228         * This method checks the parameters.
229         * @return  <b>String</b>      "" if there is no error, or the error message.
230         */
231        private String checkParameters() {
232            //Check file to open
233            String errorMessage = "";
234            //check delay.
235            String delay = getTextDelay().getText();
236            if (delay != null && !delay.equals("")) {
237                try {
238                    Double.parseDouble(delay);
239                } catch (NumberFormatException e) {
240                    //Delay value is not a number.
241                    errorMessage += SearsResourceBundle.getResource("error_delayNotValid")+"\n";
242                }
243            } else {
244                //Delay value is null.
245                errorMessage += SearsResourceBundle.getResource("error_delayNull")+"\n";
246            }
247            return errorMessage;
248        }
249    
250        /**
251         * This method initializes jTextField       
252         *  
253         * @return javax.swing.JTextField   
254         */
255        private JTextField getTextDelay() {
256            if (textDelay == null) {
257                textDelay = new JTextField(5);
258                textDelay.setToolTipText(SearsResourceBundle.getResource("delay_tip"));
259                textDelay.setText("1");
260                //add an action listener to validate when user press 'enter' in textField.
261                textDelay.addActionListener(new ActionListener() {
262                    public void actionPerformed(ActionEvent e) {
263                        okAction();
264                    }
265                });
266                //Add a focus listener, to update slider when textfield lost focus.
267                textDelay.addFocusListener(new FocusListener() {
268                    public void focusLost(FocusEvent e) {
269                        valueChanged(e.getSource());
270                    }
271                
272                    public void focusGained(FocusEvent e) {
273                        //Nothing to do on focus gain
274                    }
275                });
276            }
277            return textDelay;
278        }
279    
280    
281        /**
282         * Method getDelay.
283         * <br><b>Summary:</b><br>
284         * Return the entered delay.
285         * @return      <b>double</b>      The entered delay.
286         */
287        public double getDelay() {
288            return Double.parseDouble(getTextDelay().getText());
289        }
290    
291        /* (non-Javadoc)
292         * @see sears.gui.SearsJDialog#getDialogName()
293         */
294        protected String getDialogName() {
295            return "delay";
296        }
297    }