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