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.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.io.File;
19 import java.io.FilenameFilter;
20 import java.net.URL;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 import javax.swing.BorderFactory;
29 import javax.swing.DropMode;
30 import javax.swing.GroupLayout;
31 import javax.swing.GroupLayout.Alignment;
32 import javax.swing.JButton;
33 import javax.swing.JCheckBox;
34 import javax.swing.JFrame;
35 import javax.swing.JLabel;
36 import javax.swing.JMenu;
37 import javax.swing.JMenuBar;
38 import javax.swing.JMenuItem;
39 import javax.swing.JPanel;
40 import javax.swing.JScrollPane;
41 import javax.swing.JTable;
42 import javax.swing.JTextField;
43 import javax.swing.KeyStroke;
44 import javax.swing.LayoutStyle.ComponentPlacement;
45 import javax.swing.TransferHandler;
46 import javax.swing.WindowConstants;
47 import org.apache.commons.lang.StringUtils;
48 import saccubus.MainFrame_AboutBox;
49 import saccubus.worker.Download;
50 import saccubus.worker.profile.CommentProfile;
51 import saccubus.worker.profile.DownloadProfile;
52 import saccubus.worker.profile.GeneralProfile;
53 import saccubus.worker.profile.LoginProfile;
54 import saccubus.worker.profile.ProxyProfile;
55 import saccubus.worker.profile.VideoProfile;
56 import yukihane.Util;
57 import yukihane.inqubus.Config;
58 import yukihane.inqubus.model.Target;
59 import yukihane.inqubus.model.TargetsTableModel;
60
61 /**
62  *
63  * @author yuki
64  */
65 public class MainFrame extends JFrame {
66
67     private static final long serialVersionUID = 1L;
68     private static final Logger logger = Logger.getLogger(MainFrame.class.getName());
69     private static final String ID_FIELD_TOOLTIP = "動画のIDまたはURLを入力します。";
70     private static final String FILE_LOCALBUTTON_TOOLTIP
71             = "ダウンロードする場合はチェックを外します。ローカルファイルを使用する場合はチェックを入れます。";
72     private static final String FILE_INPUTFIELD_TOOLTIP
73             = "ダウンロードする場合はファイル命名規則を入力します。"
74             + "ローカルファイルを使用する場合はパスを含むファイル名を入力します。";
75     private static final String FILE_OUTPUTFIELD_TOOLTIP
76             = "ファイル命名規則入力します。";
77     private final TargetsTableModel targetModel = new TargetsTableModel();
78
79     /** Creates new form MainFrame */
80     public MainFrame() {
81         final URL url = MainFrame_AboutBox.class.getResource("icon.png");
82         final Image icon1 = Toolkit.getDefaultToolkit().createImage(url);
83         final URL url32 = MainFrame_AboutBox.class.getResource("icon32.png");
84         final Image icon2 = Toolkit.getDefaultToolkit().createImage(url32);
85         final List<Image> images = new ArrayList<Image>(2);
86         images.add(icon1);
87         images.add(icon2);
88         setIconImages(images);
89
90         final JPanel pnlMain = new JPanel();
91         final JScrollPane scrDisplay = new JScrollPane();
92         tblDisplay = new JTable();
93         final JPanel pnlButton = new JPanel();
94         btnStart = new JButton();
95         btnStop = new JButton();
96         btnDeselect = new JButton();
97         final JPanel pnlInputMain = new JPanel();
98         final JLabel lblId = new JLabel();
99         fldId = new JTextField();
100         fldId.setToolTipText(ID_FIELD_TOOLTIP);
101         final JLabel lblVideo = new JLabel();
102         cbVideoLocal = new JCheckBox();
103         cbVideoLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
104         fldVideo = new JTextField();
105         fldVideo.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
106         btnVideo = new JButton();
107         final JLabel lblComment = new JLabel();
108         cbCommentLocal = new JCheckBox();
109         cbCommentLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
110         fldComment = new JTextField();
111         fldComment.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
112         btnComment = new JButton();
113         final JLabel lblOutput = new JLabel();
114         cbOutputEnable = new JCheckBox();
115         fldOutput = new JTextField();
116         fldOutput.setToolTipText(FILE_OUTPUTFIELD_TOOLTIP);
117
118         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
119
120         btnApply.addActionListener(new ApplyActionListener());
121
122         pnlMain.setBorder(BorderFactory.createEtchedBorder());
123
124         tblDisplay.setModel(targetModel);
125         tblDisplay.setDropMode(DropMode.INSERT_ROWS);
126         scrDisplay.setViewportView(tblDisplay);
127
128         pnlButton.setBorder(BorderFactory.createEtchedBorder());
129
130         btnStart.setText("開始");
131
132         btnStop.setText("停止");
133
134         btnDeselect.setText("選択解除");
135
136         GroupLayout gl_pnlButton = new GroupLayout(pnlButton);
137         pnlButton.setLayout(gl_pnlButton);
138         gl_pnlButton.setHorizontalGroup(
139             gl_pnlButton.createParallelGroup(Alignment.LEADING)
140             .addGroup(gl_pnlButton.createSequentialGroup()
141                 .addContainerGap()
142                 .addComponent(btnStart)
143                 .addPreferredGap(ComponentPlacement.RELATED)
144                 .addComponent(btnStop)
145                 .addPreferredGap(ComponentPlacement.RELATED, 250, Short.MAX_VALUE)
146                 .addComponent(btnDeselect)
147                 .addContainerGap())
148         );
149         gl_pnlButton.setVerticalGroup(
150             gl_pnlButton.createParallelGroup(Alignment.LEADING)
151             .addGroup(gl_pnlButton.createSequentialGroup()
152                 .addContainerGap()
153                 .addGroup(gl_pnlButton.createParallelGroup(Alignment.BASELINE)
154                     .addComponent(btnStart)
155                     .addComponent(btnStop)
156                     .addComponent(btnDeselect))
157                 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
158         );
159
160         pnlInputMain.setBorder(BorderFactory.createEtchedBorder());
161
162         lblId.setText("ID");
163
164         fldId.addFocusListener(new java.awt.event.FocusAdapter() {
165
166             public void focusLost(java.awt.event.FocusEvent evt) {
167                 idFieldFocusLost(evt);
168             }
169         });
170
171         lblVideo.setText("動画");
172
173         cbVideoLocal.setText("local");
174         cbVideoLocal.addItemListener(new java.awt.event.ItemListener() {
175
176             public void itemStateChanged(java.awt.event.ItemEvent evt) {
177                 useMovieLocalCheckBoxItemStateChanged(evt);
178             }
179         });
180
181         btnVideo.setText("...");
182
183         lblComment.setText("コメント");
184
185         cbCommentLocal.setText("local");
186         cbCommentLocal.addItemListener(new java.awt.event.ItemListener() {
187
188             public void itemStateChanged(java.awt.event.ItemEvent evt) {
189                 useMovieLocalCheckBoxItemStateChanged(evt);
190             }
191         });
192
193         btnComment.setText("...");
194
195         lblOutput.setText("出力");
196
197         cbOutputEnable.setText("変換");
198         cbOutputEnable.addItemListener(new java.awt.event.ItemListener() {
199
200             public void itemStateChanged(java.awt.event.ItemEvent evt) {
201                 outputConvertCheckBoxItemStateChanged(evt);
202             }
203         });
204
205
206         GroupLayout gl_pnlInputMain = new GroupLayout(pnlInputMain);
207         pnlInputMain.setLayout(gl_pnlInputMain);
208         gl_pnlInputMain.setHorizontalGroup(
209             gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
210             .addGroup(gl_pnlInputMain.createSequentialGroup()
211                 .addContainerGap()
212                 .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
213                     .addGroup(gl_pnlInputMain.createSequentialGroup()
214                         .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
215                             .addComponent(lblComment)
216                             .addComponent(lblVideo)
217                             .addComponent(lblId)
218                             .addComponent(lblOutput))
219                         .addPreferredGap(ComponentPlacement.RELATED)
220                         .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
221                             .addGroup(gl_pnlInputMain.createSequentialGroup()
222                                 .addComponent(cbVideoLocal)
223                                 .addPreferredGap(ComponentPlacement.RELATED)
224                                 .addComponent(fldVideo, GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE)
225                                 .addPreferredGap(ComponentPlacement.RELATED)
226                                 .addComponent(btnVideo))
227                             .addGroup(gl_pnlInputMain.createSequentialGroup()
228                                 .addComponent(fldId, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
229                                 .addComponent(cbBackLog)
230                                 .addComponent(fldBackLog, GroupLayout.PREFERRED_SIZE, 150, GroupLayout.PREFERRED_SIZE)
231                                 .addComponent(cbBackLogReduce)
232                             )
233                             .addGroup(Alignment.TRAILING, gl_pnlInputMain.createSequentialGroup()
234                                 .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.TRAILING)
235                                     .addGroup(Alignment.LEADING, gl_pnlInputMain.createSequentialGroup()
236                                         .addComponent(cbOutputEnable)
237                                         .addPreferredGap(ComponentPlacement.RELATED)
238                                         .addComponent(fldOutput, GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE))
239                                     .addGroup(gl_pnlInputMain.createSequentialGroup()
240                                         .addComponent(cbCommentLocal)
241                                         .addPreferredGap(ComponentPlacement.RELATED)
242                                         .addComponent(fldComment, GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE)))
243                                 .addPreferredGap(ComponentPlacement.RELATED)
244                                 .addComponent(btnComment))))
245                     .addComponent(btnApply, Alignment.TRAILING))
246                 .addContainerGap())
247         );
248         gl_pnlInputMain.setVerticalGroup(
249             gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
250             .addGroup(gl_pnlInputMain.createSequentialGroup()
251                 .addContainerGap()
252                 .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
253                     .addComponent(fldId, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
254                     .addComponent(lblId)
255                     .addComponent(cbBackLog)
256                     .addComponent(fldBackLog)
257                     .addComponent(cbBackLogReduce)
258                 )
259                 .addPreferredGap(ComponentPlacement.RELATED)
260                 .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
261                     .addComponent(lblVideo)
262                     .addComponent(fldVideo, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
263                     .addComponent(btnVideo)
264                     .addComponent(cbVideoLocal))
265                 .addPreferredGap(ComponentPlacement.RELATED)
266                 .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
267                     .addComponent(lblComment)
268                     .addComponent(fldComment, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
269                     .addComponent(btnComment)
270                     .addComponent(cbCommentLocal))
271                 .addPreferredGap(ComponentPlacement.RELATED)
272                 .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
273                     .addComponent(lblOutput)
274                     .addComponent(fldOutput, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
275                     .addComponent(cbOutputEnable))
276                 .addPreferredGap(ComponentPlacement.UNRELATED)
277                 .addComponent(btnApply)
278                 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
279         );
280
281         GroupLayout gl_pnlMain = new GroupLayout(pnlMain);
282         pnlMain.setLayout(gl_pnlMain);
283         gl_pnlMain.setHorizontalGroup(
284             gl_pnlMain.createParallelGroup(Alignment.LEADING)
285             .addGroup(Alignment.TRAILING, gl_pnlMain.createSequentialGroup()
286                 .addContainerGap()
287                 .addGroup(gl_pnlMain.createParallelGroup(Alignment.TRAILING)
288                     .addComponent(pnlInputMain, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
289                     .addComponent(scrDisplay, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
290                     .addComponent(pnlButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
291                 .addContainerGap())
292         );
293         gl_pnlMain.setVerticalGroup(
294             gl_pnlMain.createParallelGroup(Alignment.LEADING)
295             .addGroup(Alignment.TRAILING, gl_pnlMain.createSequentialGroup()
296                 .addContainerGap()
297                 .addComponent(scrDisplay, GroupLayout.DEFAULT_SIZE, 197, Short.MAX_VALUE)
298                 .addPreferredGap(ComponentPlacement.RELATED)
299                 .addComponent(pnlButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
300                 .addPreferredGap(ComponentPlacement.RELATED)
301                 .addComponent(pnlInputMain, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
302                 .addGap(24, 24, 24))
303         );
304
305
306         JMenuBar menuBar = initMenuBar();
307         setJMenuBar(menuBar);
308
309         GroupLayout layout = new GroupLayout(getContentPane());
310         getContentPane().setLayout(layout);
311         layout.setHorizontalGroup(
312             layout.createParallelGroup(Alignment.LEADING)
313             .addComponent(pnlMain, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
314         );
315         layout.setVerticalGroup(
316             layout.createParallelGroup(Alignment.LEADING)
317             .addComponent(pnlMain, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
318         );
319
320         pack();
321         initInputPanel();
322         pnlMain.setTransferHandler(new DownloadListTransferHandler());
323         tblDisplay.setTransferHandler(new TableTransferHandler());
324     }
325
326     private class ApplyActionListener implements ActionListener {
327
328         @Override
329         public void actionPerformed(ActionEvent e) {
330             final DownloadProfile prof = new InqubusDownloadProfile();
331             final String id = Util.getVideoId(fldId.getText());
332
333             new Download(prof, id).execute();
334         }
335     }
336     /** This method is called from within the constructor to
337      * initialize the form.
338      * WARNING: Do NOT modify this code. The content of this method is
339      * always regenerated by the Form Editor.
340      */
341     @SuppressWarnings("unchecked")
342     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
343     private void initComponents() {
344     }// </editor-fold>//GEN-END:initComponents
345
346     private File searchFileMatchId(final File dir, final String id) throws UnsupportedOperationException {
347         // TODO 候補は複数返すようにして、その後の対処は呼び出しもとで行ってもらった方が良いかも
348         if (id.isEmpty()) {
349             return null;
350         }
351
352         final File[] lists = dir.listFiles(new FilenameFilter() {
353
354             final Pattern pattern = Pattern.compile(id + "\\D");
355
356             @Override
357             public boolean accept(File dir, String name) {
358                 return pattern.matcher(name).find();
359             }
360         });
361
362         if (lists.length == 1) {
363             return lists[0];
364         } else if (lists.length > 1) {
365             throw new UnsupportedOperationException();
366         } else {
367             return null;
368         }
369     }
370
371     private void useMovieLocalCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_useMovieLocalCheckBoxItemStateChanged
372         final Config p = Config.INSTANCE;
373
374         final ItemSelectable source = evt.getItemSelectable();
375
376         JButton btn;
377         JTextField field;
378         File dir;
379         if (source == cbVideoLocal) {
380             btn = btnVideo;
381             field = fldVideo;
382             dir = new File(p.getVideoDir());
383         } else {
384             btn = btnComment;
385             field = fldComment;
386             dir = new File(p.getCommentDir());
387         }
388
389         final boolean useLocal = (evt.getStateChange() == ItemEvent.SELECTED);
390         btn.setEnabled(useLocal);
391
392         String text;
393         if (useLocal) {
394             final File f = searchFileMatchId(dir, fldId.getText());
395             if (f != null) {
396                 text = f.getPath();
397             } else {
398                 text = "";
399             }
400         } else {
401             text = p.getVideoFileNamePattern();
402         }
403         field.setText(text);
404     }//GEN-LAST:event_useMovieLocalCheckBoxItemStateChanged
405
406     private void outputConvertCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_outputConvertCheckBoxItemStateChanged
407         final boolean convert = (evt.getStateChange() == ItemEvent.SELECTED);
408         fldOutput.setEnabled(convert);
409     }//GEN-LAST:event_outputConvertCheckBoxItemStateChanged
410
411     private void idFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_idFieldFocusLost
412         final Config p = Config.INSTANCE;
413         final String id = fldId.getText();
414         if (id.isEmpty()) {
415             return;
416         }
417
418         if (cbVideoLocal.isSelected() && fldVideo.getText().isEmpty()) {
419             final File dir = new File(p.getVideoDir());
420             final File file = searchFileMatchId(dir, id);
421             if (file != null) {
422                 fldVideo.setText(file.getPath());
423             }
424         }
425
426         if (cbCommentLocal.isSelected() && fldComment.getText().isEmpty()) {
427             final File dir = new File(p.getCommentDir());
428             final File file = searchFileMatchId(dir, id);
429             if (file != null) {
430                 fldComment.setText(file.getPath());
431             }
432         }
433
434     }//GEN-LAST:event_idFieldFocusLost
435     // Variables declaration - do not modify//GEN-BEGIN:variables
436     private final JTable tblDisplay;
437     // ボタン領域
438     private final JButton btnStart;
439     private final JButton btnStop;
440     private final JButton btnDeselect;
441     //入力領域 - 標準
442     private final JTextField fldId;
443     private final JCheckBox cbBackLog = new JCheckBox("過去ログ");
444     private final JTextField fldBackLog = new JTextField();
445     private final JCheckBox cbBackLogReduce = new JCheckBox("コメ数減少");
446     private final JCheckBox cbVideoLocal;
447     private final JTextField fldVideo;
448     private final JButton btnVideo;
449     private final JCheckBox cbCommentLocal;
450     private final JTextField fldComment;
451     private final JButton btnComment;
452     private final JCheckBox cbOutputEnable;
453     private final JTextField fldOutput;
454     // 適用
455     private final JButton btnApply = new JButton("適用");
456     // End of variables declaration//GEN-END:variables
457
458     private void initInputPanel() {
459         final Config p = Config.INSTANCE;
460
461         fldId.setText("");
462         fldBackLog.setEnabled(false);
463         fldBackLog.setToolTipText("YYYY/MM/DD hh:mm:ss形式、あるいは1970/01/01からの経過秒を入力します。");
464         cbBackLog.setEnabled(true);
465         cbBackLog.addItemListener(new ItemListener() {
466
467             @Override
468             public void itemStateChanged(ItemEvent e) {
469                 final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
470                 fldBackLog.setEnabled(selected);
471                 cbBackLogReduce.setEnabled(selected);
472             }
473         });
474         cbBackLogReduce.setEnabled(false);
475         cbBackLogReduce.setToolTipText("「コメントの量を減らす」場合はチェックを付けます。");
476
477         final boolean movieLocal = p.getVideoUseLocal();
478         cbVideoLocal.setSelected(movieLocal);
479         btnVideo.setEnabled(movieLocal);
480         if (!movieLocal) {
481             fldVideo.setText(p.getVideoFileNamePattern());
482         }
483
484         final boolean commentLocal = p.getCommentUseLocal();
485         cbCommentLocal.setSelected(commentLocal);
486         btnComment.setEnabled(commentLocal);
487         if (!commentLocal) {
488             fldComment.setText(p.getCommentFileNamePattern());
489         }
490
491         final boolean convert = p.getOutputEnable();
492         cbOutputEnable.setSelected(convert);
493         fldOutput.setEnabled(convert);
494         fldOutput.setText(p.getOutputFileNamePattern());
495
496     }
497
498     private JMenuBar initMenuBar() {
499         final JMenuBar menuBar = new JMenuBar();
500
501         final JMenu mnFile = new JMenu("ファイル(F)");
502         menuBar.add(mnFile);
503
504         final JMenuItem itExit = new JMenuItem("終了(X)", KeyEvent.VK_X);
505         itExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
506         itExit.addActionListener(new ActionListener() {
507
508             @Override
509             public void actionPerformed(ActionEvent e) {
510                 throw new UnsupportedOperationException("Not supported yet.");
511             }
512         });
513         mnFile.add(itExit);
514
515         final JMenu mnTool = new JMenu("ツール(T)");
516         menuBar.add(mnTool);
517
518         final JMenuItem itOption = new JMenuItem("オプション(O)...", KeyEvent.VK_O);
519         // TODO ショートカットキー
520         itOption.addActionListener(new ActionListener() {
521
522             @Override
523             public void actionPerformed(ActionEvent e) {
524                 final yukihane.inqubus.gui.ConfigDialog dlg = new yukihane.inqubus.gui.ConfigDialog(MainFrame.this);
525                 dlg.setLocationRelativeTo(MainFrame.this);
526                 dlg.setModal(true);
527                 dlg.setVisible(true);
528             }
529         });
530         mnTool.add(itOption);
531
532         final JMenu mnHelp = new JMenu("ヘルプ(H)");
533         menuBar.add(mnHelp);
534
535         final JMenuItem itAbout = new JMenuItem("このソフトウェアについて(A)...", KeyEvent.VK_A);
536         itAbout.addActionListener(new ActionListener() {
537
538             @Override
539             public void actionPerformed(ActionEvent e) {
540                 MainFrame_AboutBox dlg = new MainFrame_AboutBox(MainFrame.this);
541                 dlg.pack();
542                 dlg.setLocationRelativeTo(MainFrame.this);
543                 dlg.setModal(true);
544                 dlg.setVisible(true);
545             }
546         });
547         mnHelp.add(itAbout);
548
549         return menuBar;
550     }
551
552     private class DownloadListTransferHandler extends TransferHandler {
553
554         private static final long serialVersionUID = 1L;
555         private final Pattern movieIdPattern = Pattern.compile("(\\w\\w\\d+)");
556
557         @Override
558         public boolean canImport(TransferHandler.TransferSupport support) {
559             Transferable transferable = support.getTransferable();
560             if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
561                     || transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
562                 return true;
563             }
564             return false;
565         }
566
567         @Override
568         public boolean importData(TransferHandler.TransferSupport support) {
569             try {
570                 Transferable transferable = support.getTransferable();
571                 if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
572                     @SuppressWarnings("unchecked")
573                     final List<File> data = (List<File>) transferable.getTransferData(DataFlavor.javaFileListFlavor);
574                     Collection<Target> targets = Target.from(data);
575                     targetModel.addTarget(targets);
576                 } else if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
577                     String data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
578                     Matcher matcher = movieIdPattern.matcher(data);
579                     if (matcher.find()) {
580                         String movieId = matcher.group(1);
581                         Target target = Target.fromId(movieId);
582                         targetModel.addTarget(target);
583                     } else {
584                         return false;
585                     }
586
587                 }
588                 return false;
589             } catch (Exception e) {
590                 logger.log(Level.SEVERE, null, e);
591                 return false;
592             }
593         }
594     }
595
596     private class TableTransferHandler extends DownloadListTransferHandler {
597
598         private static final long serialVersionUID = 1L;
599
600         @Override
601         public boolean canImport(TransferHandler.TransferSupport support) {
602             return super.canImport(support);
603         }
604
605         @Override
606         public boolean importData(TransferHandler.TransferSupport support) {
607             return super.importData(support);
608         }
609     }
610
611
612     private class InqubusDownloadProfile implements DownloadProfile {
613
614         private final LoginProfile loginProfile;
615         private final ProxyProfile proxyProfile;
616         private final VideoProfile videoProfile;
617         private final CommentProfile commentProfile;
618         private final GeneralProfile generalProfile;
619
620         private InqubusDownloadProfile() {
621             this.loginProfile = new InqubusLoginProfile();
622             this.proxyProfile = new InqubusProxyProfile();
623             this.videoProfile = new InqubusVideoProfile();
624             this.commentProfile = new InqubusCommentProfile();
625             this.generalProfile = new InqubusGeneralProfile();
626         }
627
628         @Override
629         public LoginProfile getLoginInfo() {
630             return this.loginProfile;
631         }
632
633         @Override
634         public ProxyProfile getProxyProfile() {
635             return this.proxyProfile;
636         }
637
638         @Override
639         public VideoProfile getVideoProfile() {
640             return this.videoProfile;
641         }
642
643         @Override
644         public CommentProfile getCommentProfile() {
645             return this.commentProfile;
646         }
647
648         @Override
649         public GeneralProfile getGeneralProfile() {
650             return this.generalProfile;
651         }
652     }
653
654     private class InqubusLoginProfile implements LoginProfile {
655         private final String mail;
656         private final String password;
657
658         private InqubusLoginProfile(){
659             final Config p = Config.INSTANCE;
660             this.mail = p.getId();
661             this.password = p.getPassword();
662         }
663
664         @Override
665         public String getMail() {
666             return this.mail;
667         }
668
669         @Override
670         public String getPassword() {
671             return this.password;
672         }
673     }
674
675     private class InqubusProxyProfile implements ProxyProfile {
676         private final boolean use;
677         private final String host;
678         private final int port;
679
680         private InqubusProxyProfile(){
681             final Config p = Config.INSTANCE;
682             this.use = p.getProxyUse();
683             this.host = p.getProxyHost();
684             final String pp = p.getProxyPort();
685             this.port = StringUtils.isBlank(pp) ? -1 : Integer.parseInt(pp);
686         }
687
688         @Override
689         public boolean use() {
690             return this.use;
691         }
692
693         @Override
694         public String getHost() {
695             return this.host;
696         }
697
698         @Override
699         public int getPort() {
700             return this.port;
701         }
702     }
703
704     private class InqubusVideoProfile implements VideoProfile {
705         private final boolean download;
706         private final File dir;
707         private final String fileName;
708         private final File localFile;
709
710         private InqubusVideoProfile(){
711             this.download = !cbVideoLocal.isSelected();
712             if (this.download) {
713                 this.dir = new File(fldVideo.getText());
714                 // TODO ディレクトリとファイル名の入力欄を分ける
715                 this.fileName = "{id}_{title}";
716                 this.localFile = null;
717             } else {
718                 this.dir = null;
719                 this.fileName = null;
720                 this.localFile = new File(fldVideo.getText());
721             }
722         }
723
724         @Override
725         public boolean isDownload() {
726             return this.download;
727         }
728
729         @Override
730         public File getDir() {
731             return this.dir;
732         }
733
734         @Override
735         public String getFileName() {
736             return this.fileName;
737         }
738
739         @Override
740         public File getLocalFile() {
741             return this.localFile;
742         }
743     }
744
745     private class InqubusCommentProfile implements CommentProfile {
746
747         @Override
748         public int getLengthRelatedCommentSize() {
749             throw new UnsupportedOperationException("Not supported yet.");
750         }
751
752         @Override
753         public boolean isDisablePerMinComment() {
754             throw new UnsupportedOperationException("Not supported yet.");
755         }
756
757         @Override
758         public int getPerMinCommentSize() {
759             throw new UnsupportedOperationException("Not supported yet.");
760         }
761
762         @Override
763         public long getBackLogPoint() {
764             throw new UnsupportedOperationException("Not supported yet.");
765         }
766
767         @Override
768         public boolean isDownload() {
769             throw new UnsupportedOperationException("Not supported yet.");
770         }
771
772         @Override
773         public File getDir() {
774             throw new UnsupportedOperationException("Not supported yet.");
775         }
776
777         @Override
778         public String getFileName() {
779             throw new UnsupportedOperationException("Not supported yet.");
780         }
781
782         @Override
783         public File getLocalFile() {
784             throw new UnsupportedOperationException("Not supported yet.");
785         }
786
787     }
788
789     private class InqubusGeneralProfile implements GeneralProfile {
790 //        private final String replaceFrom;
791         private InqubusGeneralProfile() {
792             final Config p = Config.INSTANCE;
793             // TODO 置換文字設定コンフィグが無い
794 //            this.replaceFrom = p.get
795         }
796
797         @Override
798         public String getReplaceFrom() {
799 //            return this.replaceFrom;
800             throw new UnsupportedOperationException("Not supported yet.");
801         }
802
803         @Override
804         public String getReplaceTo() {
805             throw new UnsupportedOperationException("Not supported yet.");
806         }
807
808     }
809 }