ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 05 Nov 2013 23:06:32 +0100
changeset 322 4a93f2679691
parent 309 7025177bd67e
child 358 80702021b851
permissions -rw-r--r--
Exposing Fn.activate and Fn.activePresenter so they are available from exported packages
     1 /**
     2  * HTML via Java(tm) Language Bindings
     3  * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details. apidesign.org
    13  * designates this particular file as subject to the
    14  * "Classpath" exception as provided by apidesign.org
    15  * in the License file that accompanied this code.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program. Look for COPYING file in the top folder.
    19  * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
    20  */
    21 package org.apidesign.html.kofx;
    22 
    23 import java.io.Closeable;
    24 import java.io.IOException;
    25 import java.io.InputStream;
    26 import java.util.ServiceLoader;
    27 import java.util.logging.Logger;
    28 import javafx.application.Platform;
    29 import net.java.html.js.JavaScriptBody;
    30 import netscape.javascript.JSObject;
    31 import org.apidesign.html.boot.spi.Fn;
    32 import org.apidesign.html.context.spi.Contexts;
    33 import org.apidesign.html.json.spi.FunctionBinding;
    34 import org.apidesign.html.json.spi.JSONCall;
    35 import org.apidesign.html.json.spi.PropertyBinding;
    36 import org.apidesign.html.json.spi.Technology;
    37 import org.apidesign.html.json.spi.Transfer;
    38 import org.apidesign.html.json.spi.WSTransfer;
    39 import org.openide.util.lookup.ServiceProvider;
    40 
    41 /** This is an implementation package - just
    42  * include its JAR on classpath and use official {@link Context} API
    43  * to access the functionality.
    44  * <p>
    45  * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it.
    46  *
    47  * @author Jaroslav Tulach <jtulach@netbeans.org>
    48  */
    49 public final class FXContext
    50 implements Technology.BatchInit<JSObject>, Transfer, WSTransfer<LoadWS> {
    51     static final Logger LOG = Logger.getLogger(FXContext.class.getName());
    52     private static Boolean javaScriptEnabled;
    53     private final Fn.Presenter browserContext;
    54 
    55     public FXContext(Fn.Presenter browserContext) {
    56         this.browserContext = browserContext;
    57     }
    58     
    59     @JavaScriptBody(args = {}, body = "return true;")
    60     private static boolean isJavaScriptEnabledJs() {
    61         return false;
    62     }
    63     
    64     static boolean isJavaScriptEnabled() {
    65         if (javaScriptEnabled != null) {
    66             return javaScriptEnabled;
    67         }
    68         return javaScriptEnabled = isJavaScriptEnabledJs();
    69     }
    70 
    71     final boolean areWebSocketsSupported() {
    72         return LoadWS.isSupported();
    73     }
    74 
    75 
    76     @Override
    77     public JSObject wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
    78         String[] propNames = new String[propArr.length];
    79         boolean[] propReadOnly = new boolean[propArr.length];
    80         Object[] propValues = new Object[propArr.length];
    81         for (int i = 0; i < propNames.length; i++) {
    82             propNames[i] = propArr[i].getPropertyName();
    83             propReadOnly[i] = propArr[i].isReadOnly();
    84             propValues[i] = propArr[i].getValue();
    85         }
    86         String[] funcNames = new String[funcArr.length];
    87         for (int i = 0; i < funcNames.length; i++) {
    88             funcNames[i] = funcArr[i].getFunctionName();
    89         }
    90         
    91         return Knockout.wrapModel(model, 
    92             propNames, propReadOnly, Knockout.toArray(propValues), propArr, 
    93             funcNames, funcArr
    94         );
    95     }
    96     
    97     @Override
    98     public JSObject wrapModel(Object model) {
    99         throw new UnsupportedOperationException();
   100     }
   101 
   102     @Override
   103     public void bind(PropertyBinding b, Object model, JSObject data) {
   104         throw new UnsupportedOperationException();
   105     }
   106 
   107     @Override
   108     public void valueHasMutated(JSObject data, String propertyName) {
   109         Knockout.valueHasMutated(data, propertyName);
   110     }
   111 
   112     @Override
   113     public void expose(FunctionBinding fb, Object model, JSObject d) {
   114         throw new UnsupportedOperationException();
   115     }
   116 
   117     @Override
   118     public void applyBindings(JSObject data) {
   119         Knockout.applyBindings(data);
   120     }
   121 
   122     @Override
   123     public Object wrapArray(Object[] arr) {
   124         return Knockout.toArray(arr);
   125     }
   126 
   127     @Override
   128     public void extract(Object obj, String[] props, Object[] values) {
   129         LoadJSON.extractJSON(obj, props, values);
   130     }
   131 
   132     @Override
   133     public void loadJSON(final JSONCall call) {
   134         LoadJSON.loadJSON(call);
   135     }
   136 
   137     @Override
   138     public <M> M toModel(Class<M> modelClass, Object data) {
   139         if (data instanceof JSObject) {
   140             data = ((JSObject)data).getMember("ko-fx.model"); // NOI18N
   141         }
   142         return modelClass.cast(data);
   143     }
   144 
   145     @Override
   146     public Object toJSON(InputStream is) throws IOException {
   147         return LoadJSON.parse(is);
   148     }
   149 
   150     @Override
   151     public void runSafe(final Runnable r) {
   152         class Wrap implements Runnable {
   153             @Override public void run() {
   154                 try (Closeable c = Fn.activate(browserContext)) {
   155                     r.run();
   156                 } catch (IOException ex) {
   157                     // cannot be thrown
   158                 }
   159             }
   160         }
   161         Wrap w = new Wrap();
   162         
   163         if (Platform.isFxApplicationThread()) {
   164             w.run();
   165         } else {
   166             Platform.runLater(w);
   167         }
   168     }
   169 
   170     @Override
   171     public LoadWS open(String url, JSONCall onReply) {
   172         return new LoadWS(onReply, url);
   173     }
   174 
   175     @Override
   176     public void send(LoadWS socket, JSONCall data) {
   177         socket.send(data);
   178     }
   179 
   180     @Override
   181     public void close(LoadWS socket) {
   182         socket.close();
   183     }
   184     
   185     @ServiceProvider(service = Contexts.Provider.class)
   186     public static final class Prvdr implements Contexts.Provider {
   187         @Override
   188         public void fillContext(Contexts.Builder context, Class<?> requestor) {
   189             if (isJavaScriptEnabled()) {
   190                 FXContext c = new FXContext(Fn.activePresenter());
   191                 
   192                 context.register(Technology.class, c, 100);
   193                 context.register(Transfer.class, c, 100);
   194                 if (c.areWebSocketsSupported()) {
   195                     context.register(WSTransfer.class, c, 100);
   196                 }
   197             }
   198         }
   199     }
   200 }