Listen on changes and automatically reload whenever file next to index.html changes
authorJaroslav Tulach <jtulach@netbeans.org>
Fri, 18 Jul 2014 17:02:21 +0200
changeset 7397a2f7066fc67
parent 738 5b88d9ecc21c
child 740 f34b06e2d139
Listen on changes and automatically reload whenever file next to index.html changes
boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java
boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java
     1.1 --- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java	Fri Jul 18 15:50:06 2014 +0200
     1.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java	Fri Jul 18 17:02:21 2014 +0200
     1.3 @@ -59,7 +59,7 @@
     1.4   * @author Jaroslav Tulach <jtulach@netbeans.org>
     1.5   */
     1.6  final class FXInspect implements Runnable {
     1.7 -    private static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
     1.8 +    static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
     1.9      
    1.10      
    1.11      private final WebEngine engine;
     2.1 --- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java	Fri Jul 18 15:50:06 2014 +0200
     2.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java	Fri Jul 18 17:02:21 2014 +0200
     2.3 @@ -42,13 +42,21 @@
     2.4   */
     2.5  package org.netbeans.html.boot.fx;
     2.6  
     2.7 +import java.io.IOException;
     2.8 +import java.net.URISyntaxException;
     2.9  import java.util.ArrayList;
    2.10  import java.util.List;
    2.11 +import java.util.logging.Level;
    2.12 +import java.util.prefs.Preferences;
    2.13  import javafx.beans.InvalidationListener;
    2.14  import javafx.beans.Observable;
    2.15  import javafx.beans.value.ChangeListener;
    2.16  import javafx.beans.value.ObservableValue;
    2.17  import javafx.collections.FXCollections;
    2.18 +import javafx.event.ActionEvent;
    2.19 +import javafx.event.EventHandler;
    2.20 +import javafx.scene.control.Button;
    2.21 +import javafx.scene.control.CheckBox;
    2.22  import javafx.scene.control.ComboBox;
    2.23  import javafx.scene.control.ScrollPane;
    2.24  import javafx.scene.control.Separator;
    2.25 @@ -68,9 +76,10 @@
    2.26      private final BorderPane container;
    2.27      private final ToggleGroup resizeGroup = new ToggleGroup();
    2.28      private final ComboBox<String> comboZoom = new ComboBox<String>();
    2.29 +    private WatchDir watcher;
    2.30      
    2.31 -    FXToolbar(WebView webView, BorderPane container) {
    2.32 -        this.webView = webView;
    2.33 +    FXToolbar(WebView wv, BorderPane container) {
    2.34 +        this.webView = wv;
    2.35          this.container = container;
    2.36          
    2.37          List<ResizeOption> options = ResizeOption.loadAll();
    2.38 @@ -112,6 +121,34 @@
    2.39                  comboZoom.setValue( newZoom );
    2.40              }
    2.41          });
    2.42 +        
    2.43 +        getItems().add(new Separator());
    2.44 +        final CheckBox automatic = new CheckBox("Automatic");
    2.45 +        final Preferences prefs = Preferences.userNodeForPackage(FXToolbar.class);
    2.46 +        final String ar = "automaticReload"; // NOI18N
    2.47 +        automatic.setSelected(prefs.getBoolean(ar, true));
    2.48 +        getItems().add(automatic);
    2.49 +        final Button reload = new Button("Reload");
    2.50 +        getItems().add(reload);
    2.51 +        reload.setOnAction(new EventHandler<ActionEvent>() {
    2.52 +            @Override
    2.53 +            public void handle(ActionEvent event) {
    2.54 +                webView.getEngine().reload();
    2.55 +            }
    2.56 +        });
    2.57 +        automatic.setOnAction(new EventHandler<ActionEvent>() {
    2.58 +            @Override
    2.59 +            public void handle(ActionEvent event) {
    2.60 +                prefs.putBoolean(ar, automatic.isSelected());
    2.61 +                listenOnChanges(automatic.isSelected());
    2.62 +            }
    2.63 +        });
    2.64 +        webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
    2.65 +            @Override
    2.66 +            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
    2.67 +                listenOnChanges(automatic.isSelected());
    2.68 +            }
    2.69 +        });
    2.70      }
    2.71  
    2.72      private String zoom( String zoomFactor ) {
    2.73 @@ -359,4 +396,18 @@
    2.74              return hash;
    2.75          }
    2.76      }
    2.77 +    
    2.78 +    private void listenOnChanges(boolean turnOn) {
    2.79 +        try {
    2.80 +            if (watcher != null) {
    2.81 +                watcher.close();
    2.82 +                watcher = null;
    2.83 +            }
    2.84 +            if (turnOn) {
    2.85 +                watcher = new WatchDir(webView.getEngine());
    2.86 +            }
    2.87 +        } catch (Exception ex) {
    2.88 +            FXInspect.LOG.log(Level.SEVERE, null, ex);
    2.89 +        }
    2.90 +    }
    2.91  }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java	Fri Jul 18 17:02:21 2014 +0200
     3.3 @@ -0,0 +1,117 @@
     3.4 +/**
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     3.8 + *
     3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    3.10 + * Other names may be trademarks of their respective owners.
    3.11 + *
    3.12 + * The contents of this file are subject to the terms of either the GNU
    3.13 + * General Public License Version 2 only ("GPL") or the Common
    3.14 + * Development and Distribution License("CDDL") (collectively, the
    3.15 + * "License"). You may not use this file except in compliance with the
    3.16 + * License. You can obtain a copy of the License at
    3.17 + * http://www.netbeans.org/cddl-gplv2.html
    3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    3.19 + * specific language governing permissions and limitations under the
    3.20 + * License.  When distributing the software, include this License Header
    3.21 + * Notice in each file and include the License file at
    3.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    3.23 + * particular file as subject to the "Classpath" exception as provided
    3.24 + * by Oracle in the GPL Version 2 section of the License file that
    3.25 + * accompanied this code. If applicable, add the following below the
    3.26 + * License Header, with the fields enclosed by brackets [] replaced by
    3.27 + * your own identifying information:
    3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    3.29 + *
    3.30 + * Contributor(s):
    3.31 + *
    3.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    3.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    3.34 + *
    3.35 + * If you wish your version of this file to be governed by only the CDDL
    3.36 + * or only the GPL Version 2, indicate your decision by adding
    3.37 + * "[Contributor] elects to include this software in this distribution
    3.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    3.39 + * single choice of license, a recipient has the option to distribute
    3.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    3.41 + * to extend the choice of license to its licensees as provided above.
    3.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    3.43 + * Version 2 license, then the option applies only if the new code is
    3.44 + * made subject to such option by the copyright holder.
    3.45 + */
    3.46 +package org.netbeans.html.boot.fx;
    3.47 +
    3.48 +import java.io.IOException;
    3.49 +import java.net.URI;
    3.50 +import java.net.URISyntaxException;
    3.51 +import java.nio.file.ClosedWatchServiceException;
    3.52 +import java.nio.file.Path;
    3.53 +import java.nio.file.Paths;
    3.54 +import java.nio.file.StandardWatchEventKinds;
    3.55 +import java.nio.file.WatchKey;
    3.56 +import java.nio.file.WatchService;
    3.57 +import java.util.logging.Level;
    3.58 +import java.util.logging.Logger;
    3.59 +import javafx.application.Platform;
    3.60 +import javafx.scene.web.WebEngine;
    3.61 +
    3.62 +/**
    3.63 + *
    3.64 + * @author Jaroslav Tulach
    3.65 + */
    3.66 +final class WatchDir implements Runnable {
    3.67 +    private final Path dir;
    3.68 +    private final WatchKey key;
    3.69 +    private final WatchService ws; 
    3.70 +    private final Thread watcher;
    3.71 +    private final WebEngine engine;
    3.72 +    
    3.73 +    WatchDir(WebEngine eng) throws URISyntaxException, IOException {
    3.74 +        dir = Paths.get(new URI(eng.getLocation())).getParent();
    3.75 +        engine = eng;
    3.76 +        ws = dir.getFileSystem().newWatchService();
    3.77 +        key = dir.register(ws, 
    3.78 +            StandardWatchEventKinds.ENTRY_CREATE,
    3.79 +            StandardWatchEventKinds.ENTRY_DELETE,
    3.80 +            StandardWatchEventKinds.ENTRY_MODIFY
    3.81 +        );
    3.82 +        watcher = new Thread(this, "Watching files in " + dir);
    3.83 +        watcher.setDaemon(true);
    3.84 +        watcher.setPriority(Thread.MIN_PRIORITY);
    3.85 +        watcher.start();
    3.86 +    }
    3.87 +
    3.88 +    public void close() throws IOException {
    3.89 +        key.cancel();
    3.90 +        ws.close();
    3.91 +        watcher.interrupt();
    3.92 +    }
    3.93 +
    3.94 +    @Override
    3.95 +    public void run() {
    3.96 +        if (Platform.isFxApplicationThread()) {
    3.97 +            engine.reload();
    3.98 +            return;
    3.99 +        }
   3.100 +        try {
   3.101 +            while (key.isValid()) {
   3.102 +                WatchKey changed;
   3.103 +                try {
   3.104 +                    changed = ws.take();
   3.105 +                    if (changed != key || changed.pollEvents().isEmpty()) {
   3.106 +                        continue;
   3.107 +                    }
   3.108 +                } catch (ClosedWatchServiceException ex) {
   3.109 +                    continue;
   3.110 +                }
   3.111 +                Platform.runLater(this);
   3.112 +                if (!key.reset()) {
   3.113 +                    break;
   3.114 +                }
   3.115 +            }
   3.116 +        } catch (InterruptedException ex) {
   3.117 +            FXInspect.LOG.log(Level.SEVERE, null, ex);
   3.118 +        }
   3.119 +    }
   3.120 +}