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 availbale 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.GridLayout;
024    import java.awt.event.ActionEvent;
025    import java.awt.event.ActionListener;
026    import java.util.ArrayList;
027    
028    import javax.swing.BorderFactory;
029    import javax.swing.JButton;
030    import javax.swing.JLabel;
031    import javax.swing.JPanel;
032    import javax.swing.JSlider;
033    import javax.swing.JTextField;
034    import javax.swing.event.ChangeEvent;
035    import javax.swing.event.ChangeListener;
036    
037    import sears.file.Subtitle;
038    import sears.file.SubtitleFile;
039    import sears.tools.SearsResourceBundle;
040    
041    /**
042     * Class ResynchroDialog.
043     * <br><b>Summary:</b><br>
044     * The GUI to do a resynchro
045     */
046    public class ResynchroDialog extends SearsJDialog {
047        private static final long serialVersionUID = 7702754672054592460L;
048    
049        private JPanel jContentPane = null;
050    
051        private JPanel mainPanel = null;
052    
053        private JLabel[] jLabelSource = null;
054    
055        private JTextField[] jTextSource = null;
056    
057        private JLabel[] jLabelDestination = null;
058    
059        private JTextField[] jTextDestination = null;
060        
061        private JSlider[] jSliders = null;
062        
063        private JLabel[] jLabelSubtitles = null;
064    
065        /**The sources, if precised at Dialog construction*/
066        private int[] sources;
067        
068        /**The subtitleList, that contains all the subtitles.*/
069        private ArrayList<Subtitle> subtitleList;
070    
071        /**
072         * Constructor ResynchroDialog.
073         * <br><b>Summary:</b><br>
074         * The constructor of the class ResynchroDialog
075         * Construct a new Resynchro dialog, using the given sources.
076         * @param subtitleList              The subtitles.
077         * @param sources                   The index of the selected subtitles for the resynchro.
078         */
079        public ResynchroDialog(ArrayList<Subtitle> subtitleList, int[] sources) {
080            super(SearsResourceBundle.getResource("resynch_title"));
081            this.sources = sources;
082            this.subtitleList = subtitleList;
083            //construct the source/Destination arrays using sources size.
084            jLabelSource = new JLabel[sources.length];
085            jLabelDestination = new JLabel[sources.length];
086            jTextSource = new JTextField[sources.length];
087            jTextDestination = new JTextField[sources.length];
088            jSliders = new JSlider[sources.length];
089            jLabelSubtitles = new JLabel[sources.length];
090            initialize();
091            configureSize();
092        }
093    
094        /**
095         * Constructor ResynchroDialog.
096         * <br><b>Summary:</b><br>
097         * The constructor of the class ResynchroDialog
098         * @param subtitleList      The subtitles.
099         */
100        public ResynchroDialog(ArrayList<Subtitle> subtitleList) {
101            this(subtitleList, new int[]{0, 0});
102        }
103    
104        /**
105         * This method initializes this
106         */
107        protected void initialize() {
108            this.setContentPane(getJContentPane());
109            setLocationRelativeTo(getParent());   
110            validationStatus=false;
111        }
112    
113        /**
114         * This method initializes jContentPane
115         * 
116         * @return javax.swing.JPanel
117         */
118        private JPanel getJContentPane() {
119            if (jContentPane == null) {
120                jContentPane = new JPanel();
121                jContentPane.setLayout(new BorderLayout());
122                jContentPane.add(getMainPanel(), java.awt.BorderLayout.CENTER);
123                jContentPane.add(getJPanelButtons(), java.awt.BorderLayout.SOUTH);
124            }
125            return jContentPane;
126        }
127    
128        /**
129         * This method initializes jPanel   
130         *  
131         * @return javax.swing.JPanel       
132         */
133        private JPanel getMainPanel() {
134            if (mainPanel == null) {
135                mainPanel = new JPanel();
136                mainPanel.setLayout(new GridLayout(sources.length, 1));
137                for(int i = 0; i < sources.length; i++){
138                    mainPanel.add(getJPanelSubtitle(i));
139                }
140            }
141            return mainPanel;
142        }
143    
144        /**
145         * Method getJPanelSubtitle.
146         * <br><b>Summary:</b><br>
147         * This method returns the JPanel that is used to define the subtitle of the given index.
148         * @param index                                     The index of the resynchro subtitle.
149         * @return  (<b>JPanel</b>)   the JPanel that is used to define the subtitle of the given index.
150         */
151        private JPanel getJPanelSubtitle(int index) {
152            //The result of the method.
153            JPanel result = new JPanel();
154            result.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "["+index+"]"));
155            result.setLayout(new GridBagLayout());
156            final int myIndex = index;
157            //Now construct the panel content.
158            jTextSource[index] = new JTextField("00:00:00,000");
159            jLabelSource[index] = new JLabel(SearsResourceBundle.getResource("resynch_source")+" "+index+":");
160            jTextDestination[index] = new JTextField("00:00:00,000");
161            //change the destination value if subttitle is anchored.
162            Subtitle subtitle = subtitleList.get(sources[index]);
163            if(subtitle.isAnchored()){
164                    jTextDestination[index].setText(SubtitleFile.timeToString(subtitle.getAnchor()));
165            }
166            jLabelDestination[index] = new JLabel(SearsResourceBundle.getResource("resynch_destination")+" "+index+":");
167            //Construct the JSlider, current value is the selected source index.
168            jLabelSubtitles[index] = new JLabel(((Subtitle) subtitleList.get(sources[index])).getSubtitle());
169            jSliders[index] = new JSlider(0, subtitleList.size()-1);
170            jSliders[index].addChangeListener(new ChangeListener() {
171                            public void stateChanged(ChangeEvent e) {
172                                    sliderValueChanged(myIndex);
173                            }
174                    });
175            jSliders[index].setValue(sources[index]);
176            //Construct a button that will permit to copy source to destination.
177            JButton jButtonCopy = new JButton("=>"); 
178            jButtonCopy.setToolTipText(SearsResourceBundle.getResource("resynch_copy"));
179            jButtonCopy.addActionListener(new ActionListener() {
180                            public void actionPerformed(ActionEvent e) {
181                                    copyAction(myIndex);
182                            }
183                    });
184            
185            //Add the component in the panel using GridBagLayout.
186            GridBagConstraints gbc1 =  new GridBagConstraints();
187            gbc1.gridx = 0;
188            gbc1.gridy = 0;
189            result.add(jLabelSource[index], gbc1);
190            GridBagConstraints gbc2 =  new GridBagConstraints();
191            gbc2.gridx = 1;
192            gbc2.gridy = 0;
193            gbc2.fill = GridBagConstraints.HORIZONTAL;
194            result.add(jTextSource[index], gbc2);
195            GridBagConstraints gbc3 =  new GridBagConstraints();
196            gbc3.gridx = 2;
197            gbc3.gridy = 0;
198            gbc3.weightx = 1.0;
199            gbc3.anchor = GridBagConstraints.CENTER;
200            result.add(jButtonCopy, gbc3);
201            GridBagConstraints gbc4 =  new GridBagConstraints();
202            gbc4.gridx = 3;
203            gbc4.gridy = 0;
204            result.add(jLabelDestination[index], gbc4);
205            GridBagConstraints gbc5 =  new GridBagConstraints();
206            gbc5.gridx = 4;
207            gbc5.gridy = 0;
208            gbc5.fill = GridBagConstraints.HORIZONTAL;
209            result.add(jTextDestination[index], gbc5);
210            //Line 2
211            GridBagConstraints gbc6 =  new GridBagConstraints();
212            gbc6.gridx = 0;
213            gbc6.gridy = 1;
214            gbc6.weightx = 1.0;
215            gbc6.fill = GridBagConstraints.HORIZONTAL;
216            gbc6.gridwidth = 5;
217            result.add(jLabelSubtitles[index], gbc6);
218            //line3
219            GridBagConstraints gbc7 =  new GridBagConstraints();
220            gbc7.gridx = 0;
221            gbc7.gridy = 2;
222            gbc7.weightx = 1.0;
223            gbc7.fill = GridBagConstraints.HORIZONTAL;
224            gbc7.gridwidth = 5;
225            result.add(jSliders[index], gbc7);
226            //return the result.
227            return result;
228            }
229    
230    
231        /**
232         * Method copyAction.
233         * <br><b>Summary:</b><br>
234         * This method permits to copy the value of a source to the corresponding destination.
235         * @param index                     The index of the source/destination.
236         */
237        protected void copyAction(int index) {
238            //retrieve the source value.
239            String sourceValue = jTextSource[index].getText();
240            //set it in the corresponding destination
241            jTextDestination[index].setText(sourceValue);
242            }
243    
244            /**
245         * Method sliderValueChanged.
246         * <br><b>Summary:</b><br>
247         * This method is called by the slider to indicate that their position changed.
248         * @param index             The index of the slider that change
249         */
250        protected void sliderValueChanged(int index) {
251                    //A slider has moved.
252            //get the new slider's value.
253            int subtitleIndex = jSliders[index].getValue();
254            //Changed the text of the JLabelSubtitle.
255            //Get the subtitle at the given index.
256            Subtitle subtitle = (Subtitle) subtitleList.get(subtitleIndex);
257            //construct message to show in label.
258            //Put ST number, and append the message.
259            String message = "[" + subtitle.getNumber() + "]" + subtitle.getSubtitle();
260            //Cut long ST, not to perturb GUI.
261            int maxLength = 35;
262            if (message.length() > maxLength) {
263                message = message.substring(0, maxLength - 1) + "...";
264            }
265            //set the label to the content of the subtitle.
266            jLabelSubtitles[index].setText(message);
267            //And set the source textField.
268            jTextSource[index].setText(SubtitleFile.timeToString(subtitle.getStartDate()));
269            }
270    
271            /* (non-Javadoc)
272         * @see sears.gui.SearsJDialog#hasBeenValidated()
273         */
274        public boolean hasBeenValidated() {
275            return validationStatus;
276        }
277    
278        /**
279         * Method getResult.
280         * <br><b>Summary:</b><br>
281         * This method returns the resynchro dialog result.
282         * @return      <b>int[]</b>    An array of int:[source1, destination1, source2, destination2 .... etc]
283         */
284        public int[] getResult() {
285    
286            int[] result = new int[sources.length * 2];
287            for (int i = 0; i < sources.length; i++) {
288                            result[2*i] = SubtitleFile.stringToTime(jTextSource[i].getText());
289                            result[2*i+1] = SubtitleFile.stringToTime(jTextDestination[i].getText());
290                    }
291            return result;
292        }
293    
294        /* (non-Javadoc)
295         * @see sears.gui.SearsJDialog#getDialogName()
296         */
297        protected String getDialogName() {
298            return "resynchro";
299        }
300    }