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.add(getDelayPanel(), java.awt.BorderLayout.CENTER);
077                mainPanel.add(getJPanelButtons(), java.awt.BorderLayout.SOUTH);
078            }
079            return mainPanel;
080        }
081    
082        /**
083         * This method initializes jPanel   
084         *  
085         * @return javax.swing.JPanel       
086         */
087        private JPanel getDelayPanel() {
088            if (delayPanel == null) {
089                labelDelay = new JLabel();
090                labelDelay.setText(SearsResourceBundle.getResource("delay_label"));
091                delayPanel = new JPanel();
092                delayPanel.setLayout(new GridBagLayout());
093                GridBagConstraints gbc1 = new GridBagConstraints();
094                gbc1.gridx = 0;
095                gbc1.gridy = 0;
096                delayPanel.add(labelDelay, gbc1);
097                GridBagConstraints gbc2 = new GridBagConstraints();
098                gbc2.gridx = 1;
099                gbc2.gridy = 0;
100                gbc2.fill = GridBagConstraints.HORIZONTAL;
101                gbc2.weightx = 1;
102                delayPanel.add(getTextDelay(), gbc2);
103                GridBagConstraints gbc3 = new GridBagConstraints();
104                gbc3.gridx = 0;
105                gbc3.gridy = 1;
106                gbc3.gridwidth = 2;
107                gbc3.fill = GridBagConstraints.HORIZONTAL;
108                gbc3.weightx = 1;
109                delayPanel.add(getJSliderDelay(), gbc3);
110            }
111            return delayPanel;
112        }
113    
114        /**
115         * Method getJSpinnerDelay.
116         * <br><b>Summary:</b><br>
117         * This method creates the JSpinner to control the delay
118         * @return  JSpinner.
119         */
120        private JSlider getJSliderDelay() {
121            if(jSliderDelay == null){
122                jSliderDelay = new JSlider(-100, 100);
123                jSliderDelay.setValue(10);
124                jSliderDelay.addChangeListener(new ChangeListener() {
125                    public void stateChanged(ChangeEvent e) {
126                        valueChanged(e.getSource());
127                    }
128                });
129            }
130            return jSliderDelay;
131        }
132    
133        /**
134         * Method valueChanged.
135         * <br><b>Summary:</b><br>
136         * This method is called when textField changed, or when JSpinner changed.
137         * @param source    The one which change the first.
138         */
139        protected void valueChanged(Object source) {
140            //If the slider triggered the change, update the textField (if necessary).
141            if (source.equals(jSliderDelay)) {
142                //by default we will not update the textField value.
143                boolean updateTextField = false;
144                //retrieve the slider delay value
145                double sliderDelayValue = ((double) jSliderDelay.getValue()) / 10;
146                updateTextField = true;
147                try {
148                    //  retrieve the TextField value.
149                    double delay = getDoubleTextDelayValue();
150                    if (delay != sliderDelayValue) {
151                        updateTextField = true;
152                    }
153                } catch (NumberFormatException e) {
154                    //TextField value is not valid : update !
155                    updateTextField = true;
156                }
157                //update textField if necessary
158                if (updateTextField) {
159                    getTextDelay().setText("" + sliderDelayValue);
160                }
161            } else if (source.equals(textDelay)) {
162                //If the textDelay triggered the event, update the slider if necessary.
163                //Source is the TextDelay
164                try {
165                    //  retrieve the TextField value.
166                    double delay = getDoubleTextDelayValue();
167                    double sliderDelayValue = ((double) jSliderDelay.getValue()) / 10;
168                    if (delay != sliderDelayValue) {
169                        // Udate slider.
170                        //Beware if textField value is bigger than slider max
171                        int newSliderValue =  (int) (delay * 10);
172                        if(Math.abs(newSliderValue) > jSliderDelay.getMaximum()){
173                            jSliderDelay.setMaximum(Math.abs(newSliderValue));
174                            jSliderDelay.setMinimum(-Math.abs(newSliderValue));
175                        }
176                        jSliderDelay.setValue(newSliderValue);
177                    }
178                } catch (NumberFormatException e) {
179                    //TextField value is not valid : do not update slider!
180                }
181            }
182        }
183    
184        
185        /**
186         * Method getDoubleTextDelayValue.
187         * <br><b>Summary:</b><br>
188         * This method returns the double value of the delay in the textfield.
189         * @return double   The double value of the delay in the textfield.
190         * @throws NumberFormatException
191         */
192        public double getDoubleTextDelayValue() throws NumberFormatException{
193            //the result of the method.
194            double result = 0;
195            String delayString = getTextDelay().getText();
196            if (delayString != null && !delayString.equals("")) {
197                    result = Double.parseDouble(delayString);
198            }else{
199                result = 0;
200            }
201            //return the result;
202            return result;
203        }
204        /**
205         * Method okAction.
206         * <br><b>Summary:</b><br>
207         * This method is called when user validate the dialog.
208         */
209        protected void okAction() {
210            //Just have to check parameters validity, if valids, dispose dialog,and set validation status to true.
211            String error = checkParameters();
212            if (error != null && !error.equals("")) {
213                //Show error message.
214                JOptionPane.showMessageDialog(this, error, SearsResourceBundle.getResource("error_delayConfigurationError"), JOptionPane.ERROR_MESSAGE);
215                Trace.trace("Error in Delay parameters:" + error, Trace.WARNING_PRIORITY);
216            } else {
217                //else split configuration is valid, release dialog.
218                validationStatus = true;
219                dispose();
220            }
221        }
222    
223        /**
224         * Method checkParameters.
225         * <br><b>Summary:</b><br>
226         * This method checks the parameters.
227         * @return  <b>String</b>      "" if there is no error, or the error message.
228         */
229        private String checkParameters() {
230            //Check file to open
231            String errorMessage = "";
232            //check delay.
233            String delay = getTextDelay().getText();
234            if (delay != null && !delay.equals("")) {
235                try {
236                    Double.parseDouble(delay);
237                } catch (NumberFormatException e) {
238                    //Delay value is not a number.
239                    errorMessage += SearsResourceBundle.getResource("error_delayNotValid")+"\n";
240                }
241            } else {
242                //Delay value is null.
243                errorMessage += SearsResourceBundle.getResource("error_delayNull")+"\n";
244            }
245            return errorMessage;
246        }
247    
248        /**
249         * This method initializes jTextField       
250         *  
251         * @return javax.swing.JTextField   
252         */
253        private JTextField getTextDelay() {
254            if (textDelay == null) {
255                textDelay = new JTextField(5);
256                textDelay.setToolTipText(SearsResourceBundle.getResource("delay_tip"));
257                textDelay.setText("1");
258                //add an action listener to validate when user press 'enter' in textField.
259                textDelay.addActionListener(new ActionListener() {
260                    public void actionPerformed(ActionEvent e) {
261                        okAction();
262                    }
263                });
264                //Add a focus listener, to update slider when textfield lost focus.
265                textDelay.addFocusListener(new FocusListener() {
266                    public void focusLost(FocusEvent e) {
267                        valueChanged(e.getSource());
268                    }
269                
270                    public void focusGained(FocusEvent e) {
271                        //Nothing to do on focus gain
272                    }
273                });
274            }
275            return textDelay;
276        }
277    
278    
279        /**
280         * Method getDelay.
281         * <br><b>Summary:</b><br>
282         * Return the entered delay.
283         * @return      <b>double</b>      The entered delay.
284         */
285        public double getDelay() {
286            return Double.parseDouble(getTextDelay().getText());
287        }
288    
289        /* (non-Javadoc)
290         * @see sears.gui.SearsJDialog#getDialogName()
291         */
292        protected String getDialogName() {
293            return "delay";
294        }
295    }