*/
package yukihane.inqubus.gui;
+import java.awt.Dimension;
import java.awt.Image;
import java.awt.ItemSelectable;
+import java.awt.Point;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.BorderFactory;
import javax.swing.DropMode;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JCheckBox;
+import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.WindowConstants;
+import javax.swing.border.BevelBorder;
+import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import saccubus.FfmpegOption;
import saccubus.MainFrame_AboutBox;
import saccubus.util.WayBackTimeParser;
-import saccubus.worker.Download;
+import saccubus.worker.impl.convert.ConvertProgress;
+import saccubus.worker.impl.download.DownloadProgress;
+import saccubus.worker.WorkerListener;
+import saccubus.worker.impl.convert.ConvertResult;
+import saccubus.worker.impl.download.DownloadResult;
import saccubus.worker.profile.CommentProfile;
+import saccubus.worker.profile.ConvertProfile;
import saccubus.worker.profile.DownloadProfile;
+import saccubus.worker.profile.FfmpegProfile;
import saccubus.worker.profile.GeneralProfile;
import saccubus.worker.profile.LoginProfile;
+import saccubus.worker.profile.OutputProfile;
import saccubus.worker.profile.ProxyProfile;
import saccubus.worker.profile.VideoProfile;
import yukihane.Util;
import yukihane.inqubus.Config;
+import yukihane.inqubus.filewatch.FileWatch;
+import yukihane.inqubus.manager.RequestProcess;
+import yukihane.inqubus.manager.TaskKind;
+import yukihane.inqubus.manager.TaskManage;
+import yukihane.inqubus.manager.TaskManageListener;
+import yukihane.inqubus.manager.TaskStatus;
import yukihane.inqubus.model.Target;
import yukihane.inqubus.model.TargetsTableModel;
private static final Logger logger = Logger.getLogger(MainFrame.class.getName());
private static final String ID_FIELD_TOOLTIP = "動画のIDまたはURLを入力します。";
private static final String FILE_LOCALBUTTON_TOOLTIP
- = "ダウンロードする場合はチェックを外します。ローカルファイルを使用する場合はチェックを入れます。";
+ = "<html>ダウンロードする場合はチェックを外します。<br/>ローカルファイルを使用する場合はチェックを入れます。</html>";
private static final String FILE_INPUTFIELD_TOOLTIP
- = "ダウンロードする場合はファイル命名規則を入力します。"
- + "ローカルファイルを使用する場合はパスを含むファイル名を入力します。";
+ = "<html>ダウンロードする場合はファイル命名規則を入力します。<br/>"
+ + "ローカルファイルを使用する場合はパスを含むファイル名を入力します。</html>";
private static final String FILE_OUTPUTFIELD_TOOLTIP
= "ファイル命名規則入力します。";
private final TargetsTableModel targetModel = new TargetsTableModel();
+ private final TaskManage taskManager;
+ private final Thread videoFileWatcherThread;
+ private final FileWatch videoFileWatcher;
/** Creates new form MainFrame */
public MainFrame() {
+ super();
+ addWindowListener(new MainFrameWindowListener());
+
+ final Config p = Config.INSTANCE;
+
+ // ワーカスレッド生成
+ final int thDownload = p.getSystemDownloadThread();
+ final int secDownload = p.getSystemDownloadWait();
+ final int thConvert = p.getSystemConvertThread();
+ taskManager = new TaskManage(thDownload, secDownload, thConvert, new GuiTaskManageListener());
+
+ // TODO ディレクトリ監視スレッド生成
+ final List<String> videoSearchDirs = p.getSearchVideoDirs();
+ videoSearchDirs.add(p.getVideoDir());
+ final FileSystem fs = FileSystems.getDefault();
+ final Set<Path> videoPaths = new HashSet<>(videoSearchDirs.size());
+ for (String s : videoSearchDirs) {
+ videoPaths.add(fs.getPath(s));
+ }
+ videoFileWatcher = new FileWatch(videoPaths);
+ this.videoFileWatcherThread = new Thread(videoFileWatcher);
+ this.videoFileWatcherThread.setDaemon(true);
+
final URL url = MainFrame_AboutBox.class.getResource("icon.png");
final Image icon1 = Toolkit.getDefaultToolkit().createImage(url);
final URL url32 = MainFrame_AboutBox.class.getResource("icon32.png");
final Image icon2 = Toolkit.getDefaultToolkit().createImage(url32);
- final List<Image> images = new ArrayList<Image>(2);
+ final List<Image> images = new ArrayList<>(2);
images.add(icon1);
images.add(icon2);
setIconImages(images);
final JPanel pnlMain = new JPanel();
final JScrollPane scrDisplay = new JScrollPane();
- tblDisplay = new JTable();
+ tblDisplay = new JTable(targetModel, new TargetsColumnModel());
+ tblDisplay.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
final JPanel pnlButton = new JPanel();
- btnStart = new JButton();
- btnStop = new JButton();
- btnDeselect = new JButton();
final JPanel pnlInputMain = new JPanel();
final JLabel lblId = new JLabel();
- fldId = new JTextField();
- fldId.setToolTipText(ID_FIELD_TOOLTIP);
final JLabel lblVideo = new JLabel();
cbVideoLocal = new JCheckBox();
cbVideoLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
fldVideo = new JTextField();
fldVideo.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
- btnVideo = new JButton();
+ btnVideo.addActionListener(
+ new FileChooseAction(MainFrame.this, JFileChooser.FILES_ONLY, fldVideo));
final JLabel lblComment = new JLabel();
+
+ fldBackLog.setToolTipText("YYYY/MM/DD hh:mm:ss形式、あるいは1970/01/01からの経過秒を入力します。");
+ cbBackLog.addItemListener(new ItemListener() {
+
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
+ fldBackLog.setEnabled(selected);
+ }
+ });
+ cbBackLog.addPropertyChangeListener("enabled", new PropertyChangeListener() {
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ final boolean enabled = ((Boolean) evt.getNewValue()).booleanValue();
+ final boolean fldEnabled = enabled ? cbBackLog.isSelected() : false;
+ fldBackLog.setEnabled(fldEnabled);
+ }
+ });
+ cbBackLogReduce.setToolTipText("「コメントの量を減らす」場合はチェックを付けます。");
+
cbCommentLocal = new JCheckBox();
cbCommentLocal.setToolTipText(FILE_LOCALBUTTON_TOOLTIP);
cbCommentLocal.addItemListener(new ItemListener() {
final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
cbBackLogReduce.setEnabled(!selected);
cbBackLog.setEnabled(!selected);
- if(selected) {
- cbBackLog.setSelected(false);
- }
}
});
fldComment = new JTextField();
fldComment.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
- btnComment = new JButton();
+ btnComment.addActionListener(
+ new FileChooseAction(MainFrame.this, JFileChooser.FILES_ONLY, fldComment));
final JLabel lblOutput = new JLabel();
cbOutputEnable = new JCheckBox();
fldOutput = new JTextField();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
- btnApply.addActionListener(new ApplyActionListener());
+ btnStop.addActionListener(new StopActionListener());
+ final ApplyActionListener applyListener = new ApplyActionListener();
+ btnApply.addActionListener(applyListener);
+ btnClear.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ initInputPanel();
+ }
+ });
pnlMain.setBorder(BorderFactory.createEtchedBorder());
- tblDisplay.setModel(targetModel);
tblDisplay.setDropMode(DropMode.INSERT_ROWS);
scrDisplay.setViewportView(tblDisplay);
pnlButton.setBorder(BorderFactory.createEtchedBorder());
- btnStart.setText("開始");
-
- btnStop.setText("停止");
-
- btnDeselect.setText("選択解除");
-
GroupLayout gl_pnlButton = new GroupLayout(pnlButton);
pnlButton.setLayout(gl_pnlButton);
gl_pnlButton.setHorizontalGroup(
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
- pnlInputMain.setBorder(BorderFactory.createEtchedBorder());
-
lblId.setText("ID");
+
+ fldId = new IdComboBox(videoFileWatcher);
+ fldId.setToolTipText(ID_FIELD_TOOLTIP);
+ fldId.getEditorComponent().addActionListener(applyListener);
fldId.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
}
});
- btnVideo.setText("...");
-
lblComment.setText("コメント");
cbCommentLocal.setText("local");
}
});
- btnComment.setText("...");
-
lblOutput.setText("出力");
cbOutputEnable.setText("変換");
});
- GroupLayout gl_pnlInputMain = new GroupLayout(pnlInputMain);
- pnlInputMain.setLayout(gl_pnlInputMain);
- gl_pnlInputMain.setHorizontalGroup(
- gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
- .addGroup(gl_pnlInputMain.createSequentialGroup()
+ final GroupLayout glInputMain = new GroupLayout(pnlInputMain);
+ pnlInputMain.setLayout(glInputMain);
+ glInputMain.setHorizontalGroup(
+ glInputMain.createParallelGroup(Alignment.LEADING)
+ .addGroup(glInputMain.createSequentialGroup()
.addContainerGap()
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
- .addGroup(gl_pnlInputMain.createSequentialGroup()
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
- .addComponent(lblComment)
- .addComponent(lblVideo)
- .addComponent(lblId)
- .addComponent(lblOutput))
- .addPreferredGap(ComponentPlacement.RELATED)
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
- .addGroup(gl_pnlInputMain.createSequentialGroup()
- .addComponent(cbVideoLocal)
- .addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(fldVideo, GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE)
- .addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(btnVideo))
- .addGroup(gl_pnlInputMain.createSequentialGroup()
- .addComponent(fldId, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(ComponentPlacement.UNRELATED)
- .addComponent(cbBackLogReduce)
- .addComponent(cbBackLog)
- .addComponent(fldBackLog, GroupLayout.PREFERRED_SIZE, 150, GroupLayout.PREFERRED_SIZE)
- )
- .addGroup(Alignment.TRAILING, gl_pnlInputMain.createSequentialGroup()
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.TRAILING)
- .addGroup(Alignment.LEADING, gl_pnlInputMain.createSequentialGroup()
- .addComponent(cbOutputEnable)
- .addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(fldOutput, GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE))
- .addGroup(gl_pnlInputMain.createSequentialGroup()
- .addComponent(cbCommentLocal)
- .addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(fldComment, GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE)))
- .addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(btnComment))))
- .addComponent(btnApply, Alignment.TRAILING))
- .addContainerGap())
+ .addComponent(lblId)
+ .addPreferredGap(ComponentPlacement.RELATED)
+ .addComponent(fldId, GroupLayout.PREFERRED_SIZE, 100, Short.MAX_VALUE)
+ .addPreferredGap(ComponentPlacement.UNRELATED)
+ .addComponent(cbBackLogReduce)
+ .addPreferredGap(ComponentPlacement.UNRELATED)
+ .addComponent(cbBackLog)
+ .addPreferredGap(ComponentPlacement.RELATED)
+ .addComponent(fldBackLog, GroupLayout.PREFERRED_SIZE, 150, GroupLayout.PREFERRED_SIZE)
+ .addContainerGap()
+ )
+ .addGroup(glInputMain.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
+ .addComponent(lblVideo)
+ .addComponent(lblComment)
+ .addComponent(lblOutput)
+ )
+ .addPreferredGap(ComponentPlacement.RELATED)
+ .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
+ .addComponent(cbVideoLocal)
+ .addComponent(cbCommentLocal)
+ .addComponent(cbOutputEnable)
+ )
+ .addPreferredGap(ComponentPlacement.RELATED)
+ .addGroup(glInputMain.createParallelGroup(Alignment.LEADING)
+ .addComponent(fldVideo, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
+ .addComponent(fldComment, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
+ .addComponent(fldOutput, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
+ )
+ .addGroup(glInputMain.createParallelGroup()
+ .addComponent(btnVideo)
+ .addComponent(btnComment)
+ )
+ .addContainerGap()
+ )
);
- gl_pnlInputMain.setVerticalGroup(
- gl_pnlInputMain.createParallelGroup(Alignment.LEADING)
- .addGroup(gl_pnlInputMain.createSequentialGroup()
+
+ glInputMain.setVerticalGroup(
+ glInputMain.createParallelGroup(Alignment.LEADING)
+ .addGroup(glInputMain.createSequentialGroup()
.addContainerGap()
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
+ .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
.addComponent(fldId, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(lblId)
.addComponent(cbBackLogReduce)
.addComponent(fldBackLog)
)
.addPreferredGap(ComponentPlacement.RELATED)
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
+ .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
.addComponent(lblVideo)
+ .addComponent(cbVideoLocal)
.addComponent(fldVideo, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(btnVideo)
- .addComponent(cbVideoLocal))
+ )
.addPreferredGap(ComponentPlacement.RELATED)
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
+ .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
.addComponent(lblComment)
+ .addComponent(cbCommentLocal)
.addComponent(fldComment, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(btnComment)
- .addComponent(cbCommentLocal))
+ )
.addPreferredGap(ComponentPlacement.RELATED)
- .addGroup(gl_pnlInputMain.createParallelGroup(Alignment.BASELINE)
+ .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
.addComponent(lblOutput)
.addComponent(fldOutput, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addComponent(cbOutputEnable))
- .addPreferredGap(ComponentPlacement.UNRELATED)
+ .addComponent(cbOutputEnable)
+ )
+ )
+ );
+
+ // ffmpeg入力パネル
+ pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(false);
+ pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(false);
+ pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(false);
+ pnlInputFfmpeg.cmbFfmpegOptionFile.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ final boolean notFile = !pnlInputFfmpeg.mdlFfmpegOption.isFile();
+ pnlInputFfmpeg.fldFfmpegOptionExtension.setEnabled(notFile);
+ pnlInputFfmpeg.fldFfmpegOptionMain.setEnabled(notFile);
+ pnlInputFfmpeg.fldFfmpegOptionIn.setEnabled(notFile);
+ pnlInputFfmpeg.fldFfmpegOptionOut.setEnabled(notFile);
+ pnlInputFfmpeg.fldFfmpegOptionAv.setEnabled(notFile);
+ pnlInputFfmpeg.cbFfmpegOptionResize.setEnabled(notFile);
+ }
+ });
+ pnlInputFfmpeg.cbFfmpegOptionResize.addItemListener(new ItemListener() {
+
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
+ pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(selected);
+ pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(selected);
+ pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(selected);
+ }
+ });
+ pnlInputFfmpeg.cbFfmpegOptionResize.addPropertyChangeListener("enabled", new PropertyChangeListener() {
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ final boolean enabled = ((Boolean) evt.getNewValue()).booleanValue();
+ final boolean fldEnabled = enabled ? pnlInputFfmpeg.cbFfmpegOptionResize.isSelected() : false;
+ pnlInputFfmpeg.fldFfmpegOptionResizeWidth.setEnabled(fldEnabled);
+ pnlInputFfmpeg.fldFfmpegOptionResizeHeight.setEnabled(fldEnabled);
+ pnlInputFfmpeg.cbFfmpegOptionKeepAspect.setEnabled(fldEnabled);
+ }
+ });
+
+
+ tbpInput.add("メイン", pnlInputMain);
+ tbpInput.add("ffmpeg", pnlInputFfmpeg);
+
+ // 入力部のボタンやメッセージ表示部
+ fldInputMessage.setEditable(false);
+ fldInputMessage.setEnabled(false);
+ fldInputMessage.setBorder(BorderFactory.createEmptyBorder());
+
+ final JPanel pnlInputButton = new JPanel();
+ final GroupLayout glInputButton = new GroupLayout(pnlInputButton);
+ pnlInputButton.setLayout(glInputButton);
+ glInputButton.setHorizontalGroup(glInputButton.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(fldInputMessage, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
+ .addPreferredGap(ComponentPlacement.UNRELATED)
+ .addComponent(btnClear)
+ .addPreferredGap(ComponentPlacement.UNRELATED)
+ .addComponent(btnApply)
+ .addContainerGap()
+ );
+ glInputButton.setVerticalGroup(glInputButton.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(glInputButton.createParallelGroup(Alignment.BASELINE)
+ .addComponent(fldInputMessage, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(btnClear)
.addComponent(btnApply)
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ )
+ .addContainerGap()
+ );
+
+ // 画面下半分の入力部分
+ final JPanel pnlInputAll = new JPanel();
+ pnlInputAll.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
+ final GroupLayout glInputAll = new GroupLayout(pnlInputAll);
+ pnlInputAll.setLayout(glInputAll);
+ glInputAll.setHorizontalGroup(glInputAll.createParallelGroup()
+ .addComponent(tbpInput)
+ .addComponent(pnlInputButton)
+ );
+ glInputAll.setVerticalGroup(glInputAll.createSequentialGroup()
+ .addComponent(tbpInput)
+ .addComponent(pnlInputButton)
);
GroupLayout gl_pnlMain = new GroupLayout(pnlMain);
.addGroup(Alignment.TRAILING, gl_pnlMain.createSequentialGroup()
.addContainerGap()
.addGroup(gl_pnlMain.createParallelGroup(Alignment.TRAILING)
- .addComponent(pnlInputMain, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(scrDisplay, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
- .addComponent(pnlButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(pnlButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(pnlInputAll, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ )
.addContainerGap())
);
gl_pnlMain.setVerticalGroup(
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(pnlButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(pnlInputMain, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addGap(24, 24, 24))
+ .addComponent(pnlInputAll, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addContainerGap()
+ )
);
);
pack();
+ setMinimumSize(getSize());
+
+ /*
+ * 画面のサイズや位置を前回終了時のものに設定する
+ */
+ final int windowWidth = p.getSystemWindowWidth();
+ final int windowHeight = p.getSystemWindowHeight();
+ if (windowWidth > 0 && windowHeight > 0) {
+ setSize(windowWidth, windowHeight);
+ }
+
+ // TODO 最大化した状態で終了した場合の考慮
+ final int windowPosX = p.getSystemWindowPosX();
+ final int windowPosY = p.getSystemWindowPosY();
+ if (windowPosX > 1024 && windowPosY > 1024) {
+ setLocation(windowPosX, windowPosY);
+ } else {
+ setLocationByPlatform(true);
+ }
+
+ final int colId = p.getSystemColumnId();
+ if(colId > 0) {
+ tblDisplay.getColumnModel().getColumn(0).setPreferredWidth(colId);
+ }
+ final int colStatus = p.getSystemColumnStatus();
+ if(colStatus > 0) {
+ tblDisplay.getColumnModel().getColumn(4).setPreferredWidth(colStatus);
+ }
+
initInputPanel();
pnlMain.setTransferHandler(new DownloadListTransferHandler());
tblDisplay.setTransferHandler(new TableTransferHandler());
}
- private class ApplyActionListener implements ActionListener {
+ public void startWatcher() {
+ videoFileWatcherThread.start();
+ }
+
+ private class GuiTaskManageListener implements TaskManageListener {
+
+ @Override
+ public void process(final int id, final TaskKind kind, final TaskStatus status, final double percentage,
+ final String message) {
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ targetModel.setStatus(id, kind, status, percentage, message);
+ }
+ });
+ }
+ }
+
+ private class StopActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
- final DownloadProfile prof = new InqubusDownloadProfile();
- final String id = Util.getVideoId(fldId.getText());
+ final int row = tblDisplay.getSelectedRow();
+ final Target t = targetModel.getTarget(row);
+ final boolean res = taskManager.cancel(t.getRowId());
+ logger.log(Level.FINE, "停止: {0} {1}", new Object[]{t.getVideoId(), res});
+ if (res) {
+ targetModel.setStatus(t.getRowId(), null, TaskStatus.CANCELLED, -1.0, "キャンセル");
+ }
+ }
+ }
+
+ private class ApplyActionListener implements ActionListener {
- new Download(prof, id).execute();
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ final DownloadProfile downProf = new InqubusDownloadProfile();
+ final String id = Util.getVideoId(fldId.getText());
+ final InqubusConvertProfile convProf = new InqubusConvertProfile();
+ logger.log(Level.INFO, downProf.toString());
+ logger.log(Level.INFO, convProf.toString());
+ final RequestProcess rp = new RequestProcess(downProf, id, convProf);
+ taskManager.add(rp);
+ targetModel.addTarget(new Target(rp));
+ initInputPanel();
+ } catch (Throwable th) {
+ logger.log(Level.SEVERE, null, th);
+ JOptionPane.showMessageDialog(MainFrame.this, th.getMessage(), "中断しました", JOptionPane.ERROR_MESSAGE);
+ }
}
}
- /** This method is called from within the constructor to
- * initialize the form.
- * WARNING: Do NOT modify this code. The content of this method is
- * always regenerated by the Form Editor.
- */
- @SuppressWarnings("unchecked")
- // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
- private void initComponents() {
- }// </editor-fold>//GEN-END:initComponents
- private File searchFileMatchId(final File dir, final String id) throws UnsupportedOperationException {
+ private File searchFileMatchId(final File dir, final String id) {
// TODO 候補は複数返すようにして、その後の対処は呼び出しもとで行ってもらった方が良いかも
if (id.isEmpty()) {
return null;
}
}
+ /**
+ * 動画, コメントの"local"チェックボックス更新時の処理.
+ */
private void useMovieLocalCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_useMovieLocalCheckBoxItemStateChanged
final Config p = Config.INSTANCE;
final ItemSelectable source = evt.getItemSelectable();
- JButton btn;
+ JButton button;
JTextField field;
File dir;
if (source == cbVideoLocal) {
- btn = btnVideo;
+ button = btnVideo;
field = fldVideo;
dir = new File(p.getVideoDir());
} else {
- btn = btnComment;
+ button = btnComment;
field = fldComment;
dir = new File(p.getCommentDir());
}
final boolean useLocal = (evt.getStateChange() == ItemEvent.SELECTED);
- btn.setEnabled(useLocal);
+
+ button.setEnabled(useLocal);
String text;
if (useLocal) {
}
field.setText(text);
- fldId.setEnabled(!(cbVideoLocal.isSelected() && cbCommentLocal.isSelected()));
-
}//GEN-LAST:event_useMovieLocalCheckBoxItemStateChanged
private void outputConvertCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_outputConvertCheckBoxItemStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private final JTable tblDisplay;
// ボタン領域
- private final JButton btnStart;
- private final JButton btnStop;
- private final JButton btnDeselect;
- //入力領域 - 標準
- private final JTextField fldId;
- private final JCheckBox cbBackLogReduce = new JCheckBox("コメ数減少");
+ private final JButton btnStart = new JButton("開始");
+ private final JButton btnStop = new JButton("停止");
+ private final JButton btnDeselect = new JButton("選択解除");
+ // 入力領域
+ private final JTabbedPane tbpInput = new JTabbedPane(JTabbedPane.BOTTOM);
+ // 入力領域 - メイン
+ private final IdComboBox fldId;
+ private final JCheckBox cbBackLogReduce = new JCheckBox("少コメ");
private final JCheckBox cbBackLog = new JCheckBox("過去ログ");
private final JTextField fldBackLog = new JTextField();
private final JCheckBox cbVideoLocal;
private final JTextField fldVideo;
- private final JButton btnVideo;
+ private final JButton btnVideo = new JButton("...");
private final JCheckBox cbCommentLocal;
private final JTextField fldComment;
- private final JButton btnComment;
+ private final JButton btnComment = new JButton("...");
private final JCheckBox cbOutputEnable;
private final JTextField fldOutput;
+ // 入力領域 - ffmpeg
+ private final FfmpegParamPanel pnlInputFfmpeg = new FfmpegParamPanel();
// 適用
+ private final JTextField fldInputMessage = new JTextField();
+ private final JButton btnClear = new JButton("クリア");
private final JButton btnApply = new JButton("適用");
// End of variables declaration//GEN-END:variables
private void initInputPanel() {
+ initMainTab();
+ initFfmpegTab();
+ tbpInput.setSelectedIndex(0);
+ fldId.requestFocus();
+ }
+
+ private void initMainTab() {
final Config p = Config.INSTANCE;
fldId.setText("");
fldBackLog.setEnabled(false);
- fldBackLog.setToolTipText("YYYY/MM/DD hh:mm:ss形式、あるいは1970/01/01からの経過秒を入力します。");
cbBackLog.setEnabled(true);
- cbBackLog.addItemListener(new ItemListener() {
-
- @Override
- public void itemStateChanged(ItemEvent e) {
- final boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
- fldBackLog.setEnabled(selected);
- }
- });
- cbBackLogReduce.setToolTipText("「コメントの量を減らす」場合はチェックを付けます。");
- final boolean movieLocal = p.getVideoUseLocal();
- cbVideoLocal.setSelected(movieLocal);
- btnVideo.setEnabled(movieLocal);
- if (!movieLocal) {
+ final boolean videoLocal = p.getVideoUseLocal();
+ cbVideoLocal.setSelected(videoLocal);
+ if (!videoLocal) {
fldVideo.setText(p.getVideoFileNamePattern());
}
+ btnVideo.setEnabled(videoLocal);
final boolean commentLocal = p.getCommentUseLocal();
cbCommentLocal.setSelected(commentLocal);
- btnComment.setEnabled(commentLocal);
if (!commentLocal) {
fldComment.setText(p.getCommentFileNamePattern());
}
+ btnComment.setEnabled(commentLocal);
final boolean convert = p.getOutputEnable();
cbOutputEnable.setSelected(convert);
fldOutput.setEnabled(convert);
fldOutput.setText(p.getOutputFileNamePattern());
+ }
+ private void initFfmpegTab() {
+ pnlInputFfmpeg.init(Config.INSTANCE);
}
private JMenuBar initMenuBar() {
return menuBar;
}
+ private class DownloadProgressListener implements WorkerListener<DownloadResult, DownloadProgress> {
+
+ @Override
+ public void process(DownloadProgress progress) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void cancelled() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void done(DownloadResult result) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void error(Throwable th) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+ private class ConvertProgressListener implements WorkerListener<ConvertResult, ConvertProgress> {
+
+ @Override
+ public void process(ConvertProgress progress) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void cancelled() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void done(ConvertResult result) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void error(Throwable th) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+
+
private class DownloadListTransferHandler extends TransferHandler {
private static final long serialVersionUID = 1L;
@Override
public boolean importData(TransferHandler.TransferSupport support) {
- try {
- Transferable transferable = support.getTransferable();
- if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
- @SuppressWarnings("unchecked")
- final List<File> data = (List<File>) transferable.getTransferData(DataFlavor.javaFileListFlavor);
- Collection<Target> targets = Target.from(data);
- targetModel.addTarget(targets);
- } else if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
- String data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
- Matcher matcher = movieIdPattern.matcher(data);
- if (matcher.find()) {
- String movieId = matcher.group(1);
- Target target = Target.fromId(movieId);
- targetModel.addTarget(target);
- } else {
- return false;
- }
-
- }
- return false;
- } catch (Exception e) {
- logger.log(Level.SEVERE, null, e);
- return false;
- }
+// try {
+// Transferable transferable = support.getTransferable();
+// if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
+// @SuppressWarnings("unchecked")
+// final List<File> data = (List<File>) transferable.getTransferData(DataFlavor.javaFileListFlavor);
+// Collection<Target> targets = Target.from(data);
+// targetModel.addTarget(targets);
+// } else if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+// String data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
+// Matcher matcher = movieIdPattern.matcher(data);
+// if (matcher.find()) {
+// String movieId = matcher.group(1);
+// Target target = Target.fromId(movieId);
+// targetModel.addTarget(target);
+// } else {
+// return false;
+// }
+//
+// }
+// return false;
+// } catch (Exception e) {
+// logger.log(Level.SEVERE, null, e);
+// return false;
+// }
+ // TODO 上記実装見直し(Locationは削除された)
+ return false;
}
}
}
}
+ private class MainFrameWindowListener extends WindowAdapter {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ final Config p = Config.INSTANCE;
+
+ final Dimension size = getSize();
+ p.setSystemWindowWidth(size.width);
+ p.setSystemWindowHeight(size.height);
+
+ final Point pos = getLocation();
+ p.setSystemWindowPosX(pos.x);
+ p.setSystemWindowPosY(pos.y);
+
+ p.setSystemColumnId(tblDisplay.getColumnModel().getColumn(0).getWidth());
+ p.setSystemColumnVideo(tblDisplay.getColumnModel().getColumn(1).getWidth());
+ p.setSystemColumnComment(tblDisplay.getColumnModel().getColumn(2).getWidth());
+ p.setSystemColumnConvert(tblDisplay.getColumnModel().getColumn(3).getWidth());
+ p.setSystemColumnStatus(tblDisplay.getColumnModel().getColumn(4).getWidth());
+ try {
+ p.save();
+ } catch (ConfigurationException ex) {
+ logger.log(Level.SEVERE, "コンフィグ保存失敗", ex);
+ }
+ }
+ }
+
+ /*
+ * ここからDownloadProfile作成用クラスの定義
+ */
private class InqubusDownloadProfile implements DownloadProfile {
public GeneralProfile getGeneralProfile() {
return this.generalProfile;
}
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
}
private class InqubusLoginProfile implements LoginProfile {
public String getPassword() {
return this.password;
}
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
}
private class InqubusProxyProfile implements ProxyProfile {
public int getPort() {
return this.port;
}
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
}
private class InqubusVideoProfile implements VideoProfile {
public File getLocalFile() {
return this.localFile;
}
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
}
private class InqubusCommentProfile implements CommentProfile {
private InqubusCommentProfile() {
final Config p = Config.INSTANCE;
- this.download = !cbVideoLocal.isSelected();
+ this.download = !cbCommentLocal.isSelected();
if (this.download) {
- this.dir = new File(p.getVideoDir());
- this.fileName = fldVideo.getText();
+ this.dir = new File(p.getCommentDir());
+ this.fileName = fldComment.getText();
this.localFile = null;
} else {
this.dir = null;
this.fileName = null;
- this.localFile = new File(fldVideo.getText());
+ this.localFile = new File(fldComment.getText());
}
if(cbBackLog.isSelected()) {
public long getBackLogPoint() {
return this.backLogPoint;
}
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
}
private class InqubusGeneralProfile implements GeneralProfile {
return this.replaceTo;
}
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
+ }
+
+ /*
+ * ここからConvertProfile作成用クラスの定義
+ */
+ private class InqubusConvertProfile implements ConvertProfile {
+ private final OutputProfile outputProfile;
+ private final GeneralProfile generalProfile;
+ private final FfmpegProfile ffmpegProfile;
+ private final boolean convert;
+ private final File ffmpeg;
+ private final boolean vhookDisabled;
+ private final boolean commentOverlay;
+ private final File vhook;
+ private final File tmpDir;
+ private final File font;
+ private final int fontIndex;
+ private final boolean commentOpaque;
+ private final boolean disableFontSizeArrange;
+ private final int shadowIndex;
+ private final boolean showConvrting;
+ private final int maxNumOfComment;
+ private final HideCondition ngSetting;
+
+ private InqubusConvertProfile() throws IOException {
+ final Config p = Config.INSTANCE;
+ this.outputProfile = new InqubusOutputProfile();
+ this.generalProfile = new InqubusGeneralProfile();
+ this.ffmpegProfile = new InqubusFfmpegProfile();
+ this.convert = cbOutputEnable.isSelected();
+ this.ffmpeg = new File(p.getFfmpegPath());
+ // TODO コンフィグに設定なし
+ this.vhookDisabled = false;
+ this.commentOverlay = p.getOutputCommentOverlay();
+ this.vhook = new File(p.getFfmpegDllPath());
+ this.tmpDir = new File(p.getSystemTempDir());
+ this.font = new File(p.getFontPath());
+ this.fontIndex = Integer.parseInt(p.getFontIndex());
+ this.commentOpaque = p.getCommentOpaque();
+ this.disableFontSizeArrange = p.getFontSizeArrangeDisable();
+ this.shadowIndex = p.getFontShadow();
+ // TODO コンフィグに設定なし
+ this.showConvrting = true;
+ this.maxNumOfComment = (p.getCommentDisplaySizeDefault()) ? -1 : Integer.parseInt(p.
+ getCommentDisplaySizeManual());
+ this.ngSetting = new InqubusHideCondition();
+ }
+
+ @Override
+ public OutputProfile getOutputProfile() {
+ return this.outputProfile;
+ }
+
+ @Override
+ public GeneralProfile getGeneralProfile() {
+ return this.generalProfile;
+ }
+
+ @Override
+ public FfmpegProfile getFfmpegOption() {
+ return this.ffmpegProfile;
+ }
+
+ @Override
+ public boolean isConvert() {
+ return this.convert;
+ }
+
+ @Override
+ public File getFfmpeg() {
+ return this.ffmpeg;
+ }
+
+ @Override
+ public boolean isVhookDisabled() {
+ return this.vhookDisabled;
+ }
+
+ @Override
+ public boolean isCommentOverlay() {
+ return this.commentOverlay;
+ }
+
+ @Override
+ public File getVhook() {
+ return this.vhook;
+ }
+
+ @Override
+ public File getTempDir() {
+ return this.tmpDir;
+ }
+
+ @Override
+ public File getFont() {
+ return this.font;
+ }
+
+ @Override
+ public int getFontIndex() {
+ return this.fontIndex;
+ }
+
+ @Override
+ public boolean isCommentOpaque() {
+ return this.commentOpaque;
+ }
+
+ @Override
+ public boolean isDisableFontSizeArrange() {
+ return this.disableFontSizeArrange;
+ }
+
+ @Override
+ public int getShadowIndex() {
+ return this.shadowIndex;
+ }
+
+ @Override
+ public boolean isShowConverting() {
+ return this.showConvrting;
+ }
+
+ @Override
+ public int getMaxNumOfComment() {
+ return this.maxNumOfComment;
+ }
+
+ @Override
+ public HideCondition getNgSetting() {
+ return this.ngSetting;
+ }
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
+ }
+
+ private class InqubusOutputProfile implements OutputProfile {
+ private final File dir;
+ private final String fileName;
+ private final String videoId;
+ private final String title;
+
+
+ private InqubusOutputProfile(){
+ final Config p = Config.INSTANCE;
+ this.dir = new File(p.getOutputDir());
+ this.fileName = fldOutput.getText();
+ // TODO この時点でのID/Titleはどうするか…
+ this.videoId = "";
+ this.title = "";
+ }
+
+ @Override
+ public File getDir() {
+ return this.dir;
+ }
+
+ @Override
+ public String getFileName() {
+ return this.fileName;
+ }
+
+ @Override
+ public String getVideoId() {
+ return this.videoId;
+ }
+
+ @Override
+ public String getTitile() {
+ return this.title;
+ }
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
+ }
+
+ private class InqubusFfmpegProfile implements FfmpegProfile {
+ private final String extOption;
+ private final String inOption;
+ private final String mainOption;
+ private final String outOption;
+ private final String avOption;
+ private final boolean resize;
+ private final int resizeWidth;
+ private final int resizeHeight;
+ private final boolean adjustRatio;
+
+ private InqubusFfmpegProfile() throws IOException {
+ final File file = pnlInputFfmpeg.mdlFfmpegOption.getSelectedFile();
+ if (file != null) {
+ final FfmpegOption ffop = FfmpegOption.load(file);
+ this.extOption = ffop.getExtOption();
+ this.inOption = ffop.getInOption();
+ this.mainOption = ffop.getMainOption();
+ this.outOption = ffop.getMainOption();
+ this.avOption = ffop.getAvfilterOption();
+ this.resize = ffop.isResize();
+ this.resizeWidth = ffop.getResizeWidth();
+ this.resizeHeight = ffop.getResizeHeight();
+ this.adjustRatio = ffop.isAdjustRatio();
+ } else {
+ this.extOption = pnlInputFfmpeg.fldFfmpegOptionExtension.getText();
+ this.inOption = pnlInputFfmpeg.fldFfmpegOptionIn.getText();
+ this.mainOption = pnlInputFfmpeg.fldFfmpegOptionMain.getText();
+ this.outOption = pnlInputFfmpeg.fldFfmpegOptionOut.getText();
+ this.avOption = pnlInputFfmpeg.fldFfmpegOptionAv.getText();
+ this.resize = pnlInputFfmpeg.cbFfmpegOptionResize.isSelected();
+ this.resizeWidth = Integer.parseInt(pnlInputFfmpeg.fldFfmpegOptionResizeWidth.getText());
+ this.resizeHeight = Integer.parseInt(pnlInputFfmpeg.fldFfmpegOptionResizeHeight.getText());
+ this.adjustRatio = pnlInputFfmpeg.cbFfmpegOptionKeepAspect.isSelected();
+ }
+ }
+
+ @Override
+ public String getExtOption() {
+ return this.extOption;
+ }
+
+ @Override
+ public String getInOption() {
+ return this.inOption;
+ }
+
+ @Override
+ public String getMainOption() {
+ return this.mainOption;
+ }
+
+ @Override
+ public String getOutOption() {
+ return this.outOption;
+ }
+
+ @Override
+ public String getAvfilterOption() {
+ return this.avOption;
+ }
+
+ @Override
+ public boolean isResize() {
+ return this.resize;
+ }
+
+ @Override
+ public int getResizeWidth() {
+ return this.resizeWidth;
+ }
+
+ @Override
+ public int getResizeHeight() {
+ return this.resizeHeight;
+ }
+
+ @Override
+ public boolean isAdjustRatio() {
+ return this.adjustRatio;
+ }
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
+ }
+
+ private class InqubusHideCondition implements ConvertProfile.HideCondition{
+
+ @Override
+ public String getWord() {
+ // TODO
+ return "";
+ }
+
+ @Override
+ public String getId() {
+ // TODO
+ return "";
+ }
+
+ @Override
+ public String toString(){
+ return ToStringBuilder.reflectionToString(this);
+ }
}
}