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                mainPanel.setBorder(super.createEmptyBorder());
138                for(int i = 0; i < sources.length; i++){
139                    mainPanel.add(getJPanelSubtitle(i));
140                }
141            }
142            return mainPanel;
143        }
144    
145        /**
146         * Method getJPanelSubtitle.
147         * <br><b>Summary:</b><br>
148         * This method returns the JPanel that is used to define the subtitle of the given index.
149         * @param index                                     The index of the resynchro subtitle.
150         * @return  (<b>JPanel</b>)   the JPanel that is used to define the subtitle of the given index.
151         */
152        private JPanel getJPanelSubtitle(int index) {
153            //The result of the method.
154            JPanel result = new JPanel();
155            result.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "["+index+"]"));
156            result.setLayout(new GridBagLayout());
157            final int myIndex = index;
158            //Now construct the panel content.
159            jTextSource[index] = new JTextField("00:00:00,000");
160            jLabelSource[index] = new JLabel(SearsResourceBundle.getResource("resynch_source")+" "+index+":");
161            jTextDestination[index] = new JTextField("00:00:00,000");
162            //change the destination value if subttitle is anchored.
163            Subtitle subtitle = subtitleList.get(sources[index]);
164            if(subtitle.isAnchored()){
165                    jTextDestination[index].setText(SubtitleFile.timeToString(subtitle.getAnchor()));
166            }
167            jLabelDestination[index] = new JLabel(SearsResourceBundle.getResource("resynch_destination")+" "+index+":");
168            //Construct the JSlider, current value is the selected source index.
169            jLabelSubtitles[index] = new JLabel(((Subtitle) subtitleList.get(sources[index])).getSubtitle());
170            jSliders[index] = new JSlider(0, subtitleList.size()-1);
171            jSliders[index].addChangeListener(new ChangeListener() {
172                            public void stateChanged(ChangeEvent e) {
173                                    sliderValueChanged(myIndex);
174                            }
175                    });
176            jSliders[index].setValue(sources[index]);
177            //Construct a button that will permit to copy source to destination.
178            JButton jButtonCopy = new JButton("=>"); 
179            jButtonCopy.setToolTipText(SearsResourceBundle.getResource("resynch_copy"));
180            jButtonCopy.addActionListener(new ActionListener() {
181                            public void actionPerformed(ActionEvent e) {
182                                    copyAction(myIndex);
183                            }
184                    });
185            
186            //Add the component in the panel using GridBagLayout.
187            GridBagConstraints gbc1 =  new GridBagConstraints();
188            gbc1.gridx = 0;
189            gbc1.gridy = 0;
190            gbc1.ipadx = 4;
191            result.add(jLabelSource[index], gbc1);
192            GridBagConstraints gbc2 =  new GridBagConstraints();
193            gbc2.gridx = 1;
194            gbc2.gridy = 0;
195            gbc2.fill = GridBagConstraints.HORIZONTAL;
196            result.add(jTextSource[index], gbc2);
197            GridBagConstraints gbc3 =  new GridBagConstraints();
198            gbc3.gridx = 2;
199            gbc3.gridy = 0;
200            gbc3.weightx = 1.0;
201            gbc3.anchor = GridBagConstraints.CENTER;
202            result.add(jButtonCopy, gbc3);
203            GridBagConstraints gbc4 =  new GridBagConstraints();
204            gbc4.gridx = 3;
205            gbc4.gridy = 0;
206            gbc4.ipadx = 4;
207            result.add(jLabelDestination[index], gbc4);
208            GridBagConstraints gbc5 =  new GridBagConstraints();
209            gbc5.gridx = 4;
210            gbc5.gridy = 0;
211            gbc5.fill = GridBagConstraints.HORIZONTAL;
212            result.add(jTextDestination[index], gbc5);
213            //Line 2
214            GridBagConstraints gbc6 =  new GridBagConstraints();
215            gbc6.gridx = 0;
216            gbc6.gridy = 1;
217            gbc6.weightx = 1.0;
218            gbc6.fill = GridBagConstraints.HORIZONTAL;
219            gbc6.gridwidth = 5;
220            result.add(jLabelSubtitles[index], gbc6);
221            //line3
222            GridBagConstraints gbc7 =  new GridBagConstraints();
223            gbc7.gridx = 0;
224            gbc7.gridy = 2;
225            gbc7.weightx = 1.0;
226            gbc7.fill = GridBagConstraints.HORIZONTAL;
227            gbc7.gridwidth = 5;
228            result.add(jSliders[index], gbc7);
229            //return the result.
230            return result;
231            }
232    
233    
234        /**
235         * Method copyAction.
236         * <br><b>Summary:</b><br>
237         * This method permits to copy the value of a source to the corresponding destination.
238         * @param index                     The index of the source/destination.
239         */
240        protected void copyAction(int index) {
241            //retrieve the source value.
242            String sourceValue = jTextSource[index].getText();
243            //set it in the corresponding destination
244            jTextDestination[index].setText(sourceValue);
245            }
246    
247            /**
248         * Method sliderValueChanged.
249         * <br><b>Summary:</b><br>
250         * This method is called by the slider to indicate that their position changed.
251         * @param index             The index of the slider that change
252         */
253        protected void sliderValueChanged(int index) {
254                    //A slider has moved.
255            //get the new slider's value.
256            int subtitleIndex = jSliders[index].getValue();
257            //Changed the text of the JLabelSubtitle.
258            //Get the subtitle at the given index.
259            Subtitle subtitle = (Subtitle) subtitleList.get(subtitleIndex);
260            //construct message to show in label.
261            //Put ST number, and append the message.
262            String message = "[" + subtitle.getNumber() + "]" + " " + subtitle.getSubtitle();
263            //Cut long ST, not to perturb GUI.
264            int maxLength = 35;
265            if (message.length() > maxLength) {
266                message = message.substring(0, maxLength - 1) + "...";
267            }
268            //set the label to the content of the subtitle.
269            jLabelSubtitles[index].setText(message);
270            //And set the source textField.
271            jTextSource[index].setText(SubtitleFile.timeToString(subtitle.getStartDate()));
272            }
273    
274            /* (non-Javadoc)
275         * @see sears.gui.SearsJDialog#hasBeenValidated()
276         */
277        public boolean hasBeenValidated() {
278            return validationStatus;
279        }
280    
281        /**
282         * Method getResult.
283         * <br><b>Summary:</b><br>
284         * This method returns the resynchro dialog result.
285         * @return      <b>int[]</b>    An array of int:[source1, destination1, source2, destination2 .... etc]
286         */
287        public int[] getResult() {
288    
289            int[] result = new int[sources.length * 2];
290            for (int i = 0; i < sources.length; i++) {
291                            result[2*i] = SubtitleFile.stringToTime(jTextSource[i].getText());
292                            result[2*i+1] = SubtitleFile.stringToTime(jTextDestination[i].getText());
293                    }
294            return result;
295        }
296    
297        /* (non-Javadoc)
298         * @see sears.gui.SearsJDialog#getDialogName()
299         */
300        protected String getDialogName() {
301            return "resynchro";
302        }
303    }