OSDN Git Service

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