1つのファイルだけでプログラミングしているが大丈夫か?になってきたのでそろそろ分割を考える。
あとはRowSorterを使ってみようかと思ったけど挙動がよくわからなかったのでJTableHeader(というかTableCellRenderer)を自前で用意してごにょごにょしてみようかと…
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.util.Date; import java.util.Arrays; import java.text.SimpleDateFormat; import java.io.File; import java.io.IOException; 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); 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 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)); new Thread(() -> { model.setCurrentDirectory(dir); table.repaint(); }).run(); 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; }); JFiler.setCellRenderer(table); JFiler.setMouseListener(tab, 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); } } } }); } 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.showConfirmDialog(table, exception.getMessage()); } } } } 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 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 4; } @Override public Object getValueAt(int row, int column){ return children[row]; } } }