net.rptools.gui.GuiBuilder.java Source code

Java tutorial

Introduction

Here is the source code for net.rptools.gui.GuiBuilder.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
package net.rptools.gui;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextInputControl;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
import net.rptools.gui.listeners.FXMLListener;
import net.rptools.gui.listeners.ResizeListener;

import org.apache.commons.lang3.StringUtils;
import org.rptools.framework.Layer;
import org.rptools.framework.ThreadPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class that does the main GUI construction off of the application thread. The
 * final staging must be done on the application thread, hence the last appendix
 * with runLater.
 */
public class GuiBuilder {
    // Utility
    private static final Logger LOGGER = LoggerFactory.getLogger(GuiBuilder.class);

    // Pattern to match (in pattern asset lists)
    private static final String PATTERN = "pattern";

    // FXML Region reference
    private Region rootRegion;

    // FXML Stage reference
    private Stage rootStage;

    // Component back-reference
    private GuiComponentImpl component;

    // FXML controller
    private FXMLListener fxmlListener;

    // State
    private ScreenLayout layout = new ScreenLayout();

    /**
     * Construct the scene in this contructor and later publish on the
     * application thread.
     * @param parent component back-reference
     */
    public GuiBuilder(final GuiComponentImpl parent) {
        component = parent;
        // Basic initialization
        rootStage = new Stage();
        final FXMLLoader fxmlLoader = new GuiFXMLLoader("main.fxml");
        try {
            rootRegion = (Region) fxmlLoader.load();
        } catch (final IOException e) {
            LOGGER.error("GUI can't be constructed", e);
        }
        fxmlListener = fxmlLoader.getController();
    }

    /** Continued initialization. */
    @ThreadPolicy(ThreadPolicy.ThreadId.JFX)
    public void init() {
        fxmlListener.setComponent(component);
        fillIn();

        // Add input listeners to GUI (filters are first in the chain)
        rootRegion.setFocusTraversable(true);
        rootRegion.addEventHandler(KeyEvent.ANY, component.getKeyInputListener());

        // Listener for window resize
        final ChangeListener<Object> resizeListener = new ResizeListener(component);
        rootRegion.widthProperty().addListener(resizeListener);
        rootRegion.heightProperty().addListener(resizeListener);
        component.getFramework().redraw(null);
        layout.parse(component.getFramework().getState("screen"));
        layout.toStage(rootStage);
    }

    /** Fill in all fields we know of. */
    @ThreadPolicy(ThreadPolicy.ThreadId.JFX)
    private void fillIn() {
        final String server = component.getFramework().getState("server");
        if (server != null) {
            final String[] serverParams = server.split(":");
            ((TextInputControl) component.lookup("#networkServer")).setText(serverParams[0]);
            ((TextInputControl) component.lookup("#networkPort")).setText(serverParams[1]);
        }
        final String login = component.getFramework().getState("login");
        if (login != null) {
            final String[] loginParams = login.split("/");
            ((TextInputControl) component.lookup("#networkUser")).setText(loginParams[0]);
        }
        try {
            ((TextInputControl) component.lookup("#networkLocalIP"))
                    .setText(InetAddress.getLocalHost().getHostAddress().toString());
        } catch (final UnknownHostException e) {
            LOGGER.error("InetAddress.getLocalHost", e);
        }

        component.getFramework().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    final URL url = new URL("http://icanhazip.com/");
                    final URLConnection con = (URLConnection) url.openConnection();

                    try (final BufferedReader in = new BufferedReader(
                            new InputStreamReader(con.getInputStream(), StandardCharsets.US_ASCII))) {
                        final String response = in.readLine();
                        ((TextInputControl) component.lookup("#networkRemoteIP")).setText(response);
                    }
                } catch (final IOException e) {
                    LOGGER.error("No result from http://icanhazip.com/", e);
                }
            }
        });

        AssetConnector.connect("#penTexture", PATTERN, component);
        AssetConnector.connect("#fillTexture", PATTERN, component);
    }

    /** Final GUI show. */
    @ThreadPolicy(ThreadPolicy.ThreadId.MAIN)
    public void showGUI() {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                rootStage.setTitle("Maptool");
                final Scene rootScene = new Scene(rootRegion);
                rootScene.getStylesheets().add(StylesheetMonitor.STYLESHEET);
                rootStage.setScene(rootScene);
                component.setRootScene(rootScene);
                rootStage.show();
                component.stopSplasher();
            }
        });
    }

    /**
     * Create all the layer panes/nodes and signal contruction end to framework.
     * @param layer layers to supply nodes to
     */
    @ThreadPolicy(ThreadPolicy.ThreadId.MAIN)
    public void createLayerPanes(final Layer layer) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                final String selector = "#" + StringUtils.uncapitalize(layer.getName());
                LOGGER.debug("selector={}", selector);
                final Node layerNode = rootRegion.lookup(selector);
                LOGGER.info("rootRegion={}; selector={}; layerNode={}", rootRegion, selector, layerNode);
                if (layerNode != null) {
                    layer.setDrawable((Pane) layerNode);
                }
            }
        });
    }

    /**
     * Getter.
     * @return FXML listener
     */
    @ThreadPolicy(ThreadPolicy.ThreadId.ANY)
    public FXMLListener getFxmlListener() {
        return fxmlListener;
    }

    /**
     * Getter.
     * @return root region
     */
    @ThreadPolicy(ThreadPolicy.ThreadId.JFX)
    public Parent getRootRegion() {
        return rootRegion;
    }

    /**
     * Getter.
     * @return layout as string
     */
    @ThreadPolicy(ThreadPolicy.ThreadId.ANY)
    public synchronized String getLayoutAsString() {
        layout.fromStage(rootStage);
        return layout.toString();
    }
}