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.io.File;
026    import java.io.IOException;
027    import java.util.ArrayList;
028    
029    import javax.swing.BorderFactory;
030    import javax.swing.JButton;
031    import javax.swing.JCheckBox;
032    import javax.swing.JLabel;
033    import javax.swing.JOptionPane;
034    import javax.swing.JPanel;
035    import javax.swing.JSlider;
036    import javax.swing.JTextField;
037    import javax.swing.event.ChangeEvent;
038    import javax.swing.event.ChangeListener;
039    
040    import sears.file.Subtitle;
041    import sears.file.SubtitleFile;
042    import sears.gui.resources.SearsResources;
043    import sears.tools.SearsResourceBundle;
044    import sears.tools.Trace;
045    
046    /**
047     * Class JDialogSplit.
048     * <br><b>Summary:</b><br>
049     * This Class permit to enter Split parameters.
050     */
051    public class JDialogSplit extends SearsJDialog implements ChangeListener {
052        private static final long serialVersionUID = -1582903664124772065L;
053    
054        private JPanel jContentPane = null;
055    
056        private JPanel jPanelCenter = null;
057    
058        private JPanel jPanelOutputFiles = null;
059    
060        private JLabel jLabelPart1 = null;
061    
062        private JTextField jTextFieldPart1 = null;
063    
064        private JButton jButtonPart1 = null;
065    
066        private JLabel jLabelPart2 = null;
067    
068        private JTextField jTextFieldPart2 = null;
069    
070        private JButton jButtonPart2 = null;
071    
072        private JPanel jPanelSubtitle = null;
073    
074        private JLabel jLabelSubtitle = null;
075    
076        private JSlider jSliderSubtitle = null;
077    
078        private JPanel jPanelChecks = null;
079    
080        private JCheckBox jCheckBoxDelay = null;
081    
082        private JTextField jTextFieldDelay = null;
083    
084        private JCheckBox jCheckBoxOpenSecond = null;
085    
086        /**The entered destination files. This array is filled in the checkParameters method*/
087        private File[] destinationFiles;
088    
089        /**The subtitleList, that contains all the subtitles.*/
090        private ArrayList subtitleList;
091    
092        /**The first choosen subtitle and the last choosen one, when user validates the dialog.*/
093        private int choosenSubtitle;
094    
095        /**The opened subtitleFile.*/
096        private SubtitleFile subtitleFile;
097    
098        /**
099         * This is the default constructor
100         */
101        public JDialogSplit(ArrayList _subtitleList, int _choosenSubtitle, SubtitleFile _subtitleFile) {
102            super(SearsResourceBundle.getResource("split_title"));
103            //Initialize attributes.
104            choosenSubtitle = _choosenSubtitle;
105            subtitleList = _subtitleList;
106            validationStatus = false;
107            subtitleFile = _subtitleFile;
108            initializeDestinationFiles();
109            setContentPane(getJContentPane());
110            configureSize();
111        }
112    
113        /**
114         * Method initializeDestinationFiles.
115         * <br><b>Summary:</b><br>
116         * Call to method to initialize the destination files array.
117         */
118        private void initializeDestinationFiles() {
119            //construct array.
120            destinationFiles = new File[2];
121            //Construct filename 1 (which will contains the first range)
122            String fileName = subtitleFile.getFile().getName();
123            //remove extension
124            fileName = fileName.substring(0, fileName.lastIndexOf("."));
125            destinationFiles[0] = new File(subtitleFile.getFile().getParent() + File.separator + fileName + "_1.srt");
126            //construct filename 2
127            destinationFiles[1] = new File(subtitleFile.getFile().getParent() + File.separator + fileName + "_2.srt");
128        }
129    
130        /**
131         * This method initializes jContentPane
132         * 
133         * @return javax.swing.JPanel
134         */
135        private JPanel getJContentPane() {
136            if (jContentPane == null) {
137                jContentPane = new JPanel();
138                jContentPane.setLayout(new BorderLayout());
139                jContentPane.add(getJPanelButtons(), java.awt.BorderLayout.SOUTH);
140                jContentPane.add(getJPanelCenter(), java.awt.BorderLayout.CENTER);
141            }
142            return jContentPane;
143        }
144    
145        /**
146         * Method okAction.
147         * <br><b>Summary:</b><br>
148         * This method is called when user validate the dialog.
149         */
150        protected void okAction() {
151            //Just have to check parameters validity, if valids, dispose dialog,and set validation status to true.
152            String error = checkParameters();
153            if (error != null && !error.equals("")) {
154                //Show error message.
155                JOptionPane.showMessageDialog(this, error, SearsResourceBundle.getResource("error_splitConfigurationError"),
156                        JOptionPane.ERROR_MESSAGE);
157                Trace.trace("Error in Split parameters:" + error, Trace.WARNING_PRIORITY);
158            } else {
159                //else split configuration is valid, release dialog.
160                validationStatus = true;
161                dispose();
162            }
163        }
164    
165        /**
166         * Method checkParameters.
167         * <br><b>Summary:</b><br>
168         * This method permits to check the split parameters validity.
169         * It sets the final parameters that will be returned by the public methods.
170         * @return  <b>String</b>   "" if there is no error in parameters, error message otherwise.
171         */
172        private String checkParameters() {
173            //The error message that will be returned.
174            String errorMessage = "";
175            //Check first destination file.
176            errorMessage += checkFile(getJTextFieldPart1().getText(), 0);
177            //check second file.
178            errorMessage += checkFile(getJTextFieldPart2().getText(), 1);
179            //check choosen subtitle.
180            //nothing to check... slider is obsviously between min and max :/
181            choosenSubtitle = getJSliderSubtitle().getValue();
182            //check delay.
183            if (getJCheckBoxDelay().isSelected()) {
184                String delay = getJTextFieldDelay().getText();
185                if (delay != null && !delay.equals("")) {
186                    try {
187                        Double.parseDouble(delay);
188                    } catch (NumberFormatException e) {
189                        //Delay value is not a number.
190                        errorMessage += SearsResourceBundle.getResource("error_delayNotValid") + "\n";
191                    }
192                } else {
193                    //Delay value is null.
194                    errorMessage += SearsResourceBundle.getResource("error_delayNull") + "\n";
195                }
196            }
197            return errorMessage;
198        }
199    
200        /**
201         * Method checkFile.
202         * <br><b>Summary:</b><br>
203         * This method check a destination fileName validity.
204         * @param fileName          The fileNAme to check.
205         * @param destinationIndex  The destination index, 0 for first part, and 1 for the second part.
206         * @return String           The new error message.
207         */
208        private String checkFile(String fileName, int destinationIndex) {
209            String errorMessage = "";
210            if (fileName != null && !fileName.equals("")) {
211                File file = new File(fileName);
212                try {
213                    if ((file.exists() && file.canWrite()) || file.createNewFile()) {
214                        //set destination file
215                        destinationFiles[destinationIndex] = file;
216                    } else {
217                        //cannot write to file!
218                        errorMessage += SearsResourceBundle.getResource("error_cannotWrite") + fileName + ".\n";
219                    }
220                } catch (IOException e) {
221                    //cannot write to file!
222                    errorMessage += SearsResourceBundle.getResource("error_cannotWrite") + fileName + ".\n";
223                }
224            } else {
225                //cannot write to file!
226                errorMessage += SearsResourceBundle.getResource("error_destinationNotDefined1") + " " + (destinationIndex + 1) + " "
227                        + SearsResourceBundle.getResource("error_destinationNotDefined2") + "\n";
228            }
229            return errorMessage;
230        }
231    
232        /**
233         * This method initializes jPanel   
234         *  
235         * @return javax.swing.JPanel       
236         */
237        private JPanel getJPanelCenter() {
238            if (jPanelCenter == null) {
239                GridBagConstraints gridBagConstraints12 = new GridBagConstraints();
240                gridBagConstraints12.gridx = 0;
241                gridBagConstraints12.gridy = 4;
242                gridBagConstraints12.anchor = java.awt.GridBagConstraints.WEST;
243                gridBagConstraints12.fill = java.awt.GridBagConstraints.HORIZONTAL;
244                GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
245                gridBagConstraints11.fill = java.awt.GridBagConstraints.HORIZONTAL;
246                gridBagConstraints11.gridx = 0;
247                gridBagConstraints11.gridy = 2;
248                gridBagConstraints11.gridheight = 2;
249                GridBagConstraints gridBagConstraints = new GridBagConstraints();
250                gridBagConstraints.gridx = 0;
251                gridBagConstraints.gridheight = 2;
252                gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
253                gridBagConstraints.gridy = 0;
254                jPanelCenter = new JPanel();
255                jPanelCenter.setLayout(new GridBagLayout());
256                jPanelCenter.add(getJPanelOutputFiles(), gridBagConstraints);
257                jPanelCenter.add(getJPanelSubtitle(), gridBagConstraints11);
258                jPanelCenter.add(getJPanelChecks(), gridBagConstraints12);
259            }
260            return jPanelCenter;
261        }
262    
263        /**
264         * This method initializes jPanel   
265         *  
266         * @return javax.swing.JPanel       
267         */
268        private JPanel getJPanelOutputFiles() {
269            if (jPanelOutputFiles == null) {
270                GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
271                gridBagConstraints4.fill = java.awt.GridBagConstraints.HORIZONTAL;
272                gridBagConstraints4.weightx = 1.0;
273                gridBagConstraints4.gridx = 1;
274                gridBagConstraints4.gridy = 1;
275                GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
276                gridBagConstraints5.gridx = 2;
277                gridBagConstraints5.insets = new java.awt.Insets(1, 0, 7, 0);
278                gridBagConstraints5.ipadx = 0;
279                gridBagConstraints5.gridy = 1;
280                GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
281                gridBagConstraints3.gridx = 0;
282                gridBagConstraints3.gridy = 1;
283                jLabelPart2 = new JLabel();
284                jLabelPart2.setText(SearsResourceBundle.getResource("split_part") + "2");
285                jLabelPart1 = new JLabel();
286                jLabelPart1.setText(SearsResourceBundle.getResource("split_part") + "1");
287                GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
288                gridBagConstraints2.gridx = 2;
289                gridBagConstraints2.gridy = 0;
290                GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
291                gridBagConstraints1.gridx = 1;
292                gridBagConstraints1.gridy = 0;
293                gridBagConstraints1.fill = java.awt.GridBagConstraints.HORIZONTAL;
294                gridBagConstraints1.weightx = 1.0;
295                jPanelOutputFiles = new JPanel();
296                jPanelOutputFiles.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), SearsResourceBundle
297                        .getResource("split_outputFiles")));
298                jPanelOutputFiles.setSize(400, 200);
299                jPanelOutputFiles.setLayout(new GridBagLayout());
300                jPanelOutputFiles.add(jLabelPart1, new GridBagConstraints());
301                jPanelOutputFiles.add(getJTextFieldPart1(), gridBagConstraints1);
302                jPanelOutputFiles.add(getJButtonPart1(), gridBagConstraints2);
303                jPanelOutputFiles.add(jLabelPart2, gridBagConstraints3);
304                jPanelOutputFiles.add(getJTextFieldPart2(), gridBagConstraints4);
305                jPanelOutputFiles.add(getJButtonPart2(), gridBagConstraints5);
306            }
307            return jPanelOutputFiles;
308        }
309    
310        /**
311         * This method initializes jTextField       
312         *  
313         * @return javax.swing.JTextField   
314         */
315        private JTextField getJTextFieldPart1() {
316            if (jTextFieldPart1 == null) {
317                jTextFieldPart1 = new JTextField(18);
318                jTextFieldPart1.setText(destinationFiles[0].getAbsolutePath());
319            }
320            return jTextFieldPart1;
321        }
322    
323        /**
324         * This method initializes jButton  
325         *  
326         * @return javax.swing.JButton      
327         */
328        private JButton getJButtonPart1() {
329            if (jButtonPart1 == null) {
330                jButtonPart1 = new JButton(SearsResources.getIcon("BrowseIcon"));
331                jButtonPart1.addActionListener(new ActionListener() {
332                    public void actionPerformed(ActionEvent e) {
333                        browseDestinationFile(0);
334                    }
335                });
336            }
337            return jButtonPart1;
338        }
339    
340        /**
341         * Method browseDestinationFile.
342         * <br><b>Summary:</b><br>
343         * Use thid method to choose destination files.
344         * @param i     An <b>int</b> equals to 0 to choose first part, or 1 to choose second part.
345         */
346        protected void browseDestinationFile(int i) {
347            File choosenFile = MainWindow.instance.showSRTBrowser();
348            if (choosenFile != null) {
349                if (i == 0) {
350                    getJTextFieldPart1().setText(choosenFile.getAbsolutePath());
351                } else {
352                    getJTextFieldPart2().setText(choosenFile.getAbsolutePath());
353                }
354            }
355        }
356    
357        /**
358         * This method initializes jTextField       
359         *  
360         * @return javax.swing.JTextField   
361         */
362        private JTextField getJTextFieldPart2() {
363            if (jTextFieldPart2 == null) {
364                jTextFieldPart2 = new JTextField(18);
365                jTextFieldPart2.setText(destinationFiles[1].getAbsolutePath());
366            }
367            return jTextFieldPart2;
368        }
369    
370        /**
371         * This method initializes jButton  
372         *  
373         * @return javax.swing.JButton      
374         */
375        private JButton getJButtonPart2() {
376            if (jButtonPart2 == null) {
377                jButtonPart2 = new JButton(SearsResources.getIcon("BrowseIcon"));
378                jButtonPart2.addActionListener(new ActionListener() {
379                    public void actionPerformed(ActionEvent e) {
380                        browseDestinationFile(1);
381                    }
382                });
383            }
384            return jButtonPart2;
385        }
386    
387        /**
388         * This method initializes jPanel   
389         *  
390         * @return javax.swing.JPanel       
391         */
392        private JPanel getJPanelSubtitle() {
393            if (jPanelSubtitle == null) {
394                jPanelSubtitle = new JPanel();
395                jPanelSubtitle.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), SearsResourceBundle
396                        .getResource("split_cutOnST")));
397                jPanelSubtitle.setLayout(new GridLayout(2, 1));
398                jPanelSubtitle.add(getJLabelSubtitle(), null);
399                jPanelSubtitle.add(getJSliderSubtitle(), null);
400            }
401            return jPanelSubtitle;
402        }
403    
404        /**
405         * This method initialize the JLabelSubtitle.
406         * 
407         * @return javax.swing.JLabel
408         */
409        private JLabel getJLabelSubtitle() {
410            if (jLabelSubtitle == null) {
411                jLabelSubtitle = new JLabel();
412                setSubtitleLabel(choosenSubtitle);
413            }
414            return jLabelSubtitle;
415        }
416    
417        /**
418         * This method initializes jSlider  
419         *  
420         * @return javax.swing.JSlider      
421         */
422        private JSlider getJSliderSubtitle() {
423            if (jSliderSubtitle == null) {
424                jSliderSubtitle = new JSlider(0, subtitleList.size() - 1, choosenSubtitle);
425                jSliderSubtitle.addChangeListener(this);
426            }
427            return jSliderSubtitle;
428        }
429    
430        /**
431         * This method initializes jPanel   
432         *  
433         * @return javax.swing.JPanel       
434         */
435        private JPanel getJPanelChecks() {
436            if (jPanelChecks == null) {
437                GridBagConstraints gridBagConstraints8 = new GridBagConstraints();
438                gridBagConstraints8.gridx = 0;
439                gridBagConstraints8.anchor = java.awt.GridBagConstraints.WEST;
440                gridBagConstraints8.gridwidth = 2;
441                gridBagConstraints8.gridy = 1;
442                GridBagConstraints gridBagConstraints7 = new GridBagConstraints();
443                gridBagConstraints7.fill = java.awt.GridBagConstraints.NONE;
444                gridBagConstraints7.weightx = 1.0;
445                GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
446                gridBagConstraints6.anchor = java.awt.GridBagConstraints.WEST;
447                jPanelChecks = new JPanel();
448                jPanelChecks.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), SearsResourceBundle
449                        .getResource("split_options")));
450                jPanelChecks.setLayout(new GridBagLayout());
451                jPanelChecks.add(getJCheckBoxDelay(), gridBagConstraints6);
452                jPanelChecks.add(getJTextFieldDelay(), gridBagConstraints7);
453                jPanelChecks.add(getJCheckBoxOpenSecond(), gridBagConstraints8);
454            }
455            return jPanelChecks;
456        }
457    
458        /**
459         * This method initializes jCheckBox        
460         *  
461         * @return javax.swing.JCheckBox    
462         */
463        private JCheckBox getJCheckBoxDelay() {
464            if (jCheckBoxDelay == null) {
465                jCheckBoxDelay = new JCheckBox(SearsResourceBundle.getResource("split_delay2ndPart"));
466            }
467            return jCheckBoxDelay;
468        }
469    
470        /**
471         * This method initializes jTextField       
472         *  
473         * @return javax.swing.JTextField   
474         */
475        private JTextField getJTextFieldDelay() {
476            if (jTextFieldDelay == null) {
477                jTextFieldDelay = new JTextField("1", 4);
478                jTextFieldDelay.setToolTipText(SearsResourceBundle.getResource("delay_tip"));
479            }
480            return jTextFieldDelay;
481        }
482    
483        /**
484         * This method initializes jCheckBox        
485         *  
486         * @return javax.swing.JCheckBox    
487         */
488        private JCheckBox getJCheckBoxOpenSecond() {
489            if (jCheckBoxOpenSecond == null) {
490                jCheckBoxOpenSecond = new JCheckBox(SearsResourceBundle.getResource("split_open2ndPart"));
491            }
492            return jCheckBoxOpenSecond;
493        }
494    
495        /**
496         * Method getDestinationsFiles.
497         * <br><b>Summary:</b><br>
498         * This method returns the entered destinations files.
499         * @return  <b>Files[]</b>      The entered destination files. or null if user didn't validate.
500         */
501        public File[] getDestinationsFiles() {
502            //The result of the method.
503            return destinationFiles;
504        }
505    
506        /* (non-Javadoc)
507         * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
508         */
509        public void stateChanged(ChangeEvent e) {
510            //When slider change of value, change the content of the jLabelSubtitle.
511            if (e.getSource() == jSliderSubtitle) {
512                setSubtitleLabel(jSliderSubtitle.getValue());
513            }
514        }
515    
516        /**
517         * Method setSubtitleLabel.
518         * <br><b>Summary:</b><br>
519         * Call this method to fill the subtitle label with the content of the subtitle at the given index. 
520         * @param index     The <b>int</b> index to find the subtitle.
521         */
522        private void setSubtitleLabel(int index) {
523            //Get the subtitle at the given index.
524            Subtitle subtitle = (Subtitle) subtitleList.get(index);
525            //construct message to show in label.
526            //Put ST number, and append the message.
527            String message = "[" + subtitle.getNumber() + "]" + subtitle.getSubtitle();
528            //Cut long ST, not to perturb GUI.
529            int maxLength = 35;
530            if (message.length() > maxLength) {
531                message = message.substring(0, maxLength - 1) + "...";
532            }
533            //set the label to the content of the subtitle.
534            getJLabelSubtitle().setText(message);
535        }
536    
537        /**
538         * Method getDelay.
539         * <br><b>Summary:</b><br>
540         * This method return the delay entered for the second part.
541         * @return  double     The delay entered for the second part, or 1 if not delay is necessary (1s will be the delay by default).
542         */
543        public double getSecondPartDelay() {
544            //the result of the method.
545            double result = -1;
546            if (getJCheckBoxDelay().isSelected()) {
547                try {
548                    //get the delay from the textField.
549                    result = Double.parseDouble(getJTextFieldDelay().getText());
550                } catch (NumberFormatException e) {
551                    Trace.trace("Bad number entered in Delay ! Delay is ignored.", Trace.ERROR_PRIORITY);
552                    //set a delay of 1
553                    result = 1;
554                }
555            }
556            //return the result
557            return result;
558        }
559    
560        /**
561         * Method needToOpenSecondPart.
562         * <br><b>Summary:</b><br>
563         * Return true if the open second part checkBox is selected.
564         * @return  boolean True if the open second part checkBox is selected. False otherwise.
565         */
566        public boolean needToOpenSecondPart() {
567            //return true if checkBox is selectd.
568            return getJCheckBoxOpenSecond().isSelected();
569        }
570    
571        /**
572         * Method getChoosenSubtitle.
573         * <br><b>Summary:</b><br>
574         * This method return the choosen subtitle index for spliting.
575         * @return  <b>int</b>  The choosen subtitle index for spliting.
576         */
577        public int getChoosenSubtitle() {
578            return choosenSubtitle;
579        }
580    
581        /* (non-Javadoc)
582         * @see sears.gui.SearsJDialog#getDialogName()
583         */
584        protected String getDialogName() {
585            return "split";
586        }
587    }