launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/BrowserToolbar.java
changeset 1166 16555ef29e9e
child 1167 fd8ac9eb0008
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/BrowserToolbar.java	Thu May 30 06:09:42 2013 +0200
     1.3 @@ -0,0 +1,362 @@
     1.4 +/**
     1.5 + * Back 2 Browser Bytecode Translator
     1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     1.7 + *
     1.8 + * This program is free software: you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License as published by
    1.10 + * the Free Software Foundation, version 2 of the License.
    1.11 + *
    1.12 + * This program is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 + * GNU General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU General Public License
    1.18 + * along with this program. Look for COPYING file in the top folder.
    1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    1.20 + */
    1.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
    1.22 +
    1.23 +import java.util.ArrayList;
    1.24 +import java.util.List;
    1.25 +import javafx.beans.InvalidationListener;
    1.26 +import javafx.beans.Observable;
    1.27 +import javafx.beans.value.ChangeListener;
    1.28 +import javafx.beans.value.ObservableValue;
    1.29 +import javafx.collections.FXCollections;
    1.30 +import javafx.scene.control.ComboBox;
    1.31 +import javafx.scene.control.ScrollPane;
    1.32 +import javafx.scene.control.Separator;
    1.33 +import javafx.scene.control.Toggle;
    1.34 +import javafx.scene.control.ToggleButton;
    1.35 +import javafx.scene.control.ToggleGroup;
    1.36 +import javafx.scene.control.ToolBar;
    1.37 +import javafx.scene.control.Tooltip;
    1.38 +import javafx.scene.image.Image;
    1.39 +import javafx.scene.image.ImageView;
    1.40 +import javafx.scene.layout.Pane;
    1.41 +import javafx.scene.web.WebView;
    1.42 +
    1.43 +final class BrowserToolbar extends ToolBar {
    1.44 +    private final ArrayList<ResizeBtn> resizeButtons;
    1.45 +    private final WebView webView;
    1.46 +    private final Pane container;
    1.47 +    private final ToggleGroup resizeGroup = new ToggleGroup();
    1.48 +    private final ComboBox<String> comboZoom = new ComboBox<String>();
    1.49 +    
    1.50 +    private BrowserToolbar( WebView webView, Pane container ) {
    1.51 +        this.webView = webView;
    1.52 +        this.container = container;
    1.53 +        
    1.54 +        List<ResizeOption> options = ResizeOption.loadAll();
    1.55 +        options.add( 0, ResizeOption.SIZE_TO_FIT );
    1.56 +        resizeButtons = new ArrayList<ResizeBtn>( options.size() );
    1.57 +
    1.58 +        for( ResizeOption ro : options ) {
    1.59 +            ResizeBtn button = new ResizeBtn(ro);
    1.60 +            resizeButtons.add( button );
    1.61 +            resizeGroup.getToggles().add( button );
    1.62 +            getItems().add( button );
    1.63 +        }
    1.64 +        resizeButtons.get( 0 ).setSelected( true );
    1.65 +        resizeGroup.selectedToggleProperty().addListener( new InvalidationListener() {
    1.66 +
    1.67 +            @Override
    1.68 +            public void invalidated( Observable o ) {
    1.69 +                resize();
    1.70 +            }
    1.71 +        });
    1.72 +        
    1.73 +        getItems().add( new Separator() );
    1.74 +
    1.75 +        getItems().add( comboZoom );
    1.76 +        ArrayList<String> zoomModel = new ArrayList<String>( 6 );
    1.77 +        zoomModel.add( "200%" ); //NOI18N
    1.78 +        zoomModel.add( "150%" ); //NOI18N
    1.79 +        zoomModel.add( "100%" ); //NOI18N
    1.80 +        zoomModel.add( "75%" ); //NOI18N
    1.81 +        zoomModel.add( "50%" ); //NOI18N
    1.82 +        comboZoom.setItems( FXCollections.observableList( zoomModel ) );
    1.83 +        comboZoom.setEditable( true );
    1.84 +        comboZoom.setValue( "100%" ); //NOI18N
    1.85 +        comboZoom.valueProperty().addListener( new ChangeListener<String>() {
    1.86 +
    1.87 +            @Override
    1.88 +            public void changed( ObservableValue<? extends String> ov, String t, String t1 ) {
    1.89 +                String newZoom = zoom( t1 );
    1.90 +                comboZoom.setValue( newZoom );
    1.91 +            }
    1.92 +        });
    1.93 +
    1.94 +        /*
    1.95 +        final ToggleButton btnSelMode = new ToggleButton( null, new ImageView(
    1.96 +            new Image(BrowserToolbar.class.getResourceAsStream("selectionMode.png"))
    1.97 +        ));
    1.98 +        btnSelMode.setTooltip( new Tooltip( "Toggle selection mode" ) );
    1.99 +        btnSelMode.selectedProperty().addListener( new InvalidationListener() {
   1.100 +
   1.101 +            @Override
   1.102 +            public void invalidated( Observable o ) {
   1.103 +                toggleSelectionMode( btnSelMode.isSelected() );
   1.104 +            }
   1.105 +        });
   1.106 +        getItems().add( btnSelMode );
   1.107 +        */
   1.108 +    }
   1.109 +
   1.110 +    public static ToolBar create( WebView view, Pane container ) {
   1.111 +        return new BrowserToolbar( view, container );
   1.112 +    }
   1.113 +
   1.114 +    private String zoom( String zoomFactor ) {
   1.115 +        if( zoomFactor.trim().isEmpty() )
   1.116 +            return null;
   1.117 +
   1.118 +        try {
   1.119 +            zoomFactor = zoomFactor.replaceAll( "\\%", ""); //NOI18N
   1.120 +            zoomFactor = zoomFactor.trim();
   1.121 +            double zoom = Double.parseDouble( zoomFactor );
   1.122 +            zoom = Math.abs( zoom )/100;
   1.123 +            if( zoom <= 0.0 )
   1.124 +                return null;
   1.125 +            webView.impl_setScale( zoom );
   1.126 +            return (int)(100*zoom) + "%"; //NOI18N
   1.127 +        } catch( NumberFormatException nfe ) {
   1.128 +            //ignore
   1.129 +        }
   1.130 +        return null;
   1.131 +    }
   1.132 +
   1.133 +    private void resize() {
   1.134 +        Toggle selection = resizeGroup.getSelectedToggle();
   1.135 +        if( selection instanceof ResizeBtn ) {
   1.136 +            ResizeOption ro = ((ResizeBtn)selection).getResizeOption();
   1.137 +            if( ro == ResizeOption.SIZE_TO_FIT ) {
   1.138 +                _autofit();
   1.139 +            } else {
   1.140 +                _resize( ro.getWidth(), ro.getHeight() );
   1.141 +            }
   1.142 +        }
   1.143 +
   1.144 +    }
   1.145 +
   1.146 +    private void _resize( final double width, final double height ) {
   1.147 +        ScrollPane scroll;
   1.148 +        if( !(container.getChildren().get( 0) instanceof ScrollPane) ) {
   1.149 +            scroll = new ScrollPane();
   1.150 +            scroll.setContent( webView );
   1.151 +            container.getChildren().clear();
   1.152 +            container.getChildren().add( scroll );
   1.153 +        } else {
   1.154 +            scroll = ( ScrollPane ) container.getChildren().get( 0 );
   1.155 +        }
   1.156 +        scroll.setPrefViewportWidth( width );
   1.157 +        scroll.setPrefViewportHeight(height );
   1.158 +        webView.setMaxWidth( width );
   1.159 +        webView.setMaxHeight( height );
   1.160 +        webView.setMinWidth( width );
   1.161 +        webView.setMinHeight( height );
   1.162 +    }
   1.163 +
   1.164 +    private void _autofit() {
   1.165 +        if( container.getChildren().get( 0) instanceof ScrollPane ) {
   1.166 +            container.getChildren().clear();
   1.167 +            container.getChildren().add( webView );
   1.168 +        }
   1.169 +        webView.setMaxWidth( Integer.MAX_VALUE );
   1.170 +        webView.setMaxHeight( Integer.MAX_VALUE );
   1.171 +        webView.setMinWidth( -1 );
   1.172 +        webView.setMinHeight( -1 );
   1.173 +        webView.autosize();
   1.174 +    }
   1.175 +
   1.176 +    private void toggleSelectionMode( boolean selMode ) {
   1.177 +        System.err.println( "selection mode: " + selMode );
   1.178 +    }
   1.179 +
   1.180 +    /**
   1.181 +     * Button to resize the browser window.
   1.182 +     * Taken from NetBeans. Kept GPLwithCPEx license.
   1.183 +     * Portions Copyrighted 2012 Sun Microsystems, Inc.
   1.184 +     *
   1.185 +     * @author S. Aubrecht
   1.186 +     */
   1.187 +    static final class ResizeBtn extends ToggleButton {
   1.188 +
   1.189 +        private final ResizeOption resizeOption;
   1.190 +
   1.191 +        ResizeBtn(ResizeOption resizeOption) {
   1.192 +            super(null, new ImageView(toImage(resizeOption)));
   1.193 +            this.resizeOption = resizeOption;
   1.194 +            setTooltip(new Tooltip(resizeOption.getToolTip()));
   1.195 +        }
   1.196 +
   1.197 +        ResizeOption getResizeOption() {
   1.198 +            return resizeOption;
   1.199 +        }
   1.200 +
   1.201 +        static Image toImage(ResizeOption ro) {
   1.202 +            if (ro == ResizeOption.SIZE_TO_FIT) {
   1.203 +                return ResizeOption.Type.CUSTOM.getImage();
   1.204 +            }
   1.205 +            return ro.getType().getImage();
   1.206 +        }
   1.207 +    }
   1.208 +
   1.209 +    /**
   1.210 +     * Immutable value class describing a single button to resize web browser window.
   1.211 +     * Taken from NetBeans. Kept GPLwithCPEx license.
   1.212 +     * Portions Copyrighted 2012 Sun Microsystems, Inc.
   1.213 +     *
   1.214 +     * @author S. Aubrecht
   1.215 +     */
   1.216 +    static final class ResizeOption {
   1.217 +
   1.218 +        private final Type type;
   1.219 +        private final String displayName;
   1.220 +        private final int width;
   1.221 +        private final int height;
   1.222 +        private final boolean isDefault;
   1.223 +
   1.224 +        enum Type {
   1.225 +            DESKTOP("desktop.png"), 
   1.226 +            TABLET_PORTRAIT("tabletPortrait.png"), 
   1.227 +            TABLET_LANDSCAPE("tabletLandscape.png"), 
   1.228 +            SMARTPHONE_PORTRAIT("handheldPortrait.png"), 
   1.229 +            SMARTPHONE_LANDSCAPE("handheldLandscape.png"), 
   1.230 +            WIDESCREEN("widescreen.png"), 
   1.231 +            NETBOOK("netbook.png"), 
   1.232 +            CUSTOM("sizeToFit.png");
   1.233 +            
   1.234 +            
   1.235 +            private final String resource;
   1.236 +
   1.237 +            private Type(String r) {
   1.238 +                resource = r;
   1.239 +            }
   1.240 +
   1.241 +            public Image getImage() {
   1.242 +                return new Image(Type.class.getResourceAsStream(resource));
   1.243 +            }
   1.244 +        }
   1.245 +
   1.246 +        private ResizeOption(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
   1.247 +            super();
   1.248 +            this.type = type;
   1.249 +            this.displayName = displayName;
   1.250 +            this.width = width;
   1.251 +            this.height = height;
   1.252 +            this.isDefault = isDefault;
   1.253 +        }
   1.254 +
   1.255 +        static List<ResizeOption> loadAll() {
   1.256 +            List<ResizeOption> res = new ArrayList<ResizeOption>(10);
   1.257 +            res.add(ResizeOption.create(ResizeOption.Type.DESKTOP, "Desktop", 1280, 1024, true, true));
   1.258 +            res.add(ResizeOption.create(ResizeOption.Type.TABLET_LANDSCAPE, "Tablet Landscape", 1024, 768, true, true));
   1.259 +            res.add(ResizeOption.create(ResizeOption.Type.TABLET_PORTRAIT, "Tablet Portrait", 768, 1024, true, true));
   1.260 +            res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_LANDSCAPE, "Smartphone Landscape", 480, 320, true, true));
   1.261 +            res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_PORTRAIT, "Smartphone Portrait", 320, 480, true, true));
   1.262 +            res.add(ResizeOption.create(ResizeOption.Type.WIDESCREEN, "Widescreen", 1680, 1050, false, true));
   1.263 +            res.add(ResizeOption.create(ResizeOption.Type.NETBOOK, "Netbook", 1024, 600, false, true));
   1.264 +            return res;
   1.265 +        }
   1.266 +        
   1.267 +        /**
   1.268 +         * Creates a new instance.
   1.269 +         * @param type
   1.270 +         * @param displayName Display name to show in tooltip, cannot be empty.
   1.271 +         * @param width Screen width
   1.272 +         * @param height Screen height
   1.273 +         * @param showInToolbar True to show in web developer toolbar.
   1.274 +         * @param isDefault True if this is a predefined option that cannot be removed.
   1.275 +         * @return New instance.
   1.276 +         */
   1.277 +        public static ResizeOption create(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
   1.278 +            if (width <= 0 || height <= 0) {
   1.279 +                throw new IllegalArgumentException("Invalid screen dimensions: " + width + " x " + height); //NOI18N
   1.280 +            }
   1.281 +            return new ResizeOption(type, displayName, width, height, showInToolbar, isDefault);
   1.282 +        }
   1.283 +        /**
   1.284 +         * An extra option to size the browser content to fit its window.
   1.285 +         */
   1.286 +        public static final ResizeOption SIZE_TO_FIT = new ResizeOption(Type.CUSTOM, "Size To Fit", -1, -1, true, true);
   1.287 +
   1.288 +        public String getDisplayName() {
   1.289 +            return displayName;
   1.290 +        }
   1.291 +
   1.292 +        public Type getType() {
   1.293 +            return type;
   1.294 +        }
   1.295 +
   1.296 +        public int getWidth() {
   1.297 +            return width;
   1.298 +        }
   1.299 +
   1.300 +        public int getHeight() {
   1.301 +            return height;
   1.302 +        }
   1.303 +
   1.304 +        public boolean isDefault() {
   1.305 +            return isDefault;
   1.306 +        }
   1.307 +
   1.308 +        @Override
   1.309 +        public String toString() {
   1.310 +            return displayName;
   1.311 +        }
   1.312 +
   1.313 +        public String getToolTip() {
   1.314 +            if (width < 0 || height < 0) {
   1.315 +                return displayName;
   1.316 +            }
   1.317 +            StringBuilder sb = new StringBuilder();
   1.318 +            sb.append(width);
   1.319 +            sb.append(" x "); //NOI18N
   1.320 +            sb.append(height);
   1.321 +            sb.append(" ("); //NOI18N
   1.322 +            sb.append(displayName);
   1.323 +            sb.append(')'); //NOI18N
   1.324 +            return sb.toString();
   1.325 +        }
   1.326 +
   1.327 +        @Override
   1.328 +        public boolean equals(Object obj) {
   1.329 +            if (obj == null) {
   1.330 +                return false;
   1.331 +            }
   1.332 +            if (getClass() != obj.getClass()) {
   1.333 +                return false;
   1.334 +            }
   1.335 +            final ResizeOption other = (ResizeOption) obj;
   1.336 +            if (this.type != other.type) {
   1.337 +                return false;
   1.338 +            }
   1.339 +            if ((this.displayName == null) ? (other.displayName != null) : !this.displayName.equals(other.displayName)) {
   1.340 +                return false;
   1.341 +            }
   1.342 +            if (this.width != other.width) {
   1.343 +                return false;
   1.344 +            }
   1.345 +            if (this.height != other.height) {
   1.346 +                return false;
   1.347 +            }
   1.348 +            if (this.isDefault != other.isDefault) {
   1.349 +                return false;
   1.350 +            }
   1.351 +            return true;
   1.352 +        }
   1.353 +
   1.354 +        @Override
   1.355 +        public int hashCode() {
   1.356 +            int hash = 7;
   1.357 +            hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0);
   1.358 +            hash = 11 * hash + (this.displayName != null ? this.displayName.hashCode() : 0);
   1.359 +            hash = 11 * hash + this.width;
   1.360 +            hash = 11 * hash + this.height;
   1.361 +            hash = 11 * hash + (this.isDefault ? 1 : 0);
   1.362 +            return hash;
   1.363 +        }
   1.364 +    }
   1.365 +}