マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

Stream APIも使ってみる

ファイルがドロップされたときの処理でStream APIを使ってみた。filterでinstanceof使ってるけどこれFile以外のときあるのかな?まぁ、いいや。あとソースコードにコメントが一切ないのでコメント追加していきたい。

var list = (List<?>)transferable.getTransferData(DataFlavor.javaFileListFlavor);

list.stream().filter(o -> o instanceof File).map(o -> (File)o).forEach(f -> {
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

import javax.swing.table.TableColumn;
import javax.swing.table.AbstractTableModel;
import javax.swing.filechooser.FileSystemView;

import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;

import java.awt.dnd.DropTarget;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;

import java.awt.datatransfer.DataFlavor;

import java.util.Date;
import java.util.List;
import java.util.Arrays;

import java.nio.file.Files;

import java.text.SimpleDateFormat;

import java.io.File;

import java.io.IOException;
import java.awt.datatransfer.UnsupportedFlavorException;

public class JFiler{
    private static final String[] FILE_SUFFIX = {"B", "KB", "MB", "GB", "TB", "PB"};
    private static final int FILE_NAME_COLUMN = 0;
    private static final int FILE_MODIFY_COLUMN = 1;
    private static final int FILE_TYPE_COLUMN = 2;
    private static final int FILE_SIZE_COLUMN = 3;
    
    private static final String NAME_HEADER_TEXT = "名前";
    private static final String MODIFY_HEADER_TEXT = "更新日時";
    private static final String TYPE_HEADER_TEXT = "種類";
    private static final String SIZE_HEADER_TEXT = "サイズ";
    
    private static final Color HEADER_COLOR = new Color(0xee, 0xee, 0xFF);
    private static final Color CELL_SELECTED_COLOR = new Color(0xCC, 0xCC, 0xFF);
    
    private static final int COLUMN_COUNT = 4;
    
    public static void main(String... args){
        SwingUtilities.invokeLater(JFiler::start);
    }
    
    private static void start(){
        var frame = new JFrame();
        
        var tab = new JTabbedPane();
        var table = JFiler.createFileTable(tab, new File("./../"));
        table.setPreferredSize(new Dimension(600, 500));
        
        tab.addTab(((FileModel)table.getModel()).getCurrentDirectoryName(), new JScrollPane(table));
        frame.add(tab);
        frame.setVisible(true);
        frame.pack();
        
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    private static void acceptFileDrop(JTable table){
        var listener = new DropTargetAdapter(){
            @Override
            public void dragOver(DropTargetDragEvent e){
                if(e.isDataFlavorSupported(DataFlavor.javaFileListFlavor)){
                    e.acceptDrag(DnDConstants.ACTION_COPY);
                }else{
                    e.rejectDrag();
                }
            }
            
            @Override
            public void drop(DropTargetDropEvent e){
                if(e.isDataFlavorSupported(DataFlavor.javaFileListFlavor)){
                    e.acceptDrop(DnDConstants.ACTION_COPY);
                    
                    copyDropFiles(table, e);
                    
                    e.dropComplete(true);
                }else{
                    e.rejectDrop();
                }
            }
        };
        
        new DropTarget(table, DnDConstants.ACTION_COPY, listener, true);
    }
    
    private static void copyDropFiles(JTable table, DropTargetDropEvent e){
        try{
            var transferable = e.getTransferable();
            var list = (List<?>)transferable.getTransferData(DataFlavor.javaFileListFlavor);

            list.stream().filter(o -> o instanceof File).map(o -> (File)o).forEach(f -> {
                var dstDir = ((FileModel)table.getModel()).getCurrentDirectory();
                var dstFile = new File(dstDir, f.getName());

                try{
                    Files.copy(f.toPath(), dstFile.toPath());
                }catch(IOException exception){
                    JOptionPane.showMessageDialog(table, exception.getMessage());
                    exception.printStackTrace();
                }
            });
        }catch(UnsupportedFlavorException | IOException exception) {
            JOptionPane.showMessageDialog(table, exception.getMessage());
            exception.printStackTrace();
        }
        
        new Thread(() -> {
            var model = (FileModel)table.getModel();
            model.setCurrentDirectory(model.getCurrentDirectory());
            table.repaint();
        }).run();
    }
    
    private static JTable createFileTable(JTabbedPane tab, File dir){
        var model = new FileModel();
        
        var table = new JTable(model);
        table.setRowHeight(24);
        table.setShowGrid(false);
        table.setIntercellSpacing(new Dimension(0, 0));
        
        var header = table.getTableHeader();
        header.setDefaultRenderer((t, value, isSelected, hasFocus, row, column) -> {
            var label = new JLabel(value.toString());
            label.setOpaque(true);
            label.setBackground(JFiler.HEADER_COLOR);
            
            return label;
        });
        
        new Thread(() -> {
            model.setCurrentDirectory(dir);
            table.repaint();
        }).run();
        
        JFiler.setCellRenderer(table);
        JFiler.setMouseListener(tab, table);
        JFiler.acceptFileDrop(table);
        
        return table;
    }
    
    private static void setMouseListener(JTabbedPane tab, JTable table){
        table.addMouseListener(new MouseAdapter(){
            public void mouseClicked(MouseEvent e){
                var model = (FileModel)table.getModel();
                var row = table.rowAtPoint(e.getPoint());
                var column = table.columnAtPoint(e.getPoint());
                table.changeSelection(row, column, false, false);
                
                if(SwingUtilities.isLeftMouseButton(e)){
                    JFiler.leftClicked(e, table, model);
                }else if(SwingUtilities.isMiddleMouseButton(e)){
                    var file = (File)model.getValueAt(table.getSelectedRow(), 0);
                    
                    if(file.isDirectory()){
                        var newTable = JFiler.createFileTable(tab, file);
                        var scroll = new JScrollPane(newTable);
                        tab.addTab(((FileModel)newTable.getModel()).getCurrentDirectoryName(), scroll);
                        tab.setSelectedComponent(scroll);
                    }
                }else if(SwingUtilities.isRightMouseButton(e)){
                    
                }
            }
        });
    }
    
    private static void setFileNameRenderer(TableColumn tc){
        tc.setHeaderValue(JFiler.NAME_HEADER_TEXT);
        tc.setCellRenderer((t, value, isSelected, hasFocus, row, column) -> {
            var file = (File)value;
            var view = FileSystemView.getFileSystemView();
            var icon = view.getSystemIcon(file);
            var label = new JLabel(file.getName(), icon, JLabel.LEFT);
            
            JFiler.setLabelBackground(label, isSelected, hasFocus);
            
            return label;
        });
    }
    
    private static void setFileModifyRenderer(TableColumn tc){
        tc.setHeaderValue(JFiler.MODIFY_HEADER_TEXT);
        tc.setCellRenderer((t, value, isSelected, hasFocus, row, column) -> {
            var file = (File)value;
            var date = new Date(file.lastModified());
            var format = new SimpleDateFormat("yyyy/MM/dd HH:mm");
            var label = new JLabel(format.format(date));
            
            JFiler.setLabelBackground(label, isSelected, hasFocus);
            
            return label;
        });
    }
    
    private static void setFileTypeRenderer(TableColumn tc){
        tc.setHeaderValue(JFiler.TYPE_HEADER_TEXT);
        tc.setCellRenderer((t, value, isSelected, hasFocus, row, column) -> {
            var file = (File)value;
            var label = new JLabel();
            
            if(file.isDirectory()){
                label.setText("DIR");
            }else{
                try{
                    var path = file.getCanonicalPath();
                    var index = path.lastIndexOf(".");
                    label.setText(path.substring(index + 1, path.length()).toUpperCase() + "ファイル");
                }catch(IOException e){
                    var path = file.getName();
                    var index = path.lastIndexOf(".");
                    label.setText(path.substring(index + 1, path.length()).toUpperCase() + "ファイル");
                }
            }
            
            JFiler.setLabelBackground(label, isSelected, hasFocus);
            
            return label;
        });
    }
    
    private static void setFileSizeRenderer(TableColumn tc){
        tc.setHeaderValue(JFiler.SIZE_HEADER_TEXT);
        tc.setCellRenderer((t, value, isSelected, hasFocus, row, column) -> {
            var file = (File)value;
            var size = file.length();
            var label = new JLabel();
            var count = 0;
            
            while(size > 2048){
                size /= 1024;
                count++;
            }
            
            if(!file.isDirectory()){
                label.setText("" + size + JFiler.FILE_SUFFIX[count]);
            }
            
            JFiler.setLabelBackground(label, isSelected, hasFocus);
            
            return label;
        });
    }

    private static void setLabelBackground(JLabel label, boolean isSelected, boolean hasFocus){
        if(isSelected){
            label.setOpaque(true);
            label.setBackground(JFiler.CELL_SELECTED_COLOR);
        }
    }
    
    private static void setCellRenderer(JTable table){
        var columnModel = table.getColumnModel();

        JFiler.setFileNameRenderer(columnModel.getColumn(JFiler.FILE_NAME_COLUMN));
        JFiler.setFileModifyRenderer(columnModel.getColumn(JFiler.FILE_MODIFY_COLUMN));
        JFiler.setFileTypeRenderer(columnModel.getColumn(JFiler.FILE_TYPE_COLUMN));
        JFiler.setFileSizeRenderer(columnModel.getColumn(JFiler.FILE_SIZE_COLUMN));
    }
    
    private static void leftClicked(MouseEvent e, JTable table, FileModel model){
        if(e.getClickCount() == 2){
            var file = (File)model.getValueAt(table.getSelectedRow(), 0);

            if(file.isDirectory()){
                new Thread(() -> {
                    model.setCurrentDirectory(file);
                    table.repaint();
                }).run();
            }else{
                try{
                    Desktop.getDesktop().open(file);
                }catch(IOException exception){
                    JOptionPane.showMessageDialog(table, exception.getMessage());
                    exception.printStackTrace();
                }
            }
        }
    }
    
    private static class FileModel extends AbstractTableModel{
        private File dir;
        private File[] children;

        public String getCurrentDirectoryName(){
            try{
                var path = dir.getCanonicalPath();
                var index = path.lastIndexOf(File.separator);

                return path.substring(index + 1, path.length());
            }catch(IOException e){
                return dir.getName();
            }
        }
        
        public File getCurrentDirectory(){
            return dir;
        }

        public void setCurrentDirectory(File dir){
            this.dir = dir;
            this.children = dir.listFiles();
            
            Arrays.sort(this.children, (f1, f2) -> {
                if(f1.isDirectory() && !f2.isDirectory()){
                    return -1;
                }else if(!f1.isDirectory() && f2.isDirectory()){
                    return 1;
                }else{
                    return f1.getName().compareTo(f2.getName());
                }
            });
        }
        
        @Override
        public int getRowCount(){
            return children.length;
        }
        
        @Override
        public int getColumnCount(){
            return JFiler.COLUMN_COUNT;
        }
        
        @Override
        public Object getValueAt(int row, int column){            
            return children[row];
        }
    }
}