argius note

プログラミング関連

JavaFX版Stew?

JavaFX2はGUIライブラリになったとの話を耳にしたので、ちょっと試してみました。


stew.jarをビルドパスに追加して、LauncherクラスだけをJavaFX2で作って追加したものです。
TableViewとTextAreaだけの単純なバージョンです。更新もサポートしていません。

同程度のものをSwingで作った場合と比べると、かなり簡潔に書けますね。

package net.argius.stew.ui.ria;

import java.sql.*;
import java.util.*;

import javafx.application.*;
import javafx.beans.property.*;
import javafx.beans.value.*;
import javafx.collections.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import javafx.util.*;
import net.argius.stew.*;
import net.argius.stew.ui.*;

public final class RiaLauncher extends Application implements Launcher, OutputProcessor {

    private static final Class<RiaLauncher> CLASS = RiaLauncher.class;
    private static final ResourceManager res = ResourceManager.getInstance(CLASS);

    private Environment env;
    private TableView<Map<String, Object>> resultTable;
    private TextArea textArea;
    private int promptPosition;

    @Override
    public void start(Stage stage) throws Exception {
        stage.setTitle(res.get(".title"));
        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent e) {
                close();
            }
        });
        BorderPane pane = new BorderPane();
        pane.setCenter(this.resultTable = new TableView<>());
        pane.setBottom(this.textArea = buildOutputArea());
        stage.setScene(new Scene(pane, 600, 400));
        stage.show();
        Environment env = new Environment();
        env.setOutputProcessor(this);
        launch(env);
    }

    private TextArea buildOutputArea() {
        final TextArea o = new TextArea();
        o.setStyle(res.get("style"));
        o.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent e) {
                switch (e.getCode()) {
                    case ENTER:
                        onSubmit();
                        break;
                    case C:
                        if (e.isControlDown()) {
                            o.appendText(" [BREAK] ");
                            outputPrompt();
                        }
                        break;
                    default:
                }
            }
            @SuppressWarnings("synthetic-access")
            private void onSubmit() {
                o.end();
                final int endp = o.getCaretPosition();
                if (endp >= promptPosition) {
                    sendCommand(o.getText(promptPosition, endp));
                }
            }
        });
        return o;
    }

    private void sendCommand(final String cmd) {
        Platform.runLater(new Runnable() {
            @SuppressWarnings("synthetic-access")
            @Override
            public void run() {
                if (!Command.invoke(env, cmd)) {
                    close();
                }
                outputPrompt();
            }
        });
    }

    @Override
    public void launch(Environment env) {
        this.env = env;
        output(res.get(".about", LocalSystem.getVersion()));
        outputPrompt();
    }

    @Override
    public void output(Object o) {
        if ((o instanceof ResultSetReference) || (o instanceof ResultSet)) {
            ResultSetReference ref = (o instanceof ResultSetReference)
                    ? (ResultSetReference)o
                    : new ResultSetReference((ResultSet)o, "");
            try {
                outputResult(ref);
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
        } else if (o instanceof Prompt) {
            outputPrompt();
        } else {
            outputLine(o);
        }
    }

    void outputPrompt() {
        printf("%s", new Prompt(env));
        promptPosition = textArea.getCaretPosition();
    }

    private void outputResult(ResultSetReference ref) throws SQLException {
        ResultSet rs = ref.getResultSet();
        ColumnOrder order = ref.getOrder();
        final boolean needsOrderChange = order.size() > 0;
        ResultSetMetaData meta = rs.getMetaData();
        final int columnCount = (needsOrderChange) ? order.size() : meta.getColumnCount();
        final int limit = LocalSystem.getPropertyAsInt(PropertyKey.ROW_COUNT_LIMIT,
                                                       Integer.MAX_VALUE);
        int rowCount = 0;
        final ObservableList<TableColumn<Map<String, Object>, ?>> columns = resultTable.getColumns();
        columns.clear();
        for (int i = 0; i < columnCount; i++) {
            final String name = (needsOrderChange) ? order.getName(i) : meta.getColumnName(i + 1);
            TableColumn<Map<String, Object>, Object> column = new TableColumn<>(name);
            column.setCellValueFactory(new Callback<CellDataFeatures<Map<String, Object>, Object>, ObservableValue<Object>>() {
                @Override
                public ObservableValue<Object> call(CellDataFeatures<Map<String, Object>, Object> m) {
                    return new SimpleObjectProperty<>(m.getValue().get(name));
                }
            });
            columns.add(column);
        }
        final ObservableList<Map<String, Object>> data = FXCollections.observableArrayList();
        while (rs.next()) {
            if (++rowCount >= limit) {
                continue;
            }
            Map<String, Object> row = new HashMap<>();
            for (int i = 0; i < columnCount; i++) {
                final int index = needsOrderChange ? order.getOrder(i) : i + 1;
                row.put(columns.get(i).getText(), rs.getObject(index));
            }
            data.add(row);
        }
        resultTable.setItems(data);
        ref.setRecordCount(rowCount);
    }

    private void outputLine(Object... a) {
        if (a.length == 0) {
            printf("%n");
        } else {
            for (final Object o : a) {
                printf("%s%n", o);
            }
        }
    }

    private void printf(String format, Object... a) {
        textArea.appendText(String.format(format, a));
    }

    @Override
    public void close() {
        env.release();
        Platform.exit();
    }

    public static void main(String[] args) {
        launch(CLASS, args);
    }

}