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    package sears.gui;
018    
019    import java.awt.BorderLayout;
020    import java.awt.GridBagConstraints;
021    import java.awt.GridBagLayout;
022    import java.awt.GridLayout;
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    /**
041     * Class JDialogNormalizeAction.
042     * This dialog permits to define the parameters of a normalizeDuration action.
043     * i.e the min duration and the max duration of the ST.
044     */
045    public class JDialogNormalizeAction extends SearsJDialog {
046    
047            /** (<b>long</b>) serialVersionUID: The serialVersionUID */
048            private static final long serialVersionUID = -6105540923502362579L;
049            private JPanel jContentPane;  
050            private JPanel jPanelCenter;
051            
052            protected static final int MIN = 0;
053            
054            protected static final int MAX = 1;
055            
056            private static final int NB_TIMES=2;
057            
058            private static final String[] MIN_MAX_SUFFIXES = new String[]{"min", "max"};
059            private static final String[] DEFAULT_MIN_MAX =  new String[]{"0.5", "5"};
060            
061            private JPanel[] jPanelTime = null;
062            private JLabel[] jLabelTime = null;
063            private JTextField[] jTextFieldTime = null;
064            private JSlider[] jSliderTime = null;
065            
066            /**
067         * This is the default constructor
068         */
069        public JDialogNormalizeAction() {
070            super(SearsResourceBundle.getResource("normalizeDuration_title"));
071            jPanelTime = new JPanel[NB_TIMES];
072            jTextFieldTime = new JTextField[NB_TIMES];
073            jSliderTime = new JSlider[NB_TIMES];
074            jLabelTime = new JLabel[NB_TIMES];
075            setContentPane(getJContentPane());
076            configureSize();
077        }
078            
079        /**
080         * Method getJContentPane.
081         * <br><b>Summary:</b><br>
082         * return the contentPane
083         * @return  (<b>JPanel</b>)   A JPanel.
084         */
085        private JPanel getJContentPane() {
086            if (jContentPane == null) {
087                jContentPane = new JPanel();
088                jContentPane.setLayout(new BorderLayout());
089                jContentPane.add(getJPanelCenter(), java.awt.BorderLayout.CENTER);
090                jContentPane.add(getJPanelButtons(), java.awt.BorderLayout.SOUTH);
091            }
092            return jContentPane;
093        }
094        
095        /**
096         * This method initializes jPanel   
097         *  
098         * @return javax.swing.JPanel       
099         */
100        private JPanel getJPanelCenter() {
101            if (jPanelCenter == null) {
102                jPanelCenter = new JPanel();
103                jPanelCenter.setLayout(new GridLayout(NB_TIMES,1));
104                jPanelCenter.add(getJPanelTime(MIN));
105                jPanelCenter.add(getJPanelTime(MAX));
106            }
107            return jPanelCenter;
108        }
109    
110        /**
111         * Method getTimePanel.
112         * <br><b>Summary:</b><br>
113         * Return a penl to define a time, that use a slider, and a textField.
114         * @param minMax    MIN or MAX.
115         * @return  (<b>JPanel</b>)   A JPanel.
116         */
117        private JPanel getJPanelTime(int minMax) {
118            if (jPanelTime[minMax] == null) {
119                jLabelTime[minMax] = new JLabel();
120                jLabelTime[minMax].setText(SearsResourceBundle.getResource("normalizeDuration_"+MIN_MAX_SUFFIXES[minMax]+"_label"));
121                jPanelTime[minMax] = new JPanel();
122                jPanelTime[minMax].setLayout(new GridBagLayout());
123                GridBagConstraints gbc1 = new GridBagConstraints();
124                gbc1.gridx = 0;
125                gbc1.gridy = 0;
126                jPanelTime[minMax].add(jLabelTime[minMax], gbc1);
127                GridBagConstraints gbc2 = new GridBagConstraints();
128                gbc2.gridx = 1;
129                gbc2.gridy = 0;
130                gbc2.fill = GridBagConstraints.HORIZONTAL;
131                gbc2.weightx = 1;
132                jPanelTime[minMax].add(getJTextFieldTime(minMax), gbc2);
133                GridBagConstraints gbc3 = new GridBagConstraints();
134                gbc3.gridx = 0;
135                gbc3.gridy = 1;
136                gbc3.gridwidth = 2;
137                gbc3.fill = GridBagConstraints.HORIZONTAL;
138                gbc3.weightx = 1;
139                jPanelTime[minMax].add(getJSliderTime(minMax), gbc3);
140            }
141            return jPanelTime[minMax];
142        }
143        
144            
145            /**
146             * Method getJSliderTime.
147             * <br><b>Summary:</b><br>
148             * return the slider that correspond to the given min or max.
149             * @param minMax        MIN or MAX.
150             * @return  (<b>JSlider</b>)   A JSlider.
151             */
152            private JSlider getJSliderTime(int minMax) {
153                    if(jSliderTime[minMax] == null){
154                            jSliderTime[minMax] = new JSlider(0, 100);
155                            jSliderTime[minMax].setValue((int) Double.parseDouble(DEFAULT_MIN_MAX[minMax])*10);
156                            final int minMaxFinal = minMax;
157                            jSliderTime[minMax].addChangeListener(new ChangeListener() {
158                    public void stateChanged(ChangeEvent e) {
159                        valueChanged(e.getSource(), minMaxFinal);
160                    }
161                });
162            }
163            return jSliderTime[minMax];
164            }
165    
166            /**
167             * Method valueChanged.
168             * <br><b>Summary:</b><br>
169             * this method is called when a slider changed or value.
170             * @param source                The slider that generates the event.
171             * @param minMax                To know if it is min or max that changed.
172             */
173            private void valueChanged(Object source, int minMax) {
174            //If the slider triggered the change, update the textField (if necessary).
175            if (source instanceof JSlider) {
176                //by default we will not update the textField value.
177                boolean updateTextField = false;
178                //retrieve the slider delay value
179                double sliderDelayValue = ((double) jSliderTime[minMax].getValue()) / 10;
180                updateTextField = true;
181                try {
182                    //  retrieve the TextField value.
183                    double delay = getDoubleTextDelayValue(minMax);
184                    if (delay != sliderDelayValue) {
185                        updateTextField = true;
186                    }
187                } catch (NumberFormatException e) {
188                    //TextField value is not valid : update !
189                    updateTextField = true;
190                }
191                //update textField if necessary
192                if (updateTextField) {
193                    jTextFieldTime[minMax].setText("" + sliderDelayValue);
194                }
195            } else if (source instanceof JTextField) {
196                //If the textDelay triggered the event, update the slider if necessary.
197                //Source is the TextDelay
198                try {
199                    //  retrieve the TextField value.
200                    double delay = getDoubleTextDelayValue(minMax);
201                    double sliderDelayValue = ((double) jSliderTime[minMax].getValue()) / 10;
202                    if (delay != sliderDelayValue) {
203                        // Udate slider.
204                        //Beware if textField value is bigger than slider max
205                        int newSliderValue =  (int) (delay * 10);
206                        if(Math.abs(newSliderValue) > jSliderTime[minMax].getMaximum()){
207                            jSliderTime[minMax].setMaximum(Math.abs(newSliderValue));
208                        }
209                        jSliderTime[minMax].setValue(newSliderValue);
210                    }
211                } catch (NumberFormatException e) {
212                    //TextField value is not valid : do not update slider!
213                }
214            }
215                    
216            }
217            
218        /**
219         * Method getDoubleTextDelayValue.
220         * <br><b>Summary:</b><br>
221         * This method returns the double value of the delay in the textfield for given minMax
222         * @param minMax    To select the MIN or the MAX
223         * @return double   The double value of the delay in the textfield.
224         * @throws NumberFormatException
225         */
226        public double getDoubleTextDelayValue(int minMax) throws NumberFormatException{
227            //the result of the method.
228            double result = 0;
229            String delayString = jTextFieldTime[minMax].getText();
230            if (delayString != null && !delayString.equals("")) {
231                    result = Double.parseDouble(delayString);
232            }else{
233                result = 0;
234            }
235            //return the result;
236            return result;
237        }
238            
239            
240            /**
241             * Method getJTextFieldTime.
242             * <br><b>Summary:</b><br>
243             * return the textField that correspond to the given min or max.
244             * @param minMax        MIN or MAX
245             * @return  (<b>JTextField</b>)   A JTextField.
246             */
247            private JTextField getJTextFieldTime(int minMax) {
248                    if (jTextFieldTime[minMax] == null) {
249                            jTextFieldTime[minMax] = new JTextField(5);
250                            jTextFieldTime[minMax].setToolTipText(SearsResourceBundle.getResource("delay_tip"));
251                            jTextFieldTime[minMax].setText(DEFAULT_MIN_MAX[minMax]);
252                //add an action listener to validate when user press 'enter' in textField.
253                            jTextFieldTime[minMax].addActionListener(new ActionListener() {
254                    public void actionPerformed(ActionEvent e) {
255                        okAction();
256                    }
257                });
258                //Add a focus listener, to update slider when textfield lost focus.
259                            final int minMaxFinal = minMax;
260                            jTextFieldTime[minMax].addFocusListener(new FocusListener() {
261                    public void focusLost(FocusEvent e) {
262                        valueChanged(e.getSource(), minMaxFinal);
263                    }
264                
265                    public void focusGained(FocusEvent e) {
266                        //Nothing to do on focus gain
267                    }
268                });
269            }
270            return jTextFieldTime[minMax];
271            }
272            
273             /**
274         * Method okAction.
275         * <br><b>Summary:</b><br>
276         * This method is called when user validate the dialog.
277         */
278        protected void okAction() {
279            //Just have to check parameters validity, if valids, dispose dialog,and set validation status to true.
280            String error = checkParameters();
281            if (error != null && !error.equals("")) {
282                //Show error message.
283                JOptionPane.showMessageDialog(this, error, SearsResourceBundle.getResource("error_delayConfigurationError"), JOptionPane.ERROR_MESSAGE);
284                Trace.trace("Error in Delay parameters:" + error, Trace.WARNING_PRIORITY);
285            } else {
286                //else split configuration is valid, release dialog.
287                validationStatus = true;
288                dispose();
289            }
290        }
291        
292        /**
293         * Method checkParameters.
294         * <br><b>Summary:</b><br>
295         * This method checks the parameters.
296         * @return  <b>String</b>      "" if there is no error, or the error message.
297         */
298        private String checkParameters() {
299            //Check file to open
300            String errorMessage = "";
301            //check time for min and max.
302            for(int i= 0; i < NB_TIMES;i++ ){
303                    String delay = jTextFieldTime[i].getText();
304                    if (delay != null && !delay.equals("")) {
305                        try {
306                            Double.parseDouble(delay);
307                        } catch (NumberFormatException e) {
308                            //Delay value is not a number.
309                            errorMessage += "["+MIN_MAX_SUFFIXES[i]+"]"+SearsResourceBundle.getResource("error_delayNotValid")+"\n";
310                        }
311                    } else {
312                        //Delay value is null.
313                        errorMessage += "["+MIN_MAX_SUFFIXES[i]+"]"+SearsResourceBundle.getResource("error_delayNull")+"\n";
314                    }
315            }
316            return errorMessage;
317        }
318    
319        /**
320         * Method getTimes.
321         * <br><b>Summary:</b><br>
322         * return the times configured by the user.
323         * chack that user validates the dialog.
324         * @return  (<b>double[]</b>)   The result of the normalize dialog, double[]=[MIN, MAX].
325         */
326        public double[] getTimes(){
327            //The result of the method.
328            double[] result = new double[NB_TIMES];
329            for(int i= 0; i<NB_TIMES;i++){
330                    result[i] = Double.parseDouble(jTextFieldTime[i].getText());
331            }
332            //return the result.
333            return result;
334        }
335        
336            /* (non-Javadoc)
337             * @see sears.gui.SearsJDialog#getDialogName()
338             */
339            protected String getDialogName() {
340                    return "normalizeDuration";
341            }
342    
343    }