You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by jt...@apache.org on 2017/09/03 12:48:56 UTC
[23/24] incubator-netbeans-html4j git commit: [INFRA-15006] Initial
donation of HTML/Java NetBeans API. Equivalent to the content of
html4j-donation-review.zip donated as part of ApacheNetBeansDonation1.zip
with SHA256 being 7f2ca0f61953a190613c9a0fbcc1b
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
new file mode 100644
index 0000000..71c8547
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
@@ -0,0 +1,427 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.boot.fx;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.prefs.Preferences;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.concurrent.Worker;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.geometry.Rectangle2D;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.scene.web.PromptData;
+import javafx.scene.web.WebEvent;
+import javafx.scene.web.WebView;
+import javafx.stage.Modality;
+import javafx.stage.Screen;
+import javafx.stage.Stage;
+import javafx.stage.Window;
+import javafx.stage.WindowEvent;
+import javafx.util.Callback;
+
+/** This is an implementation class, to implement browser builder API. Just
+ * include this JAR on classpath and the browser builder API will find
+ * this implementation automatically.
+ */
+public class FXBrwsr extends Application {
+ private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName());
+ private static FXBrwsr INSTANCE;
+ private static final CountDownLatch FINISHED = new CountDownLatch(1);
+ private BorderPane root;
+
+ public static synchronized WebView findWebView(final URL url, final FXPresenter onLoad) {
+ if (INSTANCE == null) {
+ final String callee = findCalleeClassName();
+ Executors.newFixedThreadPool(1).submit(new Runnable() {
+ @Override
+ public void run() {
+ if (!Platform.isFxApplicationThread()) {
+ try {
+ Platform.runLater(this);
+ } catch (IllegalStateException ex) {
+ try {
+ FXBrwsr.launch(FXBrwsr.class, callee);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ } finally {
+ FINISHED.countDown();
+ }
+ }
+ } else {
+ FXBrwsr brwsr = new FXBrwsr();
+ brwsr.start(new Stage(), callee);
+ INSTANCE = brwsr;
+ FINISHED.countDown();
+ }
+ }
+ });
+ }
+ while (INSTANCE == null) {
+ try {
+ FXBrwsr.class.wait();
+ } catch (InterruptedException ex) {
+ // wait more
+ }
+ }
+ if (!Platform.isFxApplicationThread()) {
+ final WebView[] arr = {null};
+ final CountDownLatch waitForResult = new CountDownLatch(1);
+ Platform.runLater(new Runnable() {
+ @Override
+ public void run() {
+ arr[0] = INSTANCE.newView(url, onLoad);
+ waitForResult.countDown();
+ }
+ });
+ for (;;) {
+ try {
+ waitForResult.await();
+ break;
+ } catch (InterruptedException ex) {
+ LOG.log(Level.INFO, null, ex);
+ }
+ }
+ return arr[0];
+ } else {
+ return INSTANCE.newView(url, onLoad);
+ }
+ }
+
+ static synchronized Stage findStage() throws InterruptedException {
+ while (INSTANCE == null) {
+ FXBrwsr.class.wait();
+ }
+ return INSTANCE.stage;
+ }
+
+ private Stage stage;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ start(primaryStage, this.getParameters().getRaw().get(0));
+ }
+
+ final void start(Stage primaryStage, String callee) {
+ BorderPane r = new BorderPane();
+ Object[] arr = findInitialSize(callee);
+ Scene scene = new Scene(r, (Double)arr[2], (Double)arr[3]);
+ primaryStage.setScene(scene);
+ this.root = r;
+ this.stage = primaryStage;
+ synchronized (FXBrwsr.class) {
+ INSTANCE = this;
+ FXBrwsr.class.notifyAll();
+ }
+ primaryStage.setX((Double)arr[0]);
+ primaryStage.setY((Double)arr[1]);
+ if (arr[4] != null) {
+ scene.getWindow().setOnCloseRequest((EventHandler<WindowEvent>) arr[4]);
+ }
+ if (Boolean.getBoolean("fxpresenter.headless")) {
+ return;
+ }
+ primaryStage.show();
+ }
+
+ static String findCalleeClassName() {
+ StackTraceElement[] frames = new Exception().getStackTrace();
+ for (StackTraceElement e : frames) {
+ String cn = e.getClassName();
+ if (cn.startsWith("org.netbeans.html.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("net.java.html.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("java.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("javafx.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("com.sun.")) { // NOI18N
+ continue;
+ }
+ return cn;
+ }
+ return "org.netbeans.html"; // NOI18N
+ }
+
+ private static Object[] findInitialSize(String callee) {
+ final Preferences prefs = Preferences.userRoot().node(callee.replace('.', '/'));
+ Rectangle2D screen = Screen.getPrimary().getBounds();
+ double x = prefs.getDouble("x", screen.getWidth() * 0.05); // NOI18N
+ double y = prefs.getDouble("y", screen.getHeight() * 0.05); // NOI18N
+ double width = prefs.getDouble("width", screen.getWidth() * 0.9); // NOI18N
+ double height = prefs.getDouble("height", screen.getHeight() * 0.9); // NOI18N
+
+ Object[] arr = {
+ x, y, width, height, null
+ };
+
+ if (!callee.equals("org.netbeans.html")) { // NOI18N
+ arr[4] = new EventHandler<WindowEvent>() {
+ @Override
+ public void handle(WindowEvent event) {
+ Window window = (Window) event.getSource();
+ prefs.putDouble("x", window.getX()); // NOI18N
+ prefs.putDouble("y", window.getY()); // NOI18N
+ prefs.putDouble("width", window.getWidth()); // NOI18N
+ prefs.putDouble("height", window.getHeight()); // NOI18N
+ }
+ };
+ }
+
+ return arr;
+ }
+
+ private WebView newView(final URL url, final FXPresenter onLoad) {
+ final WebView view = new WebView();
+ view.setContextMenuEnabled(false);
+ Stage newStage;
+ BorderPane bp;
+ if (root == null) {
+ newStage = new Stage();
+ newStage.initOwner(stage);
+ bp = new BorderPane();
+ newStage.setScene(new Scene(bp));
+ newStage.show();
+ } else {
+ bp = root;
+ newStage = stage;
+ root = null;
+ }
+
+ attachHandlers(view, newStage);
+ bp.setCenter(view);
+ final Worker<Void> w = view.getEngine().getLoadWorker();
+ w.stateProperty().addListener(new ChangeListener<Worker.State>() {
+ private String previous;
+
+ @Override
+ public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State newState) {
+ if (newState.equals(Worker.State.SUCCEEDED)) {
+ if (checkValid()) {
+ FXConsole.register(view.getEngine());
+ onLoad.onPageLoad();
+ }
+ }
+ if (newState.equals(Worker.State.FAILED)) {
+ throw new IllegalStateException("Failed to load " + url);
+ }
+ }
+ private boolean checkValid() {
+ final String crnt = view.getEngine().getLocation();
+ if (previous != null && !previous.equals(crnt)) {
+ w.stateProperty().removeListener(this);
+ return false;
+ }
+ previous = crnt;
+ return true;
+ }
+
+ });
+ class Title implements ChangeListener<String> {
+
+ private String title;
+
+ public Title() {
+ super();
+ }
+
+ @Override
+ public void changed(ObservableValue<? extends String> ov, String t, String t1) {
+ title = view.getEngine().getTitle();
+ if (title != null) {
+ stage.setTitle(title);
+ }
+ }
+ }
+ final Title x = new Title();
+ view.getEngine().titleProperty().addListener(x);
+ x.changed(null, null, null);
+ return view;
+ }
+
+ private static void attachHandlers(final WebView view, final Stage owner) {
+ view.getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
+ @Override
+ public void handle(WebEvent<String> t) {
+ final Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.WINDOW_MODAL);
+ dialogStage.initOwner(owner);
+ ResourceBundle r = ResourceBundle.getBundle("org/netbeans/html/boot/fx/Bundle"); // NOI18N
+ dialogStage.setTitle(r.getString("AlertTitle")); // NOI18N
+ final Button button = new Button(r.getString("AlertCloseButton")); // NOI18N
+ final Text text = new Text(t.getData());
+ VBox box = new VBox();
+ box.setAlignment(Pos.CENTER);
+ box.setSpacing(10);
+ box.setPadding(new Insets(10));
+ box.getChildren().addAll(text, button);
+ dialogStage.setScene(new Scene(box));
+ button.setCancelButton(true);
+ button.setOnAction(new CloseDialogHandler(dialogStage, null));
+ dialogStage.centerOnScreen();
+ dialogStage.showAndWait();
+ }
+ });
+ view.getEngine().setConfirmHandler(new Callback<String, Boolean>() {
+ @Override
+ public Boolean call(String question) {
+ final Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.WINDOW_MODAL);
+ dialogStage.initOwner(owner);
+ ResourceBundle r = ResourceBundle.getBundle("org/netbeans/html/boot/fx/Bundle"); // NOI18N
+ dialogStage.setTitle(r.getString("ConfirmTitle")); // NOI18N
+ final Button ok = new Button(r.getString("ConfirmOKButton")); // NOI18N
+ final Button cancel = new Button(r.getString("ConfirmCancelButton")); // NOI18N
+ final Text text = new Text(question);
+ final Insets ins = new Insets(10);
+ final VBox box = new VBox();
+ box.setAlignment(Pos.CENTER);
+ box.setSpacing(10);
+ box.setPadding(ins);
+ final HBox buttons = new HBox(10);
+ buttons.getChildren().addAll(ok, cancel);
+ buttons.setAlignment(Pos.CENTER);
+ buttons.setPadding(ins);
+ box.getChildren().addAll(text, buttons);
+ dialogStage.setScene(new Scene(box));
+ ok.setCancelButton(false);
+
+ final boolean[] res = new boolean[1];
+ ok.setOnAction(new CloseDialogHandler(dialogStage, res));
+ cancel.setCancelButton(true);
+ cancel.setOnAction(new CloseDialogHandler(dialogStage, null));
+ dialogStage.centerOnScreen();
+ dialogStage.showAndWait();
+ return res[0];
+ }
+ });
+ view.getEngine().setPromptHandler(new Callback<PromptData, String>() {
+ @Override
+ public String call(PromptData prompt) {
+ final Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.WINDOW_MODAL);
+ dialogStage.initOwner(owner);
+ ResourceBundle r = ResourceBundle.getBundle("org/netbeans/html/boot/fx/Bundle"); // NOI18N
+ dialogStage.setTitle(r.getString("PromptTitle")); // NOI18N
+ final Button ok = new Button(r.getString("PromptOKButton")); // NOI18N
+ final Button cancel = new Button(r.getString("PromptCancelButton")); // NOI18N
+ final Text text = new Text(prompt.getMessage());
+ final TextField line = new TextField();
+ if (prompt.getDefaultValue() != null) {
+ line.setText(prompt.getDefaultValue());
+ }
+ final Insets ins = new Insets(10);
+ final VBox box = new VBox();
+ box.setAlignment(Pos.CENTER);
+ box.setSpacing(10);
+ box.setPadding(ins);
+ final HBox buttons = new HBox(10);
+ buttons.getChildren().addAll(ok, cancel);
+ buttons.setAlignment(Pos.CENTER);
+ buttons.setPadding(ins);
+ box.getChildren().addAll(text, line, buttons);
+ dialogStage.setScene(new Scene(box));
+ ok.setCancelButton(false);
+
+ final boolean[] res = new boolean[1];
+ ok.setOnAction(new CloseDialogHandler(dialogStage, res));
+ cancel.setCancelButton(true);
+ cancel.setOnAction(new CloseDialogHandler(dialogStage, null));
+ dialogStage.centerOnScreen();
+ dialogStage.showAndWait();
+ return res[0] ? line.getText() : null;
+ }
+ });
+ }
+
+ static void waitFinished() {
+ for (;;) {
+ try {
+ FINISHED.await();
+ break;
+ } catch (InterruptedException ex) {
+ LOG.log(Level.INFO, null, ex);
+ }
+ }
+ }
+
+ private static final class CloseDialogHandler implements EventHandler<ActionEvent> {
+ private final Stage dialogStage;
+ private final boolean[] res;
+
+ public CloseDialogHandler(Stage dialogStage, boolean[] res) {
+ this.dialogStage = dialogStage;
+ this.res = res;
+ }
+
+ @Override
+ public void handle(ActionEvent t) {
+ dialogStage.close();
+ if (res != null) {
+ res[0] = true;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java
new file mode 100644
index 0000000..d176ede
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java
@@ -0,0 +1,84 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.boot.fx;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.scene.web.WebEngine;
+import netscape.javascript.JSObject;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official browser builder API
+ * to access the functionality.
+ * <p>
+ * Redirects JavaScript's messages to Java's {@link Logger}.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class FXConsole {
+ static final Logger LOG = Logger.getLogger(FXConsole.class.getName());
+
+ private FXConsole() {
+ }
+
+ static void register(WebEngine eng) {
+ JSObject fn = (JSObject) eng.executeScript(""
+ + "(function(attr, l, c) {"
+ + " window.console[attr] = function(msg) { c.log(l, msg); };"
+ + "})"
+ );
+ FXConsole c = new FXConsole();
+ c.registerImpl(fn, "log", Level.INFO);
+ c.registerImpl(fn, "info", Level.INFO);
+ c.registerImpl(fn, "warn", Level.WARNING);
+ c.registerImpl(fn, "error", Level.SEVERE);
+ }
+
+ private void registerImpl(JSObject eng, String attr, Level l) {
+ eng.call("call", null, attr, l, this);
+ }
+
+ public void log(Level l, String msg) {
+ LOG.log(l, msg);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
new file mode 100644
index 0000000..2c8bc4f
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
@@ -0,0 +1,134 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.boot.fx;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.application.Platform;
+import javafx.scene.web.WebEngine;
+import javafx.util.Callback;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class FXInspect implements Runnable {
+ static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
+
+
+ private final WebEngine engine;
+ private final ObjectInputStream input;
+ private Dbgr dbg;
+
+ private FXInspect(WebEngine engine, int port) throws IOException {
+ this.engine = engine;
+
+ Socket socket = new Socket(InetAddress.getByName(null), port);
+ ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
+ this.input = new ObjectInputStream(socket.getInputStream());
+ initializeDebugger(output);
+ }
+
+ static boolean initialize(WebEngine engine) {
+ final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N
+ if (inspectPort != -1) {
+ try {
+ FXInspect inspector = new FXInspect(engine, inspectPort);
+ Thread t = new Thread(inspector, "FX<->NetBeans Inspector");
+ t.start();
+ return true;
+ } catch (IOException ex) {
+ LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N
+ }
+ }
+ return false;
+ }
+
+ private void initializeDebugger(final ObjectOutputStream output) {
+ Platform.runLater(new Runnable() {
+ @Override
+ public void run() {
+ dbg = new Dbgr(engine, new Callback<String,Void>() {
+ @Override
+ public Void call(String message) {
+ try {
+ byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
+ output.writeInt(bytes.length);
+ output.write(bytes);
+ output.flush();
+ } catch (IOException ioex) {
+ ioex.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ int length = input.readInt();
+ byte[] bytes = new byte[length];
+ input.readFully(bytes);
+ final String message = new String(bytes, StandardCharsets.UTF_8);
+ Platform.runLater(new Runnable() {
+ @Override
+ public void run() {
+ dbg.sendMessage(message);
+ }
+ });
+ }
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, null, ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
new file mode 100644
index 0000000..c54a1a1
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
@@ -0,0 +1,88 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.boot.fx;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import javafx.scene.web.WebView;
+import net.java.html.boot.BrowserBuilder;
+import org.netbeans.html.boot.spi.Fn;
+import org.openide.util.lookup.ServiceProvider;
+
+/** This is an implementation class, use {@link BrowserBuilder} API. Just
+ * include this JAR on classpath and the {@link BrowserBuilder} API will find
+ * this implementation automatically.
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = Fn.Presenter.class)
+public final class FXPresenter extends AbstractFXPresenter {
+ static {
+ try {
+ try {
+ Class<?> c = Class.forName("javafx.application.Platform");
+ // OK, on classpath
+ } catch (ClassNotFoundException classNotFoundException) {
+ Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+ m.setAccessible(true);
+ File f = new File(System.getProperty("java.home"), "lib/jfxrt.jar");
+ if (f.exists()) {
+ URL l = f.toURI().toURL();
+ m.invoke(ClassLoader.getSystemClassLoader(), l);
+ }
+ }
+ } catch (Exception ex) {
+ throw new LinkageError("Can't add jfxrt.jar on the classpath", ex);
+ }
+ }
+
+ protected void waitFinished() {
+ FXBrwsr.waitFinished();
+ }
+
+ protected WebView findView(final URL resource) {
+ return FXBrwsr.findWebView(resource, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java
new file mode 100644
index 0000000..20d4e10
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java
@@ -0,0 +1,437 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.boot.fx;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.prefs.Preferences;
+import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Separator;
+import javafx.scene.control.Toggle;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.control.ToolBar;
+import javafx.scene.control.Tooltip;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebEngine;
+import javafx.scene.web.WebView;
+import javafx.stage.Screen;
+import javafx.stage.Stage;
+import javafx.stage.Window;
+
+final class FXToolbar extends ToolBar {
+ private final ArrayList<ResizeBtn> resizeButtons;
+ private final WebView webView;
+ private final BorderPane container;
+ private final ToggleGroup resizeGroup = new ToggleGroup();
+ private final ComboBox<String> comboZoom = new ComboBox<String>();
+ private WatchDir watcher;
+
+ FXToolbar(WebView wv, BorderPane container, boolean enableFirebug) {
+ this.webView = wv;
+ this.container = container;
+
+ List<ResizeOption> options = ResizeOption.loadAll();
+ options.add( 0, ResizeOption.SIZE_TO_FIT );
+ resizeButtons = new ArrayList<ResizeBtn>( options.size() );
+
+ for( ResizeOption ro : options ) {
+ ResizeBtn button = new ResizeBtn(ro);
+ resizeButtons.add( button );
+ resizeGroup.getToggles().add( button );
+ getItems().add( button );
+ }
+ resizeButtons.get( 0 ).setSelected( true );
+ resizeGroup.selectedToggleProperty().addListener( new InvalidationListener() {
+
+ @Override
+ public void invalidated( Observable o ) {
+ resize();
+ }
+ });
+
+ getItems().add( new Separator() );
+
+ getItems().add( comboZoom );
+ ArrayList<String> zoomModel = new ArrayList<String>( 6 );
+ zoomModel.add( "200%" ); //NOI18N
+ zoomModel.add( "150%" ); //NOI18N
+ zoomModel.add( "100%" ); //NOI18N
+ zoomModel.add( "75%" ); //NOI18N
+ zoomModel.add( "50%" ); //NOI18N
+ comboZoom.setItems( FXCollections.observableList( zoomModel ) );
+ comboZoom.setEditable( true );
+ comboZoom.setValue( "100%" ); //NOI18N
+ comboZoom.valueProperty().addListener( new ChangeListener<String>() {
+
+ @Override
+ public void changed( ObservableValue<? extends String> ov, String t, String t1 ) {
+ String newZoom = zoom( t1 );
+ comboZoom.setValue( newZoom );
+ }
+ });
+
+ getItems().add(new Separator());
+ final CheckBox automatic = new CheckBox("Automatic");
+ final Preferences prefs = Preferences.userNodeForPackage(FXToolbar.class);
+ final String ar = "automaticReload"; // NOI18N
+ automatic.setSelected(prefs.getBoolean(ar, true));
+ getItems().add(automatic);
+ final Button reload = new Button("Reload");
+ getItems().add(reload);
+ reload.setOnAction(new EventHandler<ActionEvent>() {
+ @Override
+ public void handle(ActionEvent event) {
+ webView.getEngine().reload();
+ }
+ });
+ automatic.setOnAction(new EventHandler<ActionEvent>() {
+ @Override
+ public void handle(ActionEvent event) {
+ prefs.putBoolean(ar, automatic.isSelected());
+ listenOnChanges(automatic.isSelected());
+ }
+ });
+ webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
+ listenOnChanges(automatic.isSelected());
+ }
+ });
+ if (enableFirebug){
+ final Button firebug = new Button("Firebug");
+ getItems().add(firebug);
+ firebug.setOnAction(new EventHandler<ActionEvent>() {
+
+ @Override
+ public void handle(ActionEvent event) {
+ enableFirebug(webView.getEngine());
+ firebug.setDisable(true);
+ }
+ });}
+ }
+
+ private String zoom( String zoomFactor ) {
+ if( zoomFactor.trim().isEmpty() )
+ return null;
+
+ try {
+ zoomFactor = zoomFactor.replaceAll( "\\%", ""); //NOI18N
+ zoomFactor = zoomFactor.trim();
+ double zoom = Double.parseDouble( zoomFactor );
+ zoom = Math.abs( zoom )/100;
+ if( zoom <= 0.0 )
+ return null;
+ webView.setScaleX(zoom);
+ webView.setScaleY(zoom);
+ webView.setScaleZ(zoom);
+ return (int)(100*zoom) + "%"; //NOI18N
+ } catch( NumberFormatException nfe ) {
+ //ignore
+ }
+ return null;
+ }
+
+ private void resize() {
+ Toggle selection = resizeGroup.getSelectedToggle();
+ if( selection instanceof ResizeBtn ) {
+ ResizeOption ro = ((ResizeBtn)selection).getResizeOption();
+ if( ro == ResizeOption.SIZE_TO_FIT ) {
+ _autofit();
+ } else {
+ _resize( ro.getWidth(), ro.getHeight() );
+ }
+ }
+
+ }
+
+ private void _resize(final double width, final double height) {
+ Window window = container.getScene().getWindow();
+ // size difference between root node and window depends on OS and Decorations
+ double diffY = window.getHeight() - container.getHeight();
+ double diffX = window.getWidth() - container.getWidth();
+
+ webView.setMaxWidth(width);
+ webView.setMaxHeight(height);
+ webView.setMinWidth(width);
+ webView.setMinHeight(height);
+ javafx.geometry.Rectangle2D screenBounds = Screen.getPrimary().getBounds();
+ double scaleX = screenBounds.getWidth() / ( width + diffX );
+ double scaleY = screenBounds.getHeight() / ( height + diffY );
+ // calculate scale factor if too big for device, the .1 adds some padding
+ double scale = Math.min(Math.min(scaleX, scaleY), 1.1) - .1;
+ webView.setScaleX(scale);
+ webView.setScaleY(scale);
+ container.getScene().setRoot(new Group());
+ ((Stage)window).setScene(new Scene(container, width * scale, height * scale));
+ }
+
+ private void _autofit() {
+ if (container.getCenter() != webView) {
+ container.setCenter(webView);
+ }
+ webView.setMaxWidth( Integer.MAX_VALUE );
+ webView.setMaxHeight( Integer.MAX_VALUE );
+ webView.setMinWidth( -1 );
+ webView.setMinHeight( -1 );
+ webView.autosize();
+ }
+
+ /**
+ * Button to resize the browser window.
+ * Taken from NetBeans. Kept GPLwithCPEx license.
+ * Portions Copyright 2012 Oracle.
+ *
+ * @author S. Aubrecht
+ */
+ static final class ResizeBtn extends ToggleButton {
+
+ private final ResizeOption resizeOption;
+
+ ResizeBtn(ResizeOption resizeOption) {
+ super(null, new ImageView(toImage(resizeOption)));
+ this.resizeOption = resizeOption;
+ setTooltip(new Tooltip(resizeOption.getToolTip()));
+ }
+
+ ResizeOption getResizeOption() {
+ return resizeOption;
+ }
+
+ static Image toImage(ResizeOption ro) {
+ if (ro == ResizeOption.SIZE_TO_FIT) {
+ return ResizeOption.Type.CUSTOM.getImage();
+ }
+ return ro.getType().getImage();
+ }
+ }
+
+ /**
+ * Immutable value class describing a single button to resize web browser window.
+ * Taken from NetBeans. Kept GPLwithCPEx license.
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ *
+ * @author S. Aubrecht
+ */
+ static final class ResizeOption {
+
+ private final Type type;
+ private final String displayName;
+ private final int width;
+ private final int height;
+ private final boolean isDefault;
+
+ enum Type {
+ DESKTOP("desktop.png"),
+ TABLET_PORTRAIT("tabletPortrait.png"),
+ TABLET_LANDSCAPE("tabletLandscape.png"),
+ SMARTPHONE_PORTRAIT("handheldPortrait.png"),
+ SMARTPHONE_LANDSCAPE("handheldLandscape.png"),
+ WIDESCREEN("widescreen.png"),
+ NETBOOK("netbook.png"),
+ CUSTOM("sizeToFit.png");
+
+
+ private final String resource;
+
+ private Type(String r) {
+ resource = r;
+ }
+
+ public Image getImage() {
+ return new Image(Type.class.getResourceAsStream(resource));
+ }
+ }
+
+ private ResizeOption(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
+ super();
+ this.type = type;
+ this.displayName = displayName;
+ this.width = width;
+ this.height = height;
+ this.isDefault = isDefault;
+ }
+
+ static List<ResizeOption> loadAll() {
+ List<ResizeOption> res = new ArrayList<ResizeOption>(10);
+ res.add(ResizeOption.create(ResizeOption.Type.DESKTOP, "Desktop", 1280, 1024, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.TABLET_LANDSCAPE, "Tablet Landscape", 1024, 768, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.TABLET_PORTRAIT, "Tablet Portrait", 768, 1024, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_LANDSCAPE, "Smartphone Landscape", 480, 320, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_PORTRAIT, "Smartphone Portrait", 320, 480, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.WIDESCREEN, "Widescreen", 1680, 1050, false, true));
+ res.add(ResizeOption.create(ResizeOption.Type.NETBOOK, "Netbook", 1024, 600, false, true));
+ return res;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param type
+ * @param displayName Display name to show in tooltip, cannot be empty.
+ * @param width Screen width
+ * @param height Screen height
+ * @param showInToolbar True to show in web developer toolbar.
+ * @param isDefault True if this is a predefined option that cannot be removed.
+ * @return New instance.
+ */
+ public static ResizeOption create(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException("Invalid screen dimensions: " + width + " x " + height); //NOI18N
+ }
+ return new ResizeOption(type, displayName, width, height, showInToolbar, isDefault);
+ }
+ /**
+ * An extra option to size the browser content to fit its window.
+ */
+ public static final ResizeOption SIZE_TO_FIT = new ResizeOption(Type.CUSTOM, "Size To Fit", -1, -1, true, true);
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public boolean isDefault() {
+ return isDefault;
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+
+ public String getToolTip() {
+ if (width < 0 || height < 0) {
+ return displayName;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(width);
+ sb.append(" x "); //NOI18N
+ sb.append(height);
+ sb.append(" ("); //NOI18N
+ sb.append(displayName);
+ sb.append(')'); //NOI18N
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ResizeOption other = (ResizeOption) obj;
+ if (this.type != other.type) {
+ return false;
+ }
+ if ((this.displayName == null) ? (other.displayName != null) : !this.displayName.equals(other.displayName)) {
+ return false;
+ }
+ if (this.width != other.width) {
+ return false;
+ }
+ if (this.height != other.height) {
+ return false;
+ }
+ if (this.isDefault != other.isDefault) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0);
+ hash = 11 * hash + (this.displayName != null ? this.displayName.hashCode() : 0);
+ hash = 11 * hash + this.width;
+ hash = 11 * hash + this.height;
+ hash = 11 * hash + (this.isDefault ? 1 : 0);
+ return hash;
+ }
+ }
+
+ private void listenOnChanges(boolean turnOn) {
+ try {
+ if (watcher != null) {
+ watcher.close();
+ watcher = null;
+ }
+ final WebEngine eng = webView.getEngine();
+ if (turnOn && eng.getLocation().startsWith("file:")) { // NOI18N
+ watcher = new WatchDir(eng);
+ }
+ } catch (Exception ex) {
+ FXInspect.LOG.log(Level.SEVERE, null, ex);
+ }
+ }
+ private static void enableFirebug(final WebEngine engine) {
+ engine.executeScript("if (!document.getElementById('FirebugLite')){E = document['createElement' + 'NS'] && document.documentElement.namespaceURI;E = E ? document['createElement' + 'NS'](E, 'script') : document['createElement']('script');E['setAttribute']('id', 'FirebugLite');E['setAttribute']('src', 'https://getfirebug.com/' + 'firebug-lite.js' + '#startOpened');E['setAttribute']('FirebugLite', '4');(document['getElementsByTagName']('head')[0] || document['getElementsByTagName']('body')[0]).appendChild(E);E = new Image;E['setAttribute']('src', 'https://getfirebug.com/' + '#startOpened');}");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java
new file mode 100644
index 0000000..25cc5f2
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java
@@ -0,0 +1,117 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.boot.fx;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.application.Platform;
+import javafx.scene.web.WebEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class WatchDir implements Runnable {
+ private final Path dir;
+ private final WatchKey key;
+ private final WatchService ws;
+ private final Thread watcher;
+ private final WebEngine engine;
+
+ WatchDir(WebEngine eng) throws URISyntaxException, IOException {
+ dir = Paths.get(new URI(eng.getLocation())).getParent();
+ engine = eng;
+ ws = dir.getFileSystem().newWatchService();
+ key = dir.register(ws,
+ StandardWatchEventKinds.ENTRY_CREATE,
+ StandardWatchEventKinds.ENTRY_DELETE,
+ StandardWatchEventKinds.ENTRY_MODIFY
+ );
+ watcher = new Thread(this, "Watching files in " + dir);
+ watcher.setDaemon(true);
+ watcher.setPriority(Thread.MIN_PRIORITY);
+ watcher.start();
+ }
+
+ public void close() throws IOException {
+ key.cancel();
+ ws.close();
+ watcher.interrupt();
+ }
+
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ engine.reload();
+ return;
+ }
+ try {
+ while (key.isValid()) {
+ WatchKey changed;
+ try {
+ changed = ws.take();
+ if (changed != key || changed.pollEvents().isEmpty()) {
+ continue;
+ }
+ } catch (ClosedWatchServiceException ex) {
+ continue;
+ }
+ Platform.runLater(this);
+ if (!key.reset()) {
+ break;
+ }
+ }
+ } catch (InterruptedException ex) {
+ FXInspect.LOG.log(Level.SEVERE, null, ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties
new file mode 100644
index 0000000..7ebe82d
--- /dev/null
+++ b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties
@@ -0,0 +1,54 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+#
+# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+# Other names may be trademarks of their respective owners.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common
+# Development and Distribution License("CDDL") (collectively, the
+# "License"). You may not use this file except in compliance with the
+# License. You can obtain a copy of the License at
+# http://www.netbeans.org/cddl-gplv2.html
+# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+# specific language governing permissions and limitations under the
+# License. When distributing the software, include this License Header
+# Notice in each file and include the License file at
+# nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the GPL Version 2 section of the License file that
+# accompanied this code. If applicable, add the following below the
+# License Header, with the fields enclosed by brackets [] replaced by
+# your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# Contributor(s):
+#
+# The Original Software is NetBeans. The Initial Developer of the Original
+# Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+#
+# If you wish your version of this file to be governed by only the CDDL
+# or only the GPL Version 2, indicate your decision by adding
+# "[Contributor] elects to include this software in this distribution
+# under the [CDDL or GPL Version 2] license." If you do not indicate a
+# single choice of license, a recipient has the option to distribute
+# your version of this file under either the CDDL, the GPL Version 2 or
+# to extend the choice of license to its licensees as provided above.
+# However, if you add GPL Version 2 code and therefore, elected the GPL
+# Version 2 license, then the option applies only if the new code is
+# made subject to such option by the copyright holder.
+#
+
+AlertTitle=Warning
+AlertCloseButton=Close
+
+ConfirmTitle=Question
+ConfirmOKButton=OK
+ConfirmCancelButton=Cancel
+
+PromptTitle=Question
+PromptOKButton=OK
+PromptCancelButton=Cancel
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png
new file mode 100644
index 0000000..b295e4b
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png
new file mode 100644
index 0000000..ce5d64e
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png
new file mode 100644
index 0000000..686bea8
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png
new file mode 100644
index 0000000..53838ba
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png
new file mode 100644
index 0000000..d2e398c
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png
new file mode 100644
index 0000000..5fec5a4
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png
new file mode 100644
index 0000000..89f7f61
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png
new file mode 100644
index 0000000..fb94771
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png
new file mode 100644
index 0000000..933e01f
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
new file mode 100644
index 0000000..1400ad8
--- /dev/null
+++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
@@ -0,0 +1,209 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package net.java.html.boot.fx;
+
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebView;
+import javafx.stage.Stage;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class FXBrowsersOnResourceTest {
+
+ public FXBrowsersOnResourceTest() {
+ }
+
+ @BeforeClass public void initFX() throws Throwable {
+ new Thread("initFX") {
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ new App().start(new Stage());
+ } else {
+ try {
+ App.launch(App.class);
+ } catch (IllegalStateException ex) {
+ Platform.runLater(this);
+ }
+ }
+ }
+ }.start();
+ App.CDL.await();
+ }
+
+ @Test
+ public void behaviorOfTwoWebViewsAtOnce() throws Throwable {
+ class R implements Runnable {
+ CountDownLatch DONE = new CountDownLatch(1);
+ Throwable t;
+
+ @Override
+ public void run() {
+ try {
+ doTest();
+ } catch (Throwable ex) {
+ t = ex;
+ } finally {
+ DONE.countDown();
+ }
+ }
+
+ private void doTest() throws Throwable {
+ URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV1(), u, OnPages.class, "first");
+
+ }
+ }
+ R run = new R();
+ Platform.runLater(run);
+ run.DONE.await();
+ for (int i = 0; i < 100; i++) {
+ if (run.t != null) {
+ throw run.t;
+ }
+ if (System.getProperty("finalSecond") == null) {
+ Thread.sleep(100);
+ }
+ }
+
+
+
+ assertEquals(Integer.getInteger("finalFirst"), Integer.valueOf(3), "Three times in view one");
+ assertEquals(Integer.getInteger("finalSecond"), Integer.valueOf(2), "Two times in view one");
+ }
+
+ @JavaScriptResource("wnd.js")
+ public static class OnPages {
+ static Class<?> first;
+ static Object firstWindow;
+
+ public static void first() {
+ first = OnPages.class;
+ firstWindow = window();
+ assertNotNull(firstWindow, "First window found");
+
+ assertEquals(increment(), 1, "Now it is one");
+
+ URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV2(), u, OnPages.class, "second", "Hello");
+
+ assertEquals(increment(), 2, "Now it is two and not influenced by second view");
+ System.setProperty("finalFirst", "" + increment());
+ }
+
+ public static void second(String... args) {
+ assertEquals(args.length, 1, "One string argument");
+ assertEquals(args[0], "Hello", "It is hello");
+ assertEquals(first, OnPages.class, "Both views share the same classloader");
+
+ Object window = window();
+ assertNotNull(window, "Some window found");
+ assertNotNull(firstWindow, "First window is known");
+ assertNotSame(firstWindow, window, "The window objects should be different");
+
+ assertEquals(increment(), 1, "Counting starts from zero");
+ System.setProperty("finalSecond", "" + increment());
+ }
+
+ @JavaScriptBody(args = {}, body = "return wnd;")
+ private static native Object window();
+
+ @JavaScriptBody(args = {}, body = ""
+ + "if (wnd.cnt) return ++wnd.cnt;"
+ + "return wnd.cnt = 1;"
+ )
+ private static native int increment();
+ }
+
+ public static class App extends Application {
+ static final CountDownLatch CDL = new CountDownLatch(1);
+ private static BorderPane pane;
+
+ /**
+ * @return the v1
+ */
+ static WebView getV1() {
+ return (WebView)System.getProperties().get("v1");
+ }
+
+ /**
+ * @return the v2
+ */
+ static WebView getV2() {
+ return (WebView)System.getProperties().get("v2");
+ }
+
+ @Override
+ public void start(Stage stage) {
+ pane= new BorderPane();
+ Scene scene = new Scene(pane, 800, 600);
+ stage.setScene(scene);
+
+ System.getProperties().put("v1", new WebView());
+ System.getProperties().put("v2", new WebView());
+
+ pane.setCenter(getV1());
+ pane.setBottom(getV2());
+
+ CDL.countDown();
+ }
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java
new file mode 100644
index 0000000..2498c56
--- /dev/null
+++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java
@@ -0,0 +1,253 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package net.java.html.boot.fx;
+
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebView;
+import javafx.stage.Stage;
+import net.java.html.BrwsrCtx;
+import net.java.html.js.JavaScriptBody;
+import static org.testng.Assert.*;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class FXBrowsersTest {
+ private static CountDownLatch PROPERTY_SET;
+
+ public FXBrowsersTest() {
+ }
+
+ @BeforeClass public void initFX() throws Throwable {
+ new Thread("initFX") {
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ new App().start(new Stage());
+ } else {
+ try {
+ App.launch(App.class);
+ } catch (IllegalStateException ex) {
+ Platform.runLater(this);
+ }
+ }
+ }
+ }.start();
+ App.CDL.await();
+ }
+
+ @JavaScriptBody(args = { }, body = "return true;")
+ static boolean inJS() {
+ return false;
+ }
+
+ @Test
+ public void brwsrCtxExecute() throws Throwable {
+ assertFalse(inJS(), "We aren't in JS now");
+ final CountDownLatch init = new CountDownLatch(1);
+ final BrwsrCtx[] ctx = { null };
+ FXBrowsers.runInBrowser(App.getV1(), new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(inJS(), "We are in JS context now");
+ ctx[0] = BrwsrCtx.findDefault(FXBrowsersTest.class);
+ init.countDown();
+ }
+ });
+ init.await();
+
+ final CountDownLatch cdl = new CountDownLatch(1);
+ class R implements Runnable {
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ assertTrue(inJS());
+ cdl.countDown();
+ } else {
+ ctx[0].execute(this);
+ }
+ }
+ }
+ new Thread(new R(), "Background thread").start();
+
+ cdl.await();
+ }
+
+ @Test
+ public void behaviorOfTwoWebViewsAtOnce() throws Throwable {
+ class R implements Runnable {
+ Throwable t;
+
+ @Override
+ public void run() {
+ try {
+ doTest();
+ } catch (Throwable ex) {
+ t = ex;
+ }
+ }
+
+ private void doTest() throws Throwable {
+ URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV1(), u, OnPages.class, "first");
+ }
+ }
+ R run = new R();
+ PROPERTY_SET = new CountDownLatch(2);
+ Platform.runLater(run);
+ PROPERTY_SET.await();
+
+ assertEquals(Integer.getInteger("finalFirst"), Integer.valueOf(3), "Three times in view one");
+ assertEquals(Integer.getInteger("finalSecond"), Integer.valueOf(2), "Two times in view one");
+
+ final CountDownLatch finish = new CountDownLatch(1);
+ final Object[] three = { 0 };
+ assertFalse(Platform.isFxApplicationThread());
+ FXBrowsers.runInBrowser(App.getV1(), new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(Platform.isFxApplicationThread());
+ three[0] = App.getV1().getEngine().executeScript("window.cntBrwsr");
+ finish.countDown();
+ }
+ });
+ finish.await();
+
+ assertEquals(three[0], Integer.valueOf(3));
+ }
+
+ public static class OnPages {
+ static Class<?> first;
+ static Object firstWindow;
+
+ public static void first() {
+ first = OnPages.class;
+ firstWindow = window();
+ assertNotNull(firstWindow, "First window found");
+
+ assertEquals(increment(), 1, "Now it is one");
+
+ URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV2(), u, new Runnable() {
+ @Override
+ public void run() {
+ OnPages.second("Hello");
+ }
+ });
+
+ assertEquals(increment(), 2, "Now it is two and not influenced by second view");
+ System.setProperty("finalFirst", "" + increment());
+ PROPERTY_SET.countDown();
+ }
+
+ public static void second(String... args) {
+ assertEquals(args.length, 1, "One string argument");
+ assertEquals(args[0], "Hello", "It is hello");
+ assertEquals(first, OnPages.class, "Both views share the same classloader");
+
+ Object window = window();
+ assertNotNull(window, "Some window found");
+ assertNotNull(firstWindow, "First window is known");
+ assertNotSame(firstWindow, window, "The window objects should be different");
+
+ assertEquals(increment(), 1, "Counting starts from zero");
+ System.setProperty("finalSecond", "" + increment());
+ PROPERTY_SET.countDown();
+ }
+
+ @JavaScriptBody(args = {}, body = "return window;")
+ private static native Object window();
+
+ @JavaScriptBody(args = {}, body = ""
+ + "if (window.cntBrwsr) return ++window.cntBrwsr;"
+ + "return window.cntBrwsr = 1;"
+ )
+ private static native int increment();
+ }
+
+ public static class App extends Application {
+ static final CountDownLatch CDL = new CountDownLatch(1);
+ private static BorderPane pane;
+
+ /**
+ * @return the v1
+ */
+ static WebView getV1() {
+ return (WebView)System.getProperties().get("v1");
+ }
+
+ /**
+ * @return the v2
+ */
+ static WebView getV2() {
+ return (WebView)System.getProperties().get("v2");
+ }
+
+ @Override
+ public void start(Stage stage) {
+ pane= new BorderPane();
+ Scene scene = new Scene(pane, 800, 600);
+ stage.setScene(scene);
+
+ System.getProperties().put("v1", new WebView());
+ System.getProperties().put("v2", new WebView());
+
+ pane.setCenter(getV1());
+ pane.setBottom(getV2());
+
+ CDL.countDown();
+ }
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java
new file mode 100644
index 0000000..1f52998
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java
@@ -0,0 +1,84 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.boot.fx;
+
+import org.sample.app.pkg.SampleApp;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+public class FXBrwsrTest {
+
+ public FXBrwsrTest() {
+ }
+
+ @Test
+ public void testFindCalleeClassName() throws InterruptedException {
+ String callee = invokeMain();
+ assertEquals(callee, SampleApp.class.getName(), "Callee is found correctly");
+ }
+
+ synchronized static String invokeMain() throws InterruptedException {
+ new Thread("starting main") {
+ @Override
+ public void run() {
+ SampleApp.main();
+ }
+ }.start();
+ for (;;) {
+ String callee = System.getProperty("callee");
+ if (callee != null) {
+ return callee;
+ }
+ FXBrwsrTest.class.wait();
+ }
+ }
+
+
+ public static void computeCalleeClassName() {
+ String name = FXBrwsr.findCalleeClassName();
+ System.setProperty("callee", name);
+ synchronized (FXBrwsrTest.class) {
+ FXBrwsrTest.class.notifyAll();
+ }
+ }
+}