During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
9 * The contents of this file are subject to the terms of either the GNU
10 * General Public License Version 2 only ("GPL") or the Common
11 * Development and Distribution License("CDDL") (collectively, the
12 * "License"). You may not use this file except in compliance with the
13 * License. You can obtain a copy of the License at
14 * http://www.netbeans.org/cddl-gplv2.html
15 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16 * specific language governing permissions and limitations under the
17 * License. When distributing the software, include this License Header
18 * Notice in each file and include the License file at
19 * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
20 * particular file as subject to the "Classpath" exception as provided
21 * by Oracle in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the
23 * License Header, with the fields enclosed by brackets [] replaced by
24 * your own identifying information:
25 * "Portions Copyrighted [year] [name of copyright owner]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
32 * If you wish your version of this file to be governed by only the CDDL
33 * or only the GPL Version 2, indicate your decision by adding
34 * "[Contributor] elects to include this software in this distribution
35 * under the [CDDL or GPL Version 2] license." If you do not indicate a
36 * single choice of license, a recipient has the option to distribute
37 * your version of this file under either the CDDL, the GPL Version 2 or
38 * to extend the choice of license to its licensees as provided above.
39 * However, if you add GPL Version 2 code and therefore, elected the GPL
40 * Version 2 license, then the option applies only if the new code is
41 * made subject to such option by the copyright holder.
43 package org.netbeans.html.boot.fx;
45 import java.io.BufferedReader;
46 import java.io.Closeable;
47 import java.io.IOException;
48 import java.io.Reader;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.List;
53 import java.util.concurrent.Executor;
54 import java.util.logging.Level;
55 import java.util.logging.Logger;
56 import javafx.application.Platform;
57 import javafx.collections.ObservableList;
58 import javafx.scene.Node;
59 import javafx.scene.Parent;
60 import javafx.scene.layout.BorderPane;
61 import javafx.scene.web.WebEngine;
62 import javafx.scene.web.WebView;
63 import netscape.javascript.JSObject;
64 import org.netbeans.html.boot.spi.Fn;
68 * @author Jaroslav Tulach
70 public abstract class AbstractFXPresenter
71 implements Fn.Presenter, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
72 static final Logger LOG = Logger.getLogger(FXPresenter.class.getName());
73 protected static int cnt;
74 protected Runnable onLoad;
75 protected WebEngine engine;
77 // transient - e.g. not cloneable
78 private JSObject arraySize;
79 private JSObject wrapArrImpl;
82 protected AbstractFXPresenter clone() {
84 AbstractFXPresenter p = (AbstractFXPresenter) super.clone();
88 } catch (CloneNotSupportedException ex) {
89 throw new IllegalStateException(ex);
94 public Fn defineFn(String code, String... names) {
95 return defineJSFn(code, names);
98 final JSFn defineJSFn(String code, String... names) {
99 StringBuilder sb = new StringBuilder();
100 sb.append("(function() {");
101 sb.append(" return function(");
103 for (String n : names) {
104 sb.append(sep).append(n);
111 if (LOG.isLoggable(Level.FINE)) {
113 "defining function #{0}:\n{1}\n",
114 new Object[] { ++cnt, code }
117 JSObject x = (JSObject) engine.executeScript(sb.toString());
118 return new JSFn(this, x, cnt);
122 public void loadScript(Reader code) throws Exception {
123 BufferedReader r = new BufferedReader(code);
124 StringBuilder sb = new StringBuilder();
126 String l = r.readLine();
130 sb.append(l).append('\n');
132 final String script = sb.toString();
133 engine.executeScript(script);
136 protected final void onPageLoad() {
137 Closeable c = Fn.activate(this.clone());
143 } catch (IOException ex) {
144 LOG.log(Level.SEVERE, null, ex);
150 public void displayPage(final URL resource, final Runnable onLoad) {
151 this.onLoad = onLoad;
152 final WebView view = findView(resource);
153 this.engine = view.getEngine();
154 boolean inspectOn = false;
156 if (FXInspect.initialize(engine)) {
159 } catch (Throwable ex) {
160 ex.printStackTrace();
162 final boolean isInspectOn = inspectOn;
164 class Run implements Runnable {
169 view.setContextMenuEnabled(true);
170 final Parent p = view.getParent();
171 if (p instanceof BorderPane) {
172 BorderPane bp = (BorderPane) p;
173 if (bp.getTop() == null) {
174 bp.setTop(new FXToolbar(view, bp));
178 engine.load(resource.toExternalForm());
182 if (Platform.isFxApplicationThread()) {
185 Platform.runLater(run);
190 protected abstract void waitFinished();
192 protected abstract WebView findView(final URL resource);
194 final JSObject convertArrays(Object[] arr) {
195 for (int i = 0; i < arr.length; i++) {
196 if (arr[i] instanceof Object[]) {
197 arr[i] = convertArrays((Object[]) arr[i]);
200 final JSObject wrapArr = (JSObject)wrapArrFn().call("array", arr); // NOI18N
204 private final JSObject wrapArrFn() {
205 if (wrapArrImpl == null) {
207 wrapArrImpl = (JSObject)defineJSFn(" var k = {};"
208 + " k.array= function() {"
209 + " return Array.prototype.slice.call(arguments);"
212 ).invokeImpl(null, false);
213 } catch (Exception ex) {
214 throw new IllegalStateException(ex);
220 final Object checkArray(Object val) {
221 int length = ((Number) arraySizeFn().call("array", val, null)).intValue();
225 Object[] arr = new Object[length];
226 arraySizeFn().call("array", val, arr);
229 private final JSObject arraySizeFn() {
230 if (arraySize == null) {
232 arraySize = (JSObject)defineJSFn(" var k = {};"
233 + " k.array = function(arr, to) {"
234 + " if (to === null) {"
235 + " if (Object.prototype.toString.call(arr) === '[object Array]') return arr.length;"
238 + " var l = arr.length;"
239 + " for (var i = 0; i < l; i++) to[i] = arr[i];"
244 ).invokeImpl(null, false);
245 } catch (Exception ex) {
246 throw new IllegalStateException(ex);
253 public Object toJava(Object jsArray) {
254 return checkArray(jsArray);
258 public Object toJavaScript(Object toReturn) {
259 if (toReturn instanceof Object[]) {
260 return convertArrays((Object[])toReturn);
266 @Override public void execute(final Runnable r) {
267 if (Platform.isFxApplicationThread()) {
268 Closeable c = Fn.activate(this);
274 } catch (IOException ex) {
279 class Wrap implements Runnable {
282 Closeable c = Fn.activate(AbstractFXPresenter.this);
288 } catch (IOException ex) {
294 Platform.runLater(new Wrap());
298 private static final class JSFn extends Fn {
300 private final JSObject fn;
301 private static int call;
302 private final int id;
304 public JSFn(AbstractFXPresenter p, JSObject fn, int id) {
311 public Object invoke(Object thiz, Object... args) throws Exception {
312 return invokeImpl(thiz, true, args);
315 final Object invokeImpl(Object thiz, boolean arrayChecks, Object... args) throws Exception {
317 if (LOG.isLoggable(Level.FINE)) {
318 LOG.log(Level.FINE, "calling {0} function #{1}", new Object[]{++call, id});
319 LOG.log(Level.FINER, " thiz : {0}", thiz);
320 LOG.log(Level.FINER, " params: {0}", Arrays.asList(args));
322 List<Object> all = new ArrayList<Object>(args.length + 1);
323 all.add(thiz == null ? fn : thiz);
324 for (int i = 0; i < args.length; i++) {
325 if (arrayChecks && args[i] instanceof Object[]) {
326 Object[] arr = (Object[]) args[i];
327 Object conv = ((AbstractFXPresenter)presenter()).convertArrays(arr);
332 Object ret = fn.call("call", all.toArray()); // NOI18N
339 return ((AbstractFXPresenter)presenter()).checkArray(ret);
343 } catch (Exception t) {