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 }