package aima.gui.fx.framework; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Optional; import aima.core.util.CancelableThread; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.scene.control.ScrollPane; import javafx.scene.control.TextArea; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.scene.text.Font; import javafx.stage.Stage; /** * Controller class for integrated applications. Integrated applications are * built by the {@link IntegratedAppBuilder} and provide access to * {@link IntegrableApplication} instances and console applications. This * controller class is responsible starting applications, integrating their GUI * into the window of the integrated application, title update, and for scale * property management. * * @author Ruediger Lunde */ public class IntegratedAppPaneCtrl { private BorderPane pane; private Stage stage; private String title; private TextArea messageArea; private ScrollPane messageScrollPane; private MessagePaneCtrl messagePaneCtrl; private DoubleProperty scale = new SimpleDoubleProperty(); private Optional<IntegrableApplication> currApp = Optional.empty(); private Optional<CancelableThread> currDemoThread = Optional.empty(); public IntegratedAppPaneCtrl() { messageArea = new TextArea(); messageArea.setFont(Font.font("monospaced")); messageScrollPane = new ScrollPane(messageArea); messageScrollPane.setFitToWidth(true); messageScrollPane.setFitToHeight(true); messagePaneCtrl = new MessagePaneCtrl(messageArea); scale.set(1.0); } public void setContext(BorderPane pane, Stage stage, String title) { this.pane = pane; this.stage = stage; this.title = title; updateStageTitle(); } public DoubleProperty scaleProperty() { return scale; } public void startApp(Class<? extends IntegrableApplication> appClass) { stopRunningAppsAndDemo(); try { currApp = Optional.of(appClass.newInstance()); Pane appPane = currApp.get().createRootPane(); pane.setCenter(appPane); updateStageTitle(); currApp.get().initialize(); } catch (Exception e) { e.printStackTrace(); } } public void startDemo(Class<?> demoClass) { stopRunningAppsAndDemo(); if (pane.getCenter() != messageScrollPane) pane.setCenter(messageScrollPane); messageArea.clear(); updateStageTitle(); // redirect the standard output into the text area PrintStream pStream = messagePaneCtrl.getPrintStream(); System.setOut(pStream); // System.setErr(messagePaneCtrl.getPrintStream()); currDemoThread = Optional.of(new CancelableThread(() -> { startMain(demoClass); pStream.flush(); })); currDemoThread.get().setDaemon(true); currDemoThread.get().start(); } private void startMain(Class<?> demoClass) { try { Method m = demoClass.getMethod("main", String[].class); m.invoke(null, (Object) new String[] {}); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { e.printStackTrace(); } } private void stopRunningAppsAndDemo() { if (currApp.isPresent()) { currApp.get().cleanup(); currApp = Optional.empty(); } if (currDemoThread.isPresent()) { currDemoThread.get().cancel(); currDemoThread = Optional.empty(); } } /** * Updates the window title using the title of the integrated application * and the current embedded application (if any). */ private void updateStageTitle() { stage.setTitle(title + (currApp.isPresent() ? " - " + currApp.get().getTitle() : "")); } }