launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/BrowserToolbar.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 08 Jun 2013 12:09:10 +0200
changeset 1169 c19ac78b940e
parent 1167 fd8ac9eb0008
child 1283 1d0e583ac981
permissions -rw-r--r--
LiveHTML WebKitDebugging protocol through CLI that supports --livehtml command
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 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.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.launcher.fximpl;
    19 
    20 import java.util.ArrayList;
    21 import java.util.List;
    22 import javafx.beans.InvalidationListener;
    23 import javafx.beans.Observable;
    24 import javafx.beans.value.ChangeListener;
    25 import javafx.beans.value.ObservableValue;
    26 import javafx.collections.FXCollections;
    27 import javafx.scene.control.ComboBox;
    28 import javafx.scene.control.ScrollPane;
    29 import javafx.scene.control.Separator;
    30 import javafx.scene.control.Toggle;
    31 import javafx.scene.control.ToggleButton;
    32 import javafx.scene.control.ToggleGroup;
    33 import javafx.scene.control.ToolBar;
    34 import javafx.scene.control.Tooltip;
    35 import javafx.scene.image.Image;
    36 import javafx.scene.image.ImageView;
    37 import javafx.scene.layout.Pane;
    38 import javafx.scene.web.WebEngine;
    39 import javafx.scene.web.WebView;
    40 
    41 final class BrowserToolbar extends ToolBar {
    42     private final ArrayList<ResizeBtn> resizeButtons;
    43     private final WebView webView;
    44     private final Pane container;
    45     private final ToggleGroup resizeGroup = new ToggleGroup();
    46     private final ComboBox<String> comboZoom = new ComboBox<String>();
    47     
    48     BrowserToolbar(WebView webView, Pane container, boolean useFirebug, final WebDebug webDebug) {
    49         this.webView = webView;
    50         this.container = container;
    51         
    52         List<ResizeOption> options = ResizeOption.loadAll();
    53         options.add( 0, ResizeOption.SIZE_TO_FIT );
    54         resizeButtons = new ArrayList<ResizeBtn>( options.size() );
    55 
    56         for( ResizeOption ro : options ) {
    57             ResizeBtn button = new ResizeBtn(ro);
    58             resizeButtons.add( button );
    59             resizeGroup.getToggles().add( button );
    60             getItems().add( button );
    61         }
    62         resizeButtons.get( 0 ).setSelected( true );
    63         resizeGroup.selectedToggleProperty().addListener( new InvalidationListener() {
    64 
    65             @Override
    66             public void invalidated( Observable o ) {
    67                 resize();
    68             }
    69         });
    70         
    71         getItems().add( new Separator() );
    72 
    73         getItems().add( comboZoom );
    74         ArrayList<String> zoomModel = new ArrayList<String>( 6 );
    75         zoomModel.add( "200%" ); //NOI18N
    76         zoomModel.add( "150%" ); //NOI18N
    77         zoomModel.add( "100%" ); //NOI18N
    78         zoomModel.add( "75%" ); //NOI18N
    79         zoomModel.add( "50%" ); //NOI18N
    80         comboZoom.setItems( FXCollections.observableList( zoomModel ) );
    81         comboZoom.setEditable( true );
    82         comboZoom.setValue( "100%" ); //NOI18N
    83         comboZoom.valueProperty().addListener( new ChangeListener<String>() {
    84 
    85             @Override
    86             public void changed( ObservableValue<? extends String> ov, String t, String t1 ) {
    87                 String newZoom = zoom( t1 );
    88                 comboZoom.setValue( newZoom );
    89             }
    90         });
    91         
    92         if (useFirebug) {
    93             getItems().add(new Separator());
    94 
    95             final ToggleButton firebug = new ToggleButton(null, new ImageView(
    96                 new Image(BrowserToolbar.class.getResourceAsStream("firebug.png"))
    97             ));
    98             firebug.setTooltip(new Tooltip("Show/Hide firebug"));
    99             firebug.selectedProperty().addListener(new InvalidationListener() {
   100                 @Override
   101                 public void invalidated(Observable o) {
   102                     toggleFireBug(firebug.isSelected());
   103                 }
   104             });
   105             getItems().add(firebug);
   106         }
   107         
   108         if (webDebug != null) {
   109             final ToggleButton btnSelMode = new ToggleButton(null, new ImageView(
   110                     new Image(BrowserToolbar.class.getResourceAsStream("selectionMode.png"))));
   111             btnSelMode.setTooltip(new Tooltip("Toggle selection mode"));
   112             btnSelMode.selectedProperty().addListener(new InvalidationListener() {
   113                 @Override
   114                 public void invalidated(Observable o) {
   115                     toggleSelectionMode(webDebug, btnSelMode.isSelected());
   116                 }
   117             });
   118             getItems().add(btnSelMode);
   119         }
   120     }
   121 
   122     private String zoom( String zoomFactor ) {
   123         if( zoomFactor.trim().isEmpty() )
   124             return null;
   125 
   126         try {
   127             zoomFactor = zoomFactor.replaceAll( "\\%", ""); //NOI18N
   128             zoomFactor = zoomFactor.trim();
   129             double zoom = Double.parseDouble( zoomFactor );
   130             zoom = Math.abs( zoom )/100;
   131             if( zoom <= 0.0 )
   132                 return null;
   133             webView.impl_setScale( zoom );
   134             return (int)(100*zoom) + "%"; //NOI18N
   135         } catch( NumberFormatException nfe ) {
   136             //ignore
   137         }
   138         return null;
   139     }
   140 
   141     private void resize() {
   142         Toggle selection = resizeGroup.getSelectedToggle();
   143         if( selection instanceof ResizeBtn ) {
   144             ResizeOption ro = ((ResizeBtn)selection).getResizeOption();
   145             if( ro == ResizeOption.SIZE_TO_FIT ) {
   146                 _autofit();
   147             } else {
   148                 _resize( ro.getWidth(), ro.getHeight() );
   149             }
   150         }
   151 
   152     }
   153 
   154     private void _resize( final double width, final double height ) {
   155         ScrollPane scroll;
   156         if( !(container.getChildren().get( 0) instanceof ScrollPane) ) {
   157             scroll = new ScrollPane();
   158             scroll.setContent( webView );
   159             container.getChildren().clear();
   160             container.getChildren().add( scroll );
   161         } else {
   162             scroll = ( ScrollPane ) container.getChildren().get( 0 );
   163         }
   164         scroll.setPrefViewportWidth( width );
   165         scroll.setPrefViewportHeight(height );
   166         webView.setMaxWidth( width );
   167         webView.setMaxHeight( height );
   168         webView.setMinWidth( width );
   169         webView.setMinHeight( height );
   170     }
   171 
   172     private void _autofit() {
   173         if( container.getChildren().get( 0) instanceof ScrollPane ) {
   174             container.getChildren().clear();
   175             container.getChildren().add( webView );
   176         }
   177         webView.setMaxWidth( Integer.MAX_VALUE );
   178         webView.setMaxHeight( Integer.MAX_VALUE );
   179         webView.setMinWidth( -1 );
   180         webView.setMinHeight( -1 );
   181         webView.autosize();
   182     }
   183 
   184     private void toggleSelectionMode(WebDebug dbg, boolean selMode) {
   185         // "inspect"
   186         dbg.call("{\"message\":\"selection_mode\",\"selectionMode\":" + selMode + "}");
   187     }
   188     
   189     final void toggleFireBug(boolean enable) {
   190         WebEngine eng = webView.getEngine();
   191         Object installed = eng.executeScript("window.Firebug");
   192         if ("undefined".equals(installed)) {
   193             StringBuilder sb = new StringBuilder();
   194             sb.append("var scr = window.document.createElement('script');\n");
   195             sb.append("scr.type = 'text/javascript';\n");
   196             sb.append("scr.src = 'https://getfirebug.com/firebug-lite.js';\n");
   197             sb.append("scr.text = '{ startOpened: true }';\n");
   198             sb.append("var head = window.document.getElementsByTagName('head')[0];");
   199             sb.append("head.appendChild(scr);\n");
   200             sb.append("var html = window.document.getElementsByTagName('html')[0];");
   201             sb.append("html.debug = true;\n");
   202             eng.executeScript(sb.toString());
   203         } else {
   204             if (enable) {
   205                 eng.executeScript("Firebug.chrome.open()");
   206             } else {
   207                 eng.executeScript("Firebug.chrome.close()");
   208             }
   209         }
   210     }
   211 
   212     /**
   213      * Button to resize the browser window.
   214      * Taken from NetBeans. Kept GPLwithCPEx license.
   215      * Portions Copyrighted 2012 Sun Microsystems, Inc.
   216      *
   217      * @author S. Aubrecht
   218      */
   219     static final class ResizeBtn extends ToggleButton {
   220 
   221         private final ResizeOption resizeOption;
   222 
   223         ResizeBtn(ResizeOption resizeOption) {
   224             super(null, new ImageView(toImage(resizeOption)));
   225             this.resizeOption = resizeOption;
   226             setTooltip(new Tooltip(resizeOption.getToolTip()));
   227         }
   228 
   229         ResizeOption getResizeOption() {
   230             return resizeOption;
   231         }
   232 
   233         static Image toImage(ResizeOption ro) {
   234             if (ro == ResizeOption.SIZE_TO_FIT) {
   235                 return ResizeOption.Type.CUSTOM.getImage();
   236             }
   237             return ro.getType().getImage();
   238         }
   239     }
   240 
   241     /**
   242      * Immutable value class describing a single button to resize web browser window.
   243      * Taken from NetBeans. Kept GPLwithCPEx license.
   244      * Portions Copyrighted 2012 Sun Microsystems, Inc.
   245      *
   246      * @author S. Aubrecht
   247      */
   248     static final class ResizeOption {
   249 
   250         private final Type type;
   251         private final String displayName;
   252         private final int width;
   253         private final int height;
   254         private final boolean isDefault;
   255 
   256         enum Type {
   257             DESKTOP("desktop.png"), 
   258             TABLET_PORTRAIT("tabletPortrait.png"), 
   259             TABLET_LANDSCAPE("tabletLandscape.png"), 
   260             SMARTPHONE_PORTRAIT("handheldPortrait.png"), 
   261             SMARTPHONE_LANDSCAPE("handheldLandscape.png"), 
   262             WIDESCREEN("widescreen.png"), 
   263             NETBOOK("netbook.png"), 
   264             CUSTOM("sizeToFit.png");
   265             
   266             
   267             private final String resource;
   268 
   269             private Type(String r) {
   270                 resource = r;
   271             }
   272 
   273             public Image getImage() {
   274                 return new Image(Type.class.getResourceAsStream(resource));
   275             }
   276         }
   277 
   278         private ResizeOption(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
   279             super();
   280             this.type = type;
   281             this.displayName = displayName;
   282             this.width = width;
   283             this.height = height;
   284             this.isDefault = isDefault;
   285         }
   286 
   287         static List<ResizeOption> loadAll() {
   288             List<ResizeOption> res = new ArrayList<ResizeOption>(10);
   289             res.add(ResizeOption.create(ResizeOption.Type.DESKTOP, "Desktop", 1280, 1024, true, true));
   290             res.add(ResizeOption.create(ResizeOption.Type.TABLET_LANDSCAPE, "Tablet Landscape", 1024, 768, true, true));
   291             res.add(ResizeOption.create(ResizeOption.Type.TABLET_PORTRAIT, "Tablet Portrait", 768, 1024, true, true));
   292             res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_LANDSCAPE, "Smartphone Landscape", 480, 320, true, true));
   293             res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_PORTRAIT, "Smartphone Portrait", 320, 480, true, true));
   294             res.add(ResizeOption.create(ResizeOption.Type.WIDESCREEN, "Widescreen", 1680, 1050, false, true));
   295             res.add(ResizeOption.create(ResizeOption.Type.NETBOOK, "Netbook", 1024, 600, false, true));
   296             return res;
   297         }
   298         
   299         /**
   300          * Creates a new instance.
   301          * @param type
   302          * @param displayName Display name to show in tooltip, cannot be empty.
   303          * @param width Screen width
   304          * @param height Screen height
   305          * @param showInToolbar True to show in web developer toolbar.
   306          * @param isDefault True if this is a predefined option that cannot be removed.
   307          * @return New instance.
   308          */
   309         public static ResizeOption create(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
   310             if (width <= 0 || height <= 0) {
   311                 throw new IllegalArgumentException("Invalid screen dimensions: " + width + " x " + height); //NOI18N
   312             }
   313             return new ResizeOption(type, displayName, width, height, showInToolbar, isDefault);
   314         }
   315         /**
   316          * An extra option to size the browser content to fit its window.
   317          */
   318         public static final ResizeOption SIZE_TO_FIT = new ResizeOption(Type.CUSTOM, "Size To Fit", -1, -1, true, true);
   319 
   320         public String getDisplayName() {
   321             return displayName;
   322         }
   323 
   324         public Type getType() {
   325             return type;
   326         }
   327 
   328         public int getWidth() {
   329             return width;
   330         }
   331 
   332         public int getHeight() {
   333             return height;
   334         }
   335 
   336         public boolean isDefault() {
   337             return isDefault;
   338         }
   339 
   340         @Override
   341         public String toString() {
   342             return displayName;
   343         }
   344 
   345         public String getToolTip() {
   346             if (width < 0 || height < 0) {
   347                 return displayName;
   348             }
   349             StringBuilder sb = new StringBuilder();
   350             sb.append(width);
   351             sb.append(" x "); //NOI18N
   352             sb.append(height);
   353             sb.append(" ("); //NOI18N
   354             sb.append(displayName);
   355             sb.append(')'); //NOI18N
   356             return sb.toString();
   357         }
   358 
   359         @Override
   360         public boolean equals(Object obj) {
   361             if (obj == null) {
   362                 return false;
   363             }
   364             if (getClass() != obj.getClass()) {
   365                 return false;
   366             }
   367             final ResizeOption other = (ResizeOption) obj;
   368             if (this.type != other.type) {
   369                 return false;
   370             }
   371             if ((this.displayName == null) ? (other.displayName != null) : !this.displayName.equals(other.displayName)) {
   372                 return false;
   373             }
   374             if (this.width != other.width) {
   375                 return false;
   376             }
   377             if (this.height != other.height) {
   378                 return false;
   379             }
   380             if (this.isDefault != other.isDefault) {
   381                 return false;
   382             }
   383             return true;
   384         }
   385 
   386         @Override
   387         public int hashCode() {
   388             int hash = 7;
   389             hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0);
   390             hash = 11 * hash + (this.displayName != null ? this.displayName.hashCode() : 0);
   391             hash = 11 * hash + this.width;
   392             hash = 11 * hash + this.height;
   393             hash = 11 * hash + (this.isDefault ? 1 : 0);
   394             return hash;
   395         }
   396     }
   397 }