OSDN Git Service

チェックボックス文字列修正
[coroid/inqubus.git] / frontend / src / yukihane / inqubus / gui / MainFrame.java
1 /*
2  * MainFrame.java
3  *
4  * Created on 2011/05/28, 18:14:51
5  */
6 package yukihane.inqubus.gui;
7
8 import java.awt.Dimension;
9 import java.awt.Image;
10 import java.awt.ItemSelectable;
11 import java.awt.Point;
12 import java.awt.Toolkit;
13 import java.awt.datatransfer.DataFlavor;
14 import java.awt.datatransfer.Transferable;
15 import java.awt.event.ActionEvent;
16 import java.awt.event.ActionListener;
17 import java.awt.event.ItemEvent;
18 import java.awt.event.ItemListener;
19 import java.awt.event.KeyEvent;
20 import java.awt.event.WindowAdapter;
21 import java.awt.event.WindowEvent;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.io.File;
25 import java.io.FilenameFilter;
26 import java.io.IOException;
27 import java.net.URL;
28 import java.nio.file.FileSystem;
29 import java.nio.file.FileSystems;
30 import java.nio.file.Path;
31 import java.util.ArrayList;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Set;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
37 import java.util.regex.Pattern;
38 import javax.swing.BorderFactory;
39 import javax.swing.DropMode;
40 import javax.swing.GroupLayout;
41 import javax.swing.GroupLayout.Alignment;
42 import javax.swing.JButton;
43 import javax.swing.JCheckBox;
44 import javax.swing.JFrame;
45 import javax.swing.JLabel;
46 import javax.swing.JMenu;
47 import javax.swing.JMenuBar;
48 import javax.swing.JMenuItem;
49 import javax.swing.JOptionPane;
50 import javax.swing.JPanel;
51 import javax.swing.JScrollPane;
52 import javax.swing.JTabbedPane;
53 import javax.swing.JTable;
54 import javax.swing.JTextField;
55 import javax.swing.KeyStroke;
56 import javax.swing.LayoutStyle.ComponentPlacement;
57 import javax.swing.SwingUtilities;
58 import javax.swing.TransferHandler;
59 import javax.swing.WindowConstants;
60 import javax.swing.border.BevelBorder;
61 import org.apache.commons.configuration.ConfigurationException;
62 import org.apache.commons.lang.StringUtils;
63 import org.apache.commons.lang.builder.ToStringBuilder;
64 import saccubus.FfmpegOption;
65 import saccubus.MainFrame_AboutBox;
66 import saccubus.util.WayBackTimeParser;
67 import saccubus.worker.impl.convert.ConvertProgress;
68 import saccubus.worker.impl.download.DownloadProgress;
69 import saccubus.worker.WorkerListener;
70 import saccubus.worker.impl.convert.ConvertResult;
71 import saccubus.worker.impl.download.DownloadResult;
72 import saccubus.worker.profile.CommentProfile;
73 import saccubus.worker.profile.ConvertProfile;
74 import saccubus.worker.profile.DownloadProfile;
75 import saccubus.worker.profile.FfmpegProfile;
76 import saccubus.worker.profile.GeneralProfile;
77 import saccubus.worker.profile.LoginProfile;
78 import saccubus.worker.profile.OutputProfile;
79 import saccubus.worker.profile.ProxyProfile;
80 import saccubus.worker.profile.VideoProfile;
81 import yukihane.Util;
82 import yukihane.inqubus.Config;
83 import yukihane.inqubus.filewatch.FileWatch;
84 import yukihane.inqubus.manager.RequestProcess;
85 import yukihane.inqubus.manager.TaskKind;
86 import yukihane.inqubus.manager.TaskManage;
87 import yukihane.inqubus.manager.TaskManageListener;
88 import yukihane.inqubus.manager.TaskStatus;
89 import yukihane.inqubus.model.Target;
90 import yukihane.inqubus.model.TargetsTableModel;
91
92 /**
93  *
94  * @author yuki
95  */
96 public class MainFrame extends JFrame {
97
98     private static final long serialVersionUID = 1L;
99     private static final Logger logger = Logger.getLogger(MainFrame.class.getName());
100     private static final String ID_FIELD_TOOLTIP = "動画のIDまたはURLを入力します。";
101     private static final String FILE_LOCALBUTTON_TOOLTIP
102             = "<html>ダウンロードする場合はチェックを外します。<br/>ローカルファイルを使用する場合はチェックを入れます。</html>";
103     private static final String FILE_INPUTFIELD_TOOLTIP
104             = "<html>ダウンロードする場合はファイル命名規則を入力します。<br/>"
105             + "ローカルファイルを使用する場合はパスを含むファイル名を入力します。</html>";
106     private static final String FILE_OUTPUTFIELD_TOOLTIP
107             = "ファイル命名規則入力します。";
108     private final TargetsTableModel targetModel = new TargetsTableModel();
109     private final TaskManage taskManager;
110     private final Thread videoFileWatcherThread;
111     private final FileWatch videoFileWatcher;
112
113     /** Creates new form MainFrame */
114     public MainFrame() {
115         super();
116         addWindowListener(new MainFrameWindowListener());
117
118         final Config p = Config.INSTANCE;
119
120         // ワーカスレッド生成
121         final int thDownload = p.getSystemDownloadThread();
122         final int secDownload = p.getSystemDownloadWait();
123         final int thConvert = p.getSystemConvertThread();
124         taskManager = new TaskManage(thDownload, secDownload, thConvert, new GuiTaskManageListener());
125
126         // TODO ディレクトリ監視スレッド生成
127         final List<String> videoSearchDirs = p.getSearchVideoDirs();
128         videoSearchDirs.add(p.getVideoDir());
129         final FileSystem fs = FileSystems.getDefault();
130         final Set<Path> videoPaths = new HashSet<>(videoSearchDirs.size());
131         for (String s : videoSearchDirs) {
132             videoPaths.add(fs.getPath(s));
133         }
134         videoFileWatcher = new FileWatch(videoPaths);
135         this.videoFileWatcherThread = new Thread(videoFileWatcher);
136         this.videoFileWatcherThread.setDaemon(true);
137
138         final URL url = MainFrame_AboutBox.class.getResource("icon.png");
139         final Image icon1 = Toolkit.getDefaultToolkit().createImage(url);
140         final URL url32 = MainFrame_AboutBox.class.getResource("icon32.png");
141         final Image icon2 = Toolkit.getDefaultToolkit().createImage(url32);
142         final List<Image> images = new ArrayList<>(2);
143         images.add(icon1);
144         images.add(icon2);
145         setIconImages(images);
146
147         final JPanel pnlMain = new JPanel();
148         final JScrollPane scrDisplay = new JScrollPane();
149         tblDisplay = new JTable(targetModel, new TargetsColumnModel());
150         tblDisplay.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
151         final JPanel pnlButton = new JPanel();
152         final JPanel pnlInputMain = new JPanel();
153         final JLabel lblId = new JLabel();
154         final JLabel lblVideo = new JLabel();
155         cbVideoLocal = new JCheckBox();
156         cbVideoLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
157         fldVideo = new JTextField();
158         fldVideo.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
159         final JLabel lblComment = new JLabel();
160
161         fldBackLog.setToolTipText("YYYY/MM/DD hh:mm:ss形式、あるいは1970/01/01からの経過秒を入力します。");
162         cbBackLog.addItemListener(new ItemListener() {
163
164             @Override
165             public void itemStateChanged(ItemEvent e) {
166                 final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
167                 fldBackLog.setEnabled(selected);
168             }
169         });
170         cbBackLog.addPropertyChangeListener("enabled", new PropertyChangeListener() {
171
172             @Override
173             public void propertyChange(PropertyChangeEvent evt) {
174                 final boolean enabled = ((Boolean) evt.getNewValue()).booleanValue();
175                 final boolean fldEnabled = enabled ? cbBackLog.isSelected() : false;
176                 fldBackLog.setEnabled(fldEnabled);
177             }
178         });
179         cbBackLogReduce.setToolTipText("「コメントの量を減らす」場合はチェックを付けます。");
180
181         cbCommentLocal = new JCheckBox();
182         cbCommentLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
183         cbCommentLocal.addItemListener(new ItemListener() {
184
185             @Override
186             public void itemStateChanged(ItemEvent e) {
187                 final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
188                 cbBackLogReduce.setEnabled(!selected);
189                 cbBackLog.setEnabled(!selected);
190             }
191         });
192         fldComment = new JTextField();
193         fldComment.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
194         final JLabel lblOutput = new JLabel();
195         cbOutputEnable = new JCheckBox();
196         fldOutput = new JTextField();
197         fldOutput.setToolTipText(FILE_OUTPUTFIELD_TOOLTIP);
198
199         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
200
201         btnStop.addActionListener(new StopActionListener());
202         final ApplyActionListener applyListener = new ApplyActionListener();
203         btnApply.addActionListener(applyListener);
204
205         pnlMain.setBorder(BorderFactory.createEtchedBorder());
206
207         tblDisplay.setDropMode(DropMode.INSERT_ROWS);
208         scrDisplay.setViewportView(tblDisplay);
209
210         pnlButton.setBorder(BorderFactory.createEtchedBorder());
211
212         GroupLayout gl_pnlButton = new GroupLayout(pnlButton);
213         pnlButton.setLayout(gl_pnlButton);
214         gl_pnlButton.setHorizontalGroup(
215             gl_pnlButton.createParallelGroup(Alignment.LEADING)
216             .addGroup(gl_pnlButton.createSequentialGroup()
217                 .addContainerGap()
218                 .addComponent(btnStart)
219                 .addPreferredGap(ComponentPlacement.RELATED)
220                 .addComponent(btnStop)
221                 .addPreferredGap(ComponentPlacement.RELATED, 250, Short.MAX_VALUE)
222                 .addComponent(btnDeselect)
223                 .addContainerGap())
224         );
225         gl_pnlButton.setVerticalGroup(
226             gl_pnlButton.createParallelGroup(Alignment.LEADING)
227             .addGroup(gl_pnlButton.createSequentialGroup()
228                 .addContainerGap()
229                 .addGroup(gl_pnlButton.createParallelGroup(Alignment.BASELINE)
230                     .addComponent(btnStart)
231                     .addComponent(btnStop)
232                     .addComponent(btnDeselect))
233                 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
234         );
235
236         lblId.setText("ID");
237
238
239         fldId = new IdComboBox(videoFileWatcher);
240         fldId.setToolTipText(ID_FIELD_TOOLTIP);
241         fldId.getEditorComponent().addActionListener(applyListener);
242         fldId.addFocusListener(new java.awt.event.FocusAdapter() {
243
244             public void focusLost(java.awt.event.FocusEvent evt) {
245                 idFieldFocusLost(evt);
246             }
247         });
248
249         lblVideo.setText("動画");
250
251         cbVideoLocal.setText("local");
252         cbVideoLocal.addItemListener(new java.awt.event.ItemListener() {
253
254             public void itemStateChanged(java.awt.event.ItemEvent evt) {
255                 useMovieLocalCheckBoxItemStateChanged(evt);
256             }
257         });
258
259         lblComment.setText("コメント");
260
261         cbCommentLocal.setText("local");
262         cbCommentLocal.addItemListener(new java.awt.event.ItemListener() {
263
264             public void itemStateChanged(java.awt.event.ItemEvent evt) {
265                 useMovieLocalCheckBoxItemStateChanged(evt);
266             }
267         });
268
269         lblOutput.setText("出力");
270
271         cbOutputEnable.setText("変換");
272         cbOutputEnable.addItemListener(new java.awt.event.ItemListener() {
273
274             public void itemStateChanged(java.awt.event.ItemEvent evt) {
275                 outputConvertCheckBoxItemStateChanged(evt);
276             }
277         });
278
279
280         final GroupLayout glInputMain = new GroupLayout(pnlInputMain);
281         pnlInputMain.setLayout(glInputMain);
282         glInputMain.setHorizontalGroup(
283             glInputMain.createParallelGroup(Alignment.LEADING)
284             .addGroup(glInputMain.createSequentialGroup()
285                 .addContainerGap()
286                 .addComponent(lblId)
287                 .addPreferredGap(ComponentPlacement.RELATED)
288                 .addComponent(fldId, GroupLayout.PREFERRED_SIZE, 100, Short.MAX_VALUE)
289                 .addPreferredGap(ComponentPlacement.UNRELATED)
290                 .addComponent(cbBackLogReduce)
291                 .addPreferredGap(ComponentPlacement.UNRELATED)
292                 .addComponent(cbBackLog)
293                 .addPreferredGap(ComponentPlacement.RELATED)
294                 .addComponent(fldBackLog, GroupLayout.PREFERRED_SIZE, 150, GroupLayout.PREFERRED_SIZE)
295                 .addContainerGap()
296             )
297             .addGroup(glInputMain.createSequentialGroup()
298                 .addContainerGap()
299                 .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
300                     .addComponent(lblVideo)
301                     .addComponent(lblComment)
302                     .addComponent(lblOutput)
303                 )
304                 .addPreferredGap(ComponentPlacement.RELATED)
305                 .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
306                     .addComponent(cbVideoLocal)
307                     .addComponent(cbCommentLocal)
308                     .addComponent(cbOutputEnable)
309                 )
310                 .addPreferredGap(ComponentPlacement.RELATED)
311                 .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
312                     .addComponent(fldVideo, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
313                     .addComponent(fldComment, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
314                     .addComponent(fldOutput, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
315                 )
316                 .addContainerGap()
317             )
318         );
319
320         glInputMain.setVerticalGroup(
321             glInputMain.createParallelGroup(Alignment.LEADING)
322             .addGroup(glInputMain.createSequentialGroup()
323                 .addContainerGap()
324                 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
325                     .addComponent(fldId, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
326                     .addComponent(lblId)
327                     .addComponent(cbBackLogReduce)
328                     .addComponent(cbBackLog)
329                     .addComponent(fldBackLog)
330                 )
331                 .addPreferredGap(ComponentPlacement.RELATED)
332                 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
333                     .addComponent(lblVideo)
334                     .addComponent(fldVideo, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
335                     .addComponent(cbVideoLocal))
336                 .addPreferredGap(ComponentPlacement.RELATED)
337                 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
338                     .addComponent(lblComment)
339                     .addComponent(fldComment, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
340                     .addComponent(cbCommentLocal))
341                 .addPreferredGap(ComponentPlacement.RELATED)
342                 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
343                     .addComponent(lblOutput)
344                     .addComponent(fldOutput, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
345                     .addComponent(cbOutputEnable)
346                 )
347             )
348         );
349
350         // ffmpeg入力パネル
351         pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(false);
352         pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(false);
353         pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(false);
354         pnlInputFfmpeg.cmbFfmpegOptionFile.addActionListener(new ActionListener() {
355
356             @Override
357             public void actionPerformed(ActionEvent e) {
358                 final boolean notFile = !pnlInputFfmpeg.mdlFfmpegOption.isFile();
359                 pnlInputFfmpeg.fldFfmpegOptionExtension.setEnabled(notFile);
360                 pnlInputFfmpeg.fldFfmpegOptionMain.setEnabled(notFile);
361                 pnlInputFfmpeg.fldFfmpegOptionIn.setEnabled(notFile);
362                 pnlInputFfmpeg.fldFfmpegOptionOut.setEnabled(notFile);
363                 pnlInputFfmpeg.fldFfmpegOptionAv.setEnabled(notFile);
364                 pnlInputFfmpeg.cbFfmpegOptionResize.setEnabled(notFile);
365             }
366         });
367         pnlInputFfmpeg.cbFfmpegOptionResize.addItemListener(new ItemListener() {
368
369             @Override
370             public void itemStateChanged(ItemEvent e) {
371                 final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
372                 pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(selected);
373                 pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(selected);
374                 pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(selected);
375             }
376         });
377         pnlInputFfmpeg.cbFfmpegOptionResize.addPropertyChangeListener("enabled", new PropertyChangeListener() {
378
379             @Override
380             public void propertyChange(PropertyChangeEvent evt) {
381                 final boolean enabled = ((Boolean) evt.getNewValue()).booleanValue();
382                 final boolean fldEnabled = enabled ? pnlInputFfmpeg.cbFfmpegOptionResize.isSelected() : false;
383                 pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(fldEnabled);
384                 pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(fldEnabled);
385                 pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(fldEnabled);
386             }
387         });
388
389
390         tbpInput.add("メイン", pnlInputMain);
391         tbpInput.add("ffmpeg", pnlInputFfmpeg);
392
393         // 入力部のボタンやメッセージ表示部
394         fldInputMessage.setEditable(false);
395         fldInputMessage.setEnabled(false);
396         fldInputMessage.setBorder(BorderFactory.createEmptyBorder());
397
398         final JPanel pnlInputButton = new JPanel();
399         final GroupLayout glInputButton = new GroupLayout(pnlInputButton);
400         pnlInputButton.setLayout(glInputButton);
401         glInputButton.setHorizontalGroup(glInputButton.createSequentialGroup()
402             .addContainerGap()
403             .addComponent(fldInputMessage, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
404             .addPreferredGap(ComponentPlacement.UNRELATED)
405             .addComponent(btnApply)
406             .addContainerGap()
407         );
408         glInputButton.setVerticalGroup(glInputButton.createSequentialGroup()
409             .addContainerGap()
410             .addGroup(glInputButton.createParallelGroup(Alignment.BASELINE)
411                 .addComponent(fldInputMessage, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
412                 .addComponent(btnApply)
413             )
414             .addContainerGap()
415         );
416
417         // 画面下半分の入力部分
418         final JPanel pnlInputAll = new JPanel();
419         pnlInputAll.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
420         final GroupLayout glInputAll = new GroupLayout(pnlInputAll);
421         pnlInputAll.setLayout(glInputAll);
422         glInputAll.setHorizontalGroup(glInputAll.createParallelGroup()
423             .addComponent(tbpInput)
424             .addComponent(pnlInputButton)
425         );
426         glInputAll.setVerticalGroup(glInputAll.createSequentialGroup()
427             .addComponent(tbpInput)
428             .addComponent(pnlInputButton)
429         );
430
431         GroupLayout gl_pnlMain = new GroupLayout(pnlMain);
432         pnlMain.setLayout(gl_pnlMain);
433         gl_pnlMain.setHorizontalGroup(
434             gl_pnlMain.createParallelGroup(Alignment.LEADING)
435             .addGroup(Alignment.TRAILING, gl_pnlMain.createSequentialGroup()
436                 .addContainerGap()
437                 .addGroup(gl_pnlMain.createParallelGroup(Alignment.TRAILING)
438                     .addComponent(scrDisplay, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
439                     .addComponent(pnlButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
440                     .addComponent(pnlInputAll, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
441                 )
442                 .addContainerGap())
443         );
444         gl_pnlMain.setVerticalGroup(
445             gl_pnlMain.createParallelGroup(Alignment.LEADING)
446             .addGroup(Alignment.TRAILING, gl_pnlMain.createSequentialGroup()
447                 .addContainerGap()
448                 .addComponent(scrDisplay, GroupLayout.DEFAULT_SIZE, 197, Short.MAX_VALUE)
449                 .addPreferredGap(ComponentPlacement.RELATED)
450                 .addComponent(pnlButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
451                 .addPreferredGap(ComponentPlacement.RELATED)
452                 .addComponent(pnlInputAll, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
453                 .addContainerGap()
454             )
455         );
456
457
458         JMenuBar menuBar = initMenuBar();
459         setJMenuBar(menuBar);
460
461         GroupLayout layout = new GroupLayout(getContentPane());
462         getContentPane().setLayout(layout);
463         layout.setHorizontalGroup(
464             layout.createParallelGroup(Alignment.LEADING)
465             .addComponent(pnlMain, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
466         );
467         layout.setVerticalGroup(
468             layout.createParallelGroup(Alignment.LEADING)
469             .addComponent(pnlMain, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
470         );
471
472         pack();
473
474         /*
475          * 画面のサイズや位置を前回終了時のものに設定する
476          */
477         final int windowWidth = p.getSystemWindowWidth();
478         final int windowHeight = p.getSystemWindowHeight();
479         if (windowWidth > 0 && windowHeight > 0) {
480             setSize(windowWidth, windowHeight);
481         }
482
483         final int windowPosX = p.getSystemWindowPosX();
484         final int windowPosY = p.getSystemWindowPosY();
485         if (windowPosX > 0 && windowPosY > 0) {
486             setLocation(windowPosX, windowPosY);
487         } else {
488             setLocationByPlatform(true);
489         }
490
491         final int colId = p.getSystemColumnId();
492         if(colId > 0) {
493             tblDisplay.getColumnModel().getColumn(0).setPreferredWidth(colId);
494         }
495         final int colStatus = p.getSystemColumnStatus();
496         if(colStatus > 0) {
497             tblDisplay.getColumnModel().getColumn(4).setPreferredWidth(colStatus);
498         }
499
500         initInputPanel();
501         pnlMain.setTransferHandler(new DownloadListTransferHandler());
502         tblDisplay.setTransferHandler(new TableTransferHandler());
503     }
504
505     public void startWatcher() {
506         videoFileWatcherThread.start();
507     }
508
509     private class GuiTaskManageListener implements TaskManageListener {
510
511         @Override
512         public void process(final int id, final TaskKind kind, final TaskStatus status, final double percentage,
513                 final String message) {
514             SwingUtilities.invokeLater(new Runnable() {
515
516                 @Override
517                 public void run() {
518                     targetModel.setStatus(id, kind, status, percentage, message);
519                 }
520             });
521         }
522     }
523
524     private class StopActionListener implements ActionListener {
525
526         @Override
527         public void actionPerformed(ActionEvent e) {
528             final int row = tblDisplay.getSelectedRow();
529             final Target t = targetModel.getTarget(row);
530             final boolean res = taskManager.cancel(t.getRowId());
531             logger.log(Level.FINE, "停止: {0} {1}", new Object[]{t.getVideoId(), res});
532             if (res) {
533                 targetModel.setStatus(t.getRowId(), null, TaskStatus.CANCELLED, -1.0, "キャンセル");
534             }
535         }
536     }
537
538     private class ApplyActionListener implements ActionListener {
539
540         @Override
541         public void actionPerformed(ActionEvent e) {
542             try {
543                 final DownloadProfile downProf = new InqubusDownloadProfile();
544                 final String id = Util.getVideoId(fldId.getText());
545                 final InqubusConvertProfile convProf = new InqubusConvertProfile();
546                 logger.log(Level.INFO, downProf.toString());
547                 logger.log(Level.INFO, convProf.toString());
548                 final RequestProcess rp = new RequestProcess(downProf, id, convProf);
549                 taskManager.add(rp);
550                 targetModel.addTarget(new Target(rp));
551                 initInputPanel();
552             } catch (Throwable th) {
553                 logger.log(Level.SEVERE, null, th);
554                 JOptionPane.showMessageDialog(MainFrame.this, th.getMessage(), "中断しました", JOptionPane.ERROR_MESSAGE);
555             }
556         }
557     }
558
559     private File searchFileMatchId(final File dir, final String id) {
560         // TODO 候補は複数返すようにして、その後の対処は呼び出しもとで行ってもらった方が良いかも
561         if (id.isEmpty()) {
562             return null;
563         }
564
565         final File[] lists = dir.listFiles(new FilenameFilter() {
566
567             final Pattern pattern = Pattern.compile(id + "\\D");
568
569             @Override
570             public boolean accept(File dir, String name) {
571                 return pattern.matcher(name).find();
572             }
573         });
574
575         if (lists.length == 1) {
576             return lists[0];
577         } else if (lists.length > 1) {
578             throw new UnsupportedOperationException();
579         } else {
580             return null;
581         }
582     }
583
584     /**
585      * 動画, コメントの"local"チェックボックス更新時の処理.
586      */
587     private void useMovieLocalCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_useMovieLocalCheckBoxItemStateChanged
588         final Config p = Config.INSTANCE;
589
590         final ItemSelectable source = evt.getItemSelectable();
591
592         JTextField field;
593         File dir;
594         if (source == cbVideoLocal) {
595             field = fldVideo;
596             dir = new File(p.getVideoDir());
597         } else {
598             field = fldComment;
599             dir = new File(p.getCommentDir());
600         }
601
602         final boolean useLocal = (evt.getStateChange() == ItemEvent.SELECTED);
603
604         String text;
605         if (useLocal) {
606             final File f = searchFileMatchId(dir, fldId.getText());
607             if (f != null) {
608                 text = f.getPath();
609             } else {
610                 text = "";
611             }
612         } else {
613             text = p.getVideoFileNamePattern();
614         }
615         field.setText(text);
616
617     }//GEN-LAST:event_useMovieLocalCheckBoxItemStateChanged
618
619     private void outputConvertCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_outputConvertCheckBoxItemStateChanged
620         final boolean convert = (evt.getStateChange() == ItemEvent.SELECTED);
621         fldOutput.setEnabled(convert);
622     }//GEN-LAST:event_outputConvertCheckBoxItemStateChanged
623
624     private void idFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_idFieldFocusLost
625         final Config p = Config.INSTANCE;
626         final String id = fldId.getText();
627         if (id.isEmpty()) {
628             return;
629         }
630
631         if (cbVideoLocal.isSelected() && fldVideo.getText().isEmpty()) {
632             final File dir = new File(p.getVideoDir());
633             final File file = searchFileMatchId(dir, id);
634             if (file != null) {
635                 fldVideo.setText(file.getPath());
636             }
637         }
638
639         if (cbCommentLocal.isSelected() && fldComment.getText().isEmpty()) {
640             final File dir = new File(p.getCommentDir());
641             final File file = searchFileMatchId(dir, id);
642             if (file != null) {
643                 fldComment.setText(file.getPath());
644             }
645         }
646
647     }//GEN-LAST:event_idFieldFocusLost
648     // Variables declaration - do not modify//GEN-BEGIN:variables
649     private final JTable tblDisplay;
650     // ボタン領域
651     private final JButton btnStart = new JButton("開始");
652     private final JButton btnStop = new JButton("停止");
653     private final JButton btnDeselect = new JButton("選択解除");
654     // 入力領域
655     private final JTabbedPane tbpInput = new JTabbedPane(JTabbedPane.BOTTOM);
656     // 入力領域 - メイン
657     private final IdComboBox fldId;
658     private final JCheckBox cbBackLogReduce = new JCheckBox("少コメ");
659     private final JCheckBox cbBackLog = new JCheckBox("過去ログ");
660     private final JTextField fldBackLog = new JTextField();
661     private final JCheckBox cbVideoLocal;
662     private final JTextField fldVideo;
663     private final JCheckBox cbCommentLocal;
664     private final JTextField fldComment;
665     private final JCheckBox cbOutputEnable;
666     private final JTextField fldOutput;
667     // 入力領域 - ffmpeg
668     private final FfmpegParamPanel pnlInputFfmpeg = new FfmpegParamPanel();
669     // 適用
670     private final JTextField fldInputMessage = new JTextField();
671     private final JButton btnApply = new JButton("適用");
672     // End of variables declaration//GEN-END:variables
673
674     private void initInputPanel() {
675         initMainTab();
676         initFfmpegTab();
677         tbpInput.setSelectedIndex(0);
678         fldId.requestFocus();
679     }
680
681     private void initMainTab() {
682         final Config p = Config.INSTANCE;
683
684         fldId.setText("");
685         fldBackLog.setEnabled(false);
686         cbBackLog.setEnabled(true);
687
688         final boolean movieLocal = p.getVideoUseLocal();
689         cbVideoLocal.setSelected(movieLocal);
690         if (!movieLocal) {
691             fldVideo.setText(p.getVideoFileNamePattern());
692         }
693
694         final boolean commentLocal = p.getCommentUseLocal();
695         cbCommentLocal.setSelected(commentLocal);
696         if (!commentLocal) {
697             fldComment.setText(p.getCommentFileNamePattern());
698         }
699
700         final boolean convert = p.getOutputEnable();
701         cbOutputEnable.setSelected(convert);
702         fldOutput.setEnabled(convert);
703         fldOutput.setText(p.getOutputFileNamePattern());
704     }
705
706     private void initFfmpegTab() {
707         pnlInputFfmpeg.init(Config.INSTANCE);
708     }
709
710     private JMenuBar initMenuBar() {
711         final JMenuBar menuBar = new JMenuBar();
712
713         final JMenu mnFile = new JMenu("ファイル(F)");
714         menuBar.add(mnFile);
715
716         final JMenuItem itExit = new JMenuItem("終了(X)", KeyEvent.VK_X);
717         itExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
718         itExit.addActionListener(new ActionListener() {
719
720             @Override
721             public void actionPerformed(ActionEvent e) {
722                 throw new UnsupportedOperationException("Not supported yet.");
723             }
724         });
725         mnFile.add(itExit);
726
727         final JMenu mnTool = new JMenu("ツール(T)");
728         menuBar.add(mnTool);
729
730         final JMenuItem itOption = new JMenuItem("オプション(O)...", KeyEvent.VK_O);
731         // TODO ショートカットキー
732         itOption.addActionListener(new ActionListener() {
733
734             @Override
735             public void actionPerformed(ActionEvent e) {
736                 final yukihane.inqubus.gui.ConfigDialog dlg = new yukihane.inqubus.gui.ConfigDialog(MainFrame.this);
737                 dlg.setLocationRelativeTo(MainFrame.this);
738                 dlg.setModal(true);
739                 dlg.setVisible(true);
740             }
741         });
742         mnTool.add(itOption);
743
744         final JMenu mnHelp = new JMenu("ヘルプ(H)");
745         menuBar.add(mnHelp);
746
747         final JMenuItem itAbout = new JMenuItem("このソフトウェアについて(A)...", KeyEvent.VK_A);
748         itAbout.addActionListener(new ActionListener() {
749
750             @Override
751             public void actionPerformed(ActionEvent e) {
752                 MainFrame_AboutBox dlg = new MainFrame_AboutBox(MainFrame.this);
753                 dlg.pack();
754                 dlg.setLocationRelativeTo(MainFrame.this);
755                 dlg.setModal(true);
756                 dlg.setVisible(true);
757             }
758         });
759         mnHelp.add(itAbout);
760
761         return menuBar;
762     }
763
764     private class DownloadProgressListener implements WorkerListener<DownloadResult, DownloadProgress> {
765
766         @Override
767         public void process(DownloadProgress progress) {
768             throw new UnsupportedOperationException("Not supported yet.");
769         }
770
771         @Override
772         public void cancelled() {
773             throw new UnsupportedOperationException("Not supported yet.");
774         }
775
776         @Override
777         public void done(DownloadResult result) {
778             throw new UnsupportedOperationException("Not supported yet.");
779         }
780
781         @Override
782         public void error(Throwable th) {
783             throw new UnsupportedOperationException("Not supported yet.");
784         }
785     }
786
787     private class ConvertProgressListener implements WorkerListener<ConvertResult, ConvertProgress> {
788
789         @Override
790         public void process(ConvertProgress progress) {
791             throw new UnsupportedOperationException("Not supported yet.");
792         }
793
794         @Override
795         public void cancelled() {
796             throw new UnsupportedOperationException("Not supported yet.");
797         }
798
799         @Override
800         public void done(ConvertResult result) {
801             throw new UnsupportedOperationException("Not supported yet.");
802         }
803
804         @Override
805         public void error(Throwable th) {
806             throw new UnsupportedOperationException("Not supported yet.");
807         }
808     }
809
810
811
812     private class DownloadListTransferHandler extends TransferHandler {
813
814         private static final long serialVersionUID = 1L;
815         private final Pattern movieIdPattern = Pattern.compile("(\\w\\w\\d+)");
816
817         @Override
818         public boolean canImport(TransferHandler.TransferSupport support) {
819             Transferable transferable = support.getTransferable();
820             if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
821                     || transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
822                 return true;
823             }
824             return false;
825         }
826
827         @Override
828         public boolean importData(TransferHandler.TransferSupport support) {
829 //            try {
830 //                Transferable transferable = support.getTransferable();
831 //                if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
832 //                    @SuppressWarnings("unchecked")
833 //                    final List<File> data = (List<File>) transferable.getTransferData(DataFlavor.javaFileListFlavor);
834 //                    Collection<Target> targets = Target.from(data);
835 //                    targetModel.addTarget(targets);
836 //                } else if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
837 //                    String data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
838 //                    Matcher matcher = movieIdPattern.matcher(data);
839 //                    if (matcher.find()) {
840 //                        String movieId = matcher.group(1);
841 //                        Target target = Target.fromId(movieId);
842 //                        targetModel.addTarget(target);
843 //                    } else {
844 //                        return false;
845 //                    }
846 //
847 //                }
848 //                return false;
849 //            } catch (Exception e) {
850 //                logger.log(Level.SEVERE, null, e);
851 //                return false;
852 //            }
853             // TODO 上記実装見直し(Locationは削除された)
854             return false;
855         }
856     }
857
858     private class TableTransferHandler extends DownloadListTransferHandler {
859
860         private static final long serialVersionUID = 1L;
861
862         @Override
863         public boolean canImport(TransferHandler.TransferSupport support) {
864             return super.canImport(support);
865         }
866
867         @Override
868         public boolean importData(TransferHandler.TransferSupport support) {
869             return super.importData(support);
870         }
871     }
872
873     private class MainFrameWindowListener extends WindowAdapter {
874         @Override
875         public void windowClosing(WindowEvent e) {
876             final Config p = Config.INSTANCE;
877
878             final Dimension size = getSize();
879             p.setSystemWindowWidth(size.width);
880             p.setSystemWindowHeight(size.height);
881
882             final Point pos = getLocation();
883             p.setSystemWindowPosX(pos.x);
884             p.setSystemWindowPosY(pos.y);
885
886             p.setSystemColumnId(tblDisplay.getColumnModel().getColumn(0).getWidth());
887             p.setSystemColumnVideo(tblDisplay.getColumnModel().getColumn(1).getWidth());
888             p.setSystemColumnComment(tblDisplay.getColumnModel().getColumn(2).getWidth());
889             p.setSystemColumnConvert(tblDisplay.getColumnModel().getColumn(3).getWidth());
890             p.setSystemColumnStatus(tblDisplay.getColumnModel().getColumn(4).getWidth());
891             try {
892                 p.save();
893             } catch (ConfigurationException ex) {
894                 logger.log(Level.SEVERE, "コンフィグ保存失敗", ex);
895             }
896         }
897     }
898
899     /*
900      * ここからDownloadProfile作成用クラスの定義
901      */
902
903     private class InqubusDownloadProfile implements DownloadProfile {
904
905         private final LoginProfile loginProfile;
906         private final ProxyProfile proxyProfile;
907         private final VideoProfile videoProfile;
908         private final CommentProfile commentProfile;
909         private final GeneralProfile generalProfile;
910
911         private InqubusDownloadProfile() {
912             this.loginProfile = new InqubusLoginProfile();
913             this.proxyProfile = new InqubusProxyProfile();
914             this.videoProfile = new InqubusVideoProfile();
915             this.commentProfile = new InqubusCommentProfile();
916             this.generalProfile = new InqubusGeneralProfile();
917         }
918
919         @Override
920         public LoginProfile getLoginInfo() {
921             return this.loginProfile;
922         }
923
924         @Override
925         public ProxyProfile getProxyProfile() {
926             return this.proxyProfile;
927         }
928
929         @Override
930         public VideoProfile getVideoProfile() {
931             return this.videoProfile;
932         }
933
934         @Override
935         public CommentProfile getCommentProfile() {
936             return this.commentProfile;
937         }
938
939         @Override
940         public GeneralProfile getGeneralProfile() {
941             return this.generalProfile;
942         }
943
944         @Override
945         public String toString(){
946             return ToStringBuilder.reflectionToString(this);
947         }
948     }
949
950     private class InqubusLoginProfile implements LoginProfile {
951         private final String mail;
952         private final String password;
953
954         private InqubusLoginProfile(){
955             final Config p = Config.INSTANCE;
956             this.mail = p.getId();
957             this.password = p.getPassword();
958         }
959
960         @Override
961         public String getMail() {
962             return this.mail;
963         }
964
965         @Override
966         public String getPassword() {
967             return this.password;
968         }
969
970         @Override
971         public String toString(){
972             return ToStringBuilder.reflectionToString(this);
973         }
974     }
975
976     private class InqubusProxyProfile implements ProxyProfile {
977         private final boolean use;
978         private final String host;
979         private final int port;
980
981         private InqubusProxyProfile(){
982             final Config p = Config.INSTANCE;
983             this.use = p.getProxyUse();
984             this.host = p.getProxyHost();
985             final String pp = p.getProxyPort();
986             this.port = StringUtils.isBlank(pp) ? -1 : Integer.parseInt(pp);
987         }
988
989         @Override
990         public boolean use() {
991             return this.use;
992         }
993
994         @Override
995         public String getHost() {
996             return this.host;
997         }
998
999         @Override
1000         public int getPort() {
1001             return this.port;
1002         }
1003
1004         @Override
1005         public String toString(){
1006             return ToStringBuilder.reflectionToString(this);
1007         }
1008     }
1009
1010     private class InqubusVideoProfile implements VideoProfile {
1011         private final boolean download;
1012         private final File dir;
1013         private final String fileName;
1014         private final File localFile;
1015
1016         private InqubusVideoProfile(){
1017             final Config p = Config.INSTANCE;
1018             this.download = !cbVideoLocal.isSelected();
1019             if (this.download) {
1020                 this.dir = new File(p.getVideoDir());
1021                 this.fileName = fldVideo.getText();
1022                 this.localFile = null;
1023             } else {
1024                 this.dir = null;
1025                 this.fileName = null;
1026                 this.localFile = new File(fldVideo.getText());
1027             }
1028         }
1029
1030         @Override
1031         public boolean isDownload() {
1032             return this.download;
1033         }
1034
1035         @Override
1036         public File getDir() {
1037             return this.dir;
1038         }
1039
1040         @Override
1041         public String getFileName() {
1042             return this.fileName;
1043         }
1044
1045         @Override
1046         public File getLocalFile() {
1047             return this.localFile;
1048         }
1049
1050         @Override
1051         public String toString(){
1052             return ToStringBuilder.reflectionToString(this);
1053         }
1054     }
1055
1056     private class InqubusCommentProfile implements CommentProfile {
1057         private final boolean download;
1058         private final File dir;
1059         private final String fileName;
1060         private final File localFile;
1061         private final int lengthRelatedCommentSize;
1062         private final boolean disablePerMinComment;
1063         private final int perMinCommentSize;
1064         private final long backLogPoint;
1065
1066         private InqubusCommentProfile() {
1067             final Config p = Config.INSTANCE;
1068             this.download = !cbCommentLocal.isSelected();
1069             if (this.download) {
1070                 this.dir = new File(p.getCommentDir());
1071                 this.fileName = fldComment.getText();
1072                 this.localFile = null;
1073             } else {
1074                 this.dir = null;
1075                 this.fileName = null;
1076                 this.localFile = new File(fldComment.getText());
1077             }
1078
1079             if(cbBackLog.isSelected()) {
1080                 try {
1081                     this.backLogPoint = WayBackTimeParser.parse(fldBackLog.getText());
1082                 } catch (IOException ex) {
1083                     throw new IllegalArgumentException("過去ログ時刻指定が誤っています。", ex);
1084                 }
1085             } else {
1086                 this.backLogPoint = -1L;
1087             }
1088
1089             this.disablePerMinComment = cbBackLogReduce.isSelected();
1090             this.lengthRelatedCommentSize
1091                     = (p.getCommentSizeAutosize()) ? -1 : Integer.parseInt(p.getCommentSizeManual());
1092             this.perMinCommentSize
1093                     = (p.getCommentMinSizeAutosize()) ? -1 : Integer.parseInt(p.getCommentMinSizeManual());
1094         }
1095
1096         @Override
1097         public boolean isDownload() {
1098             return this.download;
1099         }
1100
1101         @Override
1102         public File getDir() {
1103             return this.dir;
1104         }
1105
1106         @Override
1107         public String getFileName() {
1108             return this.fileName;
1109         }
1110
1111         @Override
1112         public File getLocalFile() {
1113             return this.localFile;
1114         }
1115
1116         @Override
1117         public int getLengthRelatedCommentSize() {
1118             return this.lengthRelatedCommentSize;
1119         }
1120
1121         @Override
1122         public boolean isDisablePerMinComment() {
1123             return this.disablePerMinComment;
1124         }
1125
1126         @Override
1127         public int getPerMinCommentSize() {
1128             return this.perMinCommentSize;
1129         }
1130
1131         @Override
1132         public long getBackLogPoint() {
1133             return this.backLogPoint;
1134         }
1135
1136         @Override
1137         public String toString(){
1138             return ToStringBuilder.reflectionToString(this);
1139         }
1140     }
1141
1142     private class InqubusGeneralProfile implements GeneralProfile {
1143         private final String replaceFrom;
1144         private final String replaceTo;
1145         private InqubusGeneralProfile() {
1146             final Config p = Config.INSTANCE;
1147             this.replaceFrom = p.getReplaceFrom();
1148             this.replaceTo = p.getReplaceTo();
1149         }
1150
1151         @Override
1152         public String getReplaceFrom() {
1153             return this.replaceFrom;
1154         }
1155
1156         @Override
1157         public String getReplaceTo() {
1158             return this.replaceTo;
1159         }
1160
1161         @Override
1162         public String toString(){
1163             return ToStringBuilder.reflectionToString(this);
1164         }
1165     }
1166
1167     /*
1168      * ここからConvertProfile作成用クラスの定義
1169      */
1170     private class InqubusConvertProfile implements ConvertProfile {
1171         private final OutputProfile outputProfile;
1172         private final GeneralProfile generalProfile;
1173         private final FfmpegProfile ffmpegProfile;
1174         private final boolean convert;
1175         private final File ffmpeg;
1176         private final boolean vhookDisabled;
1177         private final boolean commentOverlay;
1178         private final File vhook;
1179         private final File tmpDir;
1180         private final File font;
1181         private final int fontIndex;
1182         private final boolean commentOpaque;
1183         private final boolean disableFontSizeArrange;
1184         private final int shadowIndex;
1185         private final boolean showConvrting;
1186         private final int maxNumOfComment;
1187         private final HideCondition ngSetting;
1188
1189         private InqubusConvertProfile() throws IOException {
1190             final Config p = Config.INSTANCE;
1191             this.outputProfile = new InqubusOutputProfile();
1192             this.generalProfile = new InqubusGeneralProfile();
1193             this.ffmpegProfile = new InqubusFfmpegProfile();
1194             this.convert = cbOutputEnable.isSelected();
1195             this.ffmpeg = new File(p.getFfmpegPath());
1196             // TODO コンフィグに設定なし
1197             this.vhookDisabled = false;
1198             this.commentOverlay = p.getOutputCommentOverlay();
1199             this.vhook = new File(p.getFfmpegDllPath());
1200             this.tmpDir = new File(p.getSystemTempDir());
1201             this.font = new File(p.getFontPath());
1202             this.fontIndex = Integer.parseInt(p.getFontIndex());
1203             this.commentOpaque = p.getCommentOpaque();
1204             this.disableFontSizeArrange = p.getFontSizeArrangeDisable();
1205             this.shadowIndex = p.getFontShadow();
1206             // TODO コンフィグに設定なし
1207             this.showConvrting = true;
1208             this.maxNumOfComment = (p.getCommentDisplaySizeDefault()) ? -1 : Integer.parseInt(p.
1209                     getCommentDisplaySizeManual());
1210             this.ngSetting = new InqubusHideCondition();
1211         }
1212
1213         @Override
1214         public OutputProfile getOutputProfile() {
1215             return this.outputProfile;
1216         }
1217
1218         @Override
1219         public GeneralProfile getGeneralProfile() {
1220             return this.generalProfile;
1221         }
1222
1223         @Override
1224         public FfmpegProfile getFfmpegOption() {
1225             return this.ffmpegProfile;
1226         }
1227
1228         @Override
1229         public boolean isConvert() {
1230             return this.convert;
1231         }
1232
1233         @Override
1234         public File getFfmpeg() {
1235             return this.ffmpeg;
1236         }
1237
1238         @Override
1239         public boolean isVhookDisabled() {
1240             return this.vhookDisabled;
1241         }
1242
1243         @Override
1244         public boolean isCommentOverlay() {
1245             return this.commentOverlay;
1246         }
1247
1248         @Override
1249         public File getVhook() {
1250             return this.vhook;
1251         }
1252
1253         @Override
1254         public File getTempDir() {
1255             return this.tmpDir;
1256         }
1257
1258         @Override
1259         public File getFont() {
1260             return this.font;
1261         }
1262
1263         @Override
1264         public int getFontIndex() {
1265             return this.fontIndex;
1266         }
1267
1268         @Override
1269         public boolean isCommentOpaque() {
1270             return this.commentOpaque;
1271         }
1272
1273         @Override
1274         public boolean isDisableFontSizeArrange() {
1275             return this.disableFontSizeArrange;
1276         }
1277
1278         @Override
1279         public int getShadowIndex() {
1280             return this.shadowIndex;
1281         }
1282
1283         @Override
1284         public boolean isShowConverting() {
1285             return this.showConvrting;
1286         }
1287
1288         @Override
1289         public int getMaxNumOfComment() {
1290             return this.maxNumOfComment;
1291         }
1292
1293         @Override
1294         public HideCondition getNgSetting() {
1295             return this.ngSetting;
1296         }
1297
1298         @Override
1299         public String toString(){
1300             return ToStringBuilder.reflectionToString(this);
1301         }
1302     }
1303
1304     private class InqubusOutputProfile implements OutputProfile {
1305         private final File dir;
1306         private final String fileName;
1307         private final String videoId;
1308         private final String title;
1309
1310
1311         private InqubusOutputProfile(){
1312             final Config p = Config.INSTANCE;
1313             this.dir = new File(p.getOutputDir());
1314             this.fileName = fldOutput.getText();
1315             // TODO この時点でのID/Titleはどうするか…
1316             this.videoId = "";
1317             this.title = "";
1318         }
1319
1320         @Override
1321         public File getDir() {
1322             return this.dir;
1323         }
1324
1325         @Override
1326         public String getFileName() {
1327             return this.fileName;
1328         }
1329
1330         @Override
1331         public String getVideoId() {
1332             return this.videoId;
1333         }
1334
1335         @Override
1336         public String getTitile() {
1337             return this.title;
1338         }
1339
1340         @Override
1341         public String toString(){
1342             return ToStringBuilder.reflectionToString(this);
1343         }
1344     }
1345
1346     private class InqubusFfmpegProfile implements FfmpegProfile {
1347         private final String extOption;
1348         private final String inOption;
1349         private final String mainOption;
1350         private final String outOption;
1351         private final String avOption;
1352         private final boolean resize;
1353         private final int resizeWidth;
1354         private final int resizeHeight;
1355         private final boolean adjustRatio;
1356
1357         private InqubusFfmpegProfile() throws IOException {
1358             final File file = pnlInputFfmpeg.mdlFfmpegOption.getSelectedFile();
1359             if (file != null) {
1360                 final FfmpegOption ffop = FfmpegOption.load(file);
1361                 this.extOption = ffop.getExtOption();
1362                 this.inOption = ffop.getInOption();
1363                 this.mainOption = ffop.getMainOption();
1364                 this.outOption = ffop.getMainOption();
1365                 this.avOption = ffop.getAvfilterOption();
1366                 this.resize = ffop.isResize();
1367                 this.resizeWidth = ffop.getResizeWidth();
1368                 this.resizeHeight = ffop.getResizeHeight();
1369                 this.adjustRatio = ffop.isAdjustRatio();
1370             } else {
1371                 this.extOption = pnlInputFfmpeg.fldFfmpegOptionExtension.getText();
1372                 this.inOption = pnlInputFfmpeg.fldFfmpegOptionIn.getText();
1373                 this.mainOption = pnlInputFfmpeg.fldFfmpegOptionMain.getText();
1374                 this.outOption = pnlInputFfmpeg.fldFfmpegOptionOut.getText();
1375                 this.avOption = pnlInputFfmpeg.fldFfmpegOptionAv.getText();
1376                 this.resize = pnlInputFfmpeg.cbFfmpegOptionResize.isSelected();
1377                 this.resizeWidth = Integer.parseInt(pnlInputFfmpeg.fldFfmpegOptionResizeWidth.getText());
1378                 this.resizeHeight = Integer.parseInt(pnlInputFfmpeg.fldFfmpegOptionResizeHeight.getText());
1379                 this.adjustRatio = pnlInputFfmpeg.cbFfmpegOptionKeepAspect.isSelected();
1380             }
1381         }
1382
1383         @Override
1384         public String getExtOption() {
1385             return this.extOption;
1386         }
1387
1388         @Override
1389         public String getInOption() {
1390             return this.inOption;
1391         }
1392
1393         @Override
1394         public String getMainOption() {
1395             return this.mainOption;
1396         }
1397
1398         @Override
1399         public String getOutOption() {
1400             return this.outOption;
1401         }
1402
1403         @Override
1404         public String getAvfilterOption() {
1405             return this.avOption;
1406         }
1407
1408         @Override
1409         public boolean isResize() {
1410             return this.resize;
1411         }
1412
1413         @Override
1414         public int getResizeWidth() {
1415             return this.resizeWidth;
1416         }
1417
1418         @Override
1419         public int getResizeHeight() {
1420             return this.resizeHeight;
1421         }
1422
1423         @Override
1424         public boolean isAdjustRatio() {
1425             return this.adjustRatio;
1426         }
1427
1428         @Override
1429         public String toString(){
1430             return ToStringBuilder.reflectionToString(this);
1431         }
1432     }
1433
1434     private class InqubusHideCondition implements ConvertProfile.HideCondition{
1435
1436         @Override
1437         public String getWord() {
1438             // TODO
1439             return "";
1440         }
1441
1442         @Override
1443         public String getId() {
1444             // TODO
1445             return "";
1446         }
1447
1448         @Override
1449         public String toString(){
1450             return ToStringBuilder.reflectionToString(this);
1451         }
1452     }
1453 }