OSDN Git Service

ウィンドウのポジションがマイナスになることは普通にある
[coroid/inqubus.git] / frontend / src / yukihane / inqubus / gui / MainFrame.java
index e639419..316b2d1 100644 (file)
@@ -5,8 +5,10 @@
  */
 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;
@@ -15,18 +17,23 @@ import java.awt.event.ActionListener;
 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;
@@ -34,6 +41,7 @@ import javax.swing.GroupLayout;
 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;
@@ -51,11 +59,11 @@ 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.OptionComboBoxModel;
 import saccubus.util.WayBackTimeParser;
 import saccubus.worker.impl.convert.ConvertProgress;
 import saccubus.worker.impl.download.DownloadProgress;
@@ -73,6 +81,7 @@ 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;
@@ -99,14 +108,39 @@ public class MainFrame extends JFrame {
             = "ファイル命名規則入力します。";
     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);
@@ -116,15 +150,15 @@ public class MainFrame extends JFrame {
         tblDisplay = new JTable(targetModel, new TargetsColumnModel());
         tblDisplay.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
         final JPanel pnlButton = new JPanel();
-        final JTabbedPane tbpInput = new JTabbedPane();
         final JPanel pnlInputMain = new JPanel();
         final JLabel lblId = new JLabel();
-        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.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からの経過秒を入力します。");
@@ -160,6 +194,8 @@ public class MainFrame extends JFrame {
         });
         fldComment = new JTextField();
         fldComment.setToolTipText(FILE_INPUTFIELD_TOOLTIP);
+        btnComment.addActionListener(
+                new FileChooseAction(MainFrame.this, JFileChooser.FILES_ONLY, fldComment));
         final JLabel lblOutput = new JLabel();
         cbOutputEnable = new JCheckBox();
         fldOutput = new JTextField();
@@ -170,6 +206,13 @@ public class MainFrame extends JFrame {
         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());
 
@@ -204,7 +247,10 @@ public class MainFrame extends JFrame {
 
         lblId.setText("ID");
 
-        fldId.addActionListener(applyListener);
+
+        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) {
@@ -279,6 +325,10 @@ public class MainFrame extends JFrame {
                     .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()
             )
         );
@@ -297,13 +347,17 @@ public class MainFrame extends JFrame {
                 .addPreferredGap(ComponentPlacement.RELATED)
                 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
                     .addComponent(lblVideo)
+                    .addComponent(cbVideoLocal)
                     .addComponent(fldVideo, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addComponent(cbVideoLocal))
+                    .addComponent(btnVideo)
+                )
                 .addPreferredGap(ComponentPlacement.RELATED)
                 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
                     .addComponent(lblComment)
+                    .addComponent(cbCommentLocal)
                     .addComponent(fldComment, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addComponent(cbCommentLocal))
+                    .addComponent(btnComment)
+                )
                 .addPreferredGap(ComponentPlacement.RELATED)
                 .addGroup(glInputMain.createParallelGroup(Alignment.BASELINE)
                     .addComponent(lblOutput)
@@ -368,6 +422,8 @@ public class MainFrame extends JFrame {
             .addContainerGap()
             .addComponent(fldInputMessage, GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
             .addPreferredGap(ComponentPlacement.UNRELATED)
+            .addComponent(btnClear)
+            .addPreferredGap(ComponentPlacement.UNRELATED)
             .addComponent(btnApply)
             .addContainerGap()
         );
@@ -375,6 +431,7 @@ public class MainFrame extends JFrame {
             .addContainerGap()
             .addGroup(glInputButton.createParallelGroup(Alignment.BASELINE)
                 .addComponent(fldInputMessage, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                .addComponent(btnClear)
                 .addComponent(btnApply)
             )
             .addContainerGap()
@@ -436,15 +493,42 @@ public class MainFrame extends JFrame {
         );
 
         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());
+    }
 
-        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());
+    public void startWatcher() {
+        videoFileWatcherThread.start();
     }
 
     private class GuiTaskManageListener implements TaskManageListener {
@@ -530,18 +614,23 @@ public class MainFrame extends JFrame {
 
         final ItemSelectable source = evt.getItemSelectable();
 
+        JButton button;
         JTextField field;
         File dir;
         if (source == cbVideoLocal) {
+            button = btnVideo;
             field = fldVideo;
             dir = new File(p.getVideoDir());
         } else {
+            button = btnComment;
             field = fldComment;
             dir = new File(p.getCommentDir());
         }
 
         final boolean useLocal = (evt.getStateChange() == ItemEvent.SELECTED);
 
+        button.setEnabled(useLocal);
+
         String text;
         if (useLocal) {
             final File f = searchFileMatchId(dir, fldId.getText());
@@ -592,27 +681,34 @@ public class MainFrame extends JFrame {
     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 JTextField fldId = new JTextField();
-    private final JCheckBox cbBackLogReduce = new JCheckBox("コメ数減少");
+    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 = new JButton("...");
     private final JCheckBox cbCommentLocal;
     private final JTextField fldComment;
+    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() {
@@ -622,17 +718,19 @@ public class MainFrame extends JFrame {
         fldBackLog.setEnabled(false);
         cbBackLog.setEnabled(true);
 
-        final boolean movieLocal = p.getVideoUseLocal();
-        cbVideoLocal.setSelected(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);
         if (!commentLocal) {
             fldComment.setText(p.getCommentFileNamePattern());
         }
+        btnComment.setEnabled(commentLocal);
 
         final boolean convert = p.getOutputEnable();
         cbOutputEnable.setSelected(convert);
@@ -807,6 +905,32 @@ public class MainFrame extends JFrame {
         }
     }
 
+    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作成用クラスの定義
      */