Java CSV 比較ツール２

1. まず、JListの代わりにJTableを使用して、カラムの選択と順序の変更を可能にします。
2. カラムの順序変更のために、JTableをドラッグ＆ドロップ可能にします。
3. 選択されたカラムとその順序を取得するメソッドを追加します。
4. SQLクエリの生成部分を修正して、選択されたカラムと順序を反映させます。

以下に、修正したコードの主要な部分を示します：

```java
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.util.*;
import java.util.List;

public class CsvToSQLiteApp extends JFrame {
    // ... 他のフィールド ...
    private JTable columnTable;
    private DefaultTableModel columnTableModel;

    public CsvToSQLiteApp() {
        // ... 既存のコード ...

        // JTableの設定
        String[] columnNames = {"選択", "カラム名"};
        columnTableModel = new DefaultTableModel(columnNames, 0) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                return columnIndex == 0 ? Boolean.class : String.class;
            }
        };
        columnTable = new JTable(columnTableModel);
        columnTable.setDragEnabled(true);
        columnTable.setDropMode(DropMode.INSERT_ROWS);
        columnTable.setTransferHandler(new TableRowTransferHandler(columnTable));

        JScrollPane columnScrollPane = new JScrollPane(columnTable);
        columnPanel.add(columnScrollPane, BorderLayout.CENTER);

        // ... 既存のコード ...
    }

    private void importCsvToTable(Connection conn, String csvDirPath, String tableName, boolean hasHeader)
            throws SQLException {
        // ... 既存のコード ...

        // カラムリストの更新
        SwingUtilities.invokeLater(() -> {
            columnTableModel.setRowCount(0);
            for (String header : headers) {
                columnTableModel.addRow(new Object[]{false, header});
            }
        });

        // ... 既存のコード ...
    }

    private List<String> getSelectedColumns() {
        List<String> selectedColumns = new ArrayList<>();
        for (int i = 0; i < columnTableModel.getRowCount(); i++) {
            if ((Boolean) columnTableModel.getValueAt(i, 0)) {
                selectedColumns.add((String) columnTableModel.getValueAt(i, 1));
            }
        }
        return selectedColumns;
    }

    private void exportDiffToCsv(Connection conn, String tableA, String tableB, String outputCsvPath)
            throws SQLException, IOException {
        List<String> selectedColumns = getSelectedColumns();
        StringBuilder sql = new StringBuilder("SELECT ");
        if (selectedColumns.isEmpty()) {
            sql.append("*");
        } else {
            for (int i = 0; i < selectedColumns.size(); i++) {
                sql.append(selectedColumns.get(i));
                if (i < selectedColumns.size() - 1) {
                    sql.append(", ");
                }
            }
        }
        sql.append(" FROM ").append(tableA).append(" EXCEPT SELECT ");
        if (selectedColumns.isEmpty()) {
            sql.append("*");
        } else {
            for (int i = 0; i < selectedColumns.size(); i++) {
                sql.append(selectedColumns.get(i));
                if (i < selectedColumns.size() - 1) {
                    sql.append(", ");
                }
            }
        }
        sql.append(" FROM ").append(tableB);
        if (!selectedColumns.isEmpty()) {
            sql.append(" ORDER BY ");
            for (int i = 0; i < selectedColumns.size(); i++) {
                sql.append(selectedColumns.get(i));
                if (i < selectedColumns.size() - 1) {
                    sql.append(", ");
                }
            }
        }

        // ... 既存のコード ...
    }
}

// テーブル行のドラッグ＆ドロップを処理するクラス
class TableRowTransferHandler extends TransferHandler {
    private final JTable table;

    public TableRowTransferHandler(JTable table) {
        this.table = table;
    }

    @Override
    public int getSourceActions(JComponent c) {
        return TransferHandler.MOVE;
    }

    @Override
    protected Transferable createTransferable(JComponent c) {
        return new StringSelection(String.valueOf(table.getSelectedRow()));
    }

    @Override
    public boolean canImport(TransferSupport support) {
        return support.getComponent() == table && support.isDrop() && support.isDataFlavorSupported(DataFlavor.stringFlavor);
    }

    @Override
    public boolean importData(TransferSupport support) {
        JTable target = (JTable) support.getComponent();
        JTable.DropLocation dl = (JTable.DropLocation) support.getDropLocation();
        int index = dl.getRow();
        int max = table.getModel().getRowCount();
        if (index < 0 || index > max)
            index = max;
        target.getCellEditor().stopCellEditing();
        try {
            int rowFrom = Integer.parseInt((String) support.getTransferable().getTransferData(DataFlavor.stringFlavor));
            if (rowFrom != -1 && rowFrom != index) {
                ((DefaultTableModel) table.getModel()).moveRow(rowFrom, rowFrom, index);
                if (index > rowFrom) {
                    index--;
                }
                target.getSelectionModel().addSelectionInterval(index, index);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
```

この修正により、以下の機能が追加されます：

1. カラムをチェックボックスで選択できます。
2. カラムの順序をドラッグ＆ドロップで変更できます。
3. 選択されたカラムとその順序に基づいて、SQL文が生成されます。
4. 選択されたカラムに基づいて、結果が並び替えられます。

これらの変更により、ユーザーはより柔軟にカラムを選択し、結果の並び順を制御できるようになります。