jaroslav@1166: /** jaroslav@1166: * Back 2 Browser Bytecode Translator jaroslav@1166: * Copyright (C) 2012 Jaroslav Tulach jaroslav@1166: * jaroslav@1166: * This program is free software: you can redistribute it and/or modify jaroslav@1166: * it under the terms of the GNU General Public License as published by jaroslav@1166: * the Free Software Foundation, version 2 of the License. jaroslav@1166: * jaroslav@1166: * This program is distributed in the hope that it will be useful, jaroslav@1166: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@1166: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@1166: * GNU General Public License for more details. jaroslav@1166: * jaroslav@1166: * You should have received a copy of the GNU General Public License jaroslav@1166: * along with this program. Look for COPYING file in the top folder. jaroslav@1166: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@1166: */ jaroslav@1166: package org.apidesign.bck2brwsr.launcher.fximpl; jaroslav@1166: jaroslav@1166: import java.util.ArrayList; jaroslav@1166: import java.util.List; jaroslav@1166: import javafx.beans.InvalidationListener; jaroslav@1166: import javafx.beans.Observable; jaroslav@1166: import javafx.beans.value.ChangeListener; jaroslav@1166: import javafx.beans.value.ObservableValue; jaroslav@1166: import javafx.collections.FXCollections; jaroslav@1166: import javafx.scene.control.ComboBox; jaroslav@1166: import javafx.scene.control.ScrollPane; jaroslav@1166: import javafx.scene.control.Separator; jaroslav@1166: import javafx.scene.control.Toggle; jaroslav@1166: import javafx.scene.control.ToggleButton; jaroslav@1166: import javafx.scene.control.ToggleGroup; jaroslav@1166: import javafx.scene.control.ToolBar; jaroslav@1166: import javafx.scene.control.Tooltip; jaroslav@1166: import javafx.scene.image.Image; jaroslav@1166: import javafx.scene.image.ImageView; jaroslav@1166: import javafx.scene.layout.Pane; jaroslav@1167: import javafx.scene.web.WebEngine; jaroslav@1166: import javafx.scene.web.WebView; jaroslav@1166: jaroslav@1166: final class BrowserToolbar extends ToolBar { jaroslav@1166: private final ArrayList resizeButtons; jaroslav@1166: private final WebView webView; jaroslav@1166: private final Pane container; jaroslav@1166: private final ToggleGroup resizeGroup = new ToggleGroup(); jaroslav@1166: private final ComboBox comboZoom = new ComboBox(); jaroslav@1166: jaroslav@1283: BrowserToolbar(WebView webView, Pane container, boolean useFirebug) { jaroslav@1166: this.webView = webView; jaroslav@1166: this.container = container; jaroslav@1166: jaroslav@1166: List options = ResizeOption.loadAll(); jaroslav@1166: options.add( 0, ResizeOption.SIZE_TO_FIT ); jaroslav@1166: resizeButtons = new ArrayList( options.size() ); jaroslav@1166: jaroslav@1166: for( ResizeOption ro : options ) { jaroslav@1166: ResizeBtn button = new ResizeBtn(ro); jaroslav@1166: resizeButtons.add( button ); jaroslav@1166: resizeGroup.getToggles().add( button ); jaroslav@1166: getItems().add( button ); jaroslav@1166: } jaroslav@1166: resizeButtons.get( 0 ).setSelected( true ); jaroslav@1166: resizeGroup.selectedToggleProperty().addListener( new InvalidationListener() { jaroslav@1166: jaroslav@1166: @Override jaroslav@1166: public void invalidated( Observable o ) { jaroslav@1166: resize(); jaroslav@1166: } jaroslav@1166: }); jaroslav@1166: jaroslav@1166: getItems().add( new Separator() ); jaroslav@1166: jaroslav@1166: getItems().add( comboZoom ); jaroslav@1166: ArrayList zoomModel = new ArrayList( 6 ); jaroslav@1166: zoomModel.add( "200%" ); //NOI18N jaroslav@1166: zoomModel.add( "150%" ); //NOI18N jaroslav@1166: zoomModel.add( "100%" ); //NOI18N jaroslav@1166: zoomModel.add( "75%" ); //NOI18N jaroslav@1166: zoomModel.add( "50%" ); //NOI18N jaroslav@1166: comboZoom.setItems( FXCollections.observableList( zoomModel ) ); jaroslav@1166: comboZoom.setEditable( true ); jaroslav@1166: comboZoom.setValue( "100%" ); //NOI18N jaroslav@1166: comboZoom.valueProperty().addListener( new ChangeListener() { jaroslav@1166: jaroslav@1166: @Override jaroslav@1166: public void changed( ObservableValue ov, String t, String t1 ) { jaroslav@1166: String newZoom = zoom( t1 ); jaroslav@1166: comboZoom.setValue( newZoom ); jaroslav@1166: } jaroslav@1166: }); jaroslav@1167: jaroslav@1167: if (useFirebug) { jaroslav@1167: getItems().add(new Separator()); jaroslav@1166: jaroslav@1167: final ToggleButton firebug = new ToggleButton(null, new ImageView( jaroslav@1167: new Image(BrowserToolbar.class.getResourceAsStream("firebug.png")) jaroslav@1167: )); jaroslav@1167: firebug.setTooltip(new Tooltip("Show/Hide firebug")); jaroslav@1167: firebug.selectedProperty().addListener(new InvalidationListener() { jaroslav@1167: @Override jaroslav@1167: public void invalidated(Observable o) { jaroslav@1167: toggleFireBug(firebug.isSelected()); jaroslav@1167: } jaroslav@1167: }); jaroslav@1167: getItems().add(firebug); jaroslav@1167: } jaroslav@1166: } jaroslav@1166: jaroslav@1166: private String zoom( String zoomFactor ) { jaroslav@1166: if( zoomFactor.trim().isEmpty() ) jaroslav@1166: return null; jaroslav@1166: jaroslav@1166: try { jaroslav@1166: zoomFactor = zoomFactor.replaceAll( "\\%", ""); //NOI18N jaroslav@1166: zoomFactor = zoomFactor.trim(); jaroslav@1166: double zoom = Double.parseDouble( zoomFactor ); jaroslav@1166: zoom = Math.abs( zoom )/100; jaroslav@1166: if( zoom <= 0.0 ) jaroslav@1166: return null; jaroslav@1166: webView.impl_setScale( zoom ); jaroslav@1166: return (int)(100*zoom) + "%"; //NOI18N jaroslav@1166: } catch( NumberFormatException nfe ) { jaroslav@1166: //ignore jaroslav@1166: } jaroslav@1166: return null; jaroslav@1166: } jaroslav@1166: jaroslav@1166: private void resize() { jaroslav@1166: Toggle selection = resizeGroup.getSelectedToggle(); jaroslav@1166: if( selection instanceof ResizeBtn ) { jaroslav@1166: ResizeOption ro = ((ResizeBtn)selection).getResizeOption(); jaroslav@1166: if( ro == ResizeOption.SIZE_TO_FIT ) { jaroslav@1166: _autofit(); jaroslav@1166: } else { jaroslav@1166: _resize( ro.getWidth(), ro.getHeight() ); jaroslav@1166: } jaroslav@1166: } jaroslav@1166: jaroslav@1166: } jaroslav@1166: jaroslav@1166: private void _resize( final double width, final double height ) { jaroslav@1166: ScrollPane scroll; jaroslav@1166: if( !(container.getChildren().get( 0) instanceof ScrollPane) ) { jaroslav@1166: scroll = new ScrollPane(); jaroslav@1166: scroll.setContent( webView ); jaroslav@1166: container.getChildren().clear(); jaroslav@1166: container.getChildren().add( scroll ); jaroslav@1166: } else { jaroslav@1166: scroll = ( ScrollPane ) container.getChildren().get( 0 ); jaroslav@1166: } jaroslav@1166: scroll.setPrefViewportWidth( width ); jaroslav@1166: scroll.setPrefViewportHeight(height ); jaroslav@1166: webView.setMaxWidth( width ); jaroslav@1166: webView.setMaxHeight( height ); jaroslav@1166: webView.setMinWidth( width ); jaroslav@1166: webView.setMinHeight( height ); jaroslav@1166: } jaroslav@1166: jaroslav@1166: private void _autofit() { jaroslav@1166: if( container.getChildren().get( 0) instanceof ScrollPane ) { jaroslav@1166: container.getChildren().clear(); jaroslav@1166: container.getChildren().add( webView ); jaroslav@1166: } jaroslav@1166: webView.setMaxWidth( Integer.MAX_VALUE ); jaroslav@1166: webView.setMaxHeight( Integer.MAX_VALUE ); jaroslav@1166: webView.setMinWidth( -1 ); jaroslav@1166: webView.setMinHeight( -1 ); jaroslav@1166: webView.autosize(); jaroslav@1166: } jaroslav@1166: jaroslav@1167: final void toggleFireBug(boolean enable) { jaroslav@1167: WebEngine eng = webView.getEngine(); jaroslav@1167: Object installed = eng.executeScript("window.Firebug"); jaroslav@1167: if ("undefined".equals(installed)) { jaroslav@1167: StringBuilder sb = new StringBuilder(); jaroslav@1167: sb.append("var scr = window.document.createElement('script');\n"); jaroslav@1167: sb.append("scr.type = 'text/javascript';\n"); jaroslav@1167: sb.append("scr.src = 'https://getfirebug.com/firebug-lite.js';\n"); jaroslav@1167: sb.append("scr.text = '{ startOpened: true }';\n"); jaroslav@1167: sb.append("var head = window.document.getElementsByTagName('head')[0];"); jaroslav@1167: sb.append("head.appendChild(scr);\n"); jaroslav@1167: sb.append("var html = window.document.getElementsByTagName('html')[0];"); jaroslav@1167: sb.append("html.debug = true;\n"); jaroslav@1167: eng.executeScript(sb.toString()); jaroslav@1167: } else { jaroslav@1167: if (enable) { jaroslav@1167: eng.executeScript("Firebug.chrome.open()"); jaroslav@1167: } else { jaroslav@1167: eng.executeScript("Firebug.chrome.close()"); jaroslav@1167: } jaroslav@1167: } jaroslav@1167: } jaroslav@1166: jaroslav@1166: /** jaroslav@1166: * Button to resize the browser window. jaroslav@1166: * Taken from NetBeans. Kept GPLwithCPEx license. jaroslav@1166: * Portions Copyrighted 2012 Sun Microsystems, Inc. jaroslav@1166: * jaroslav@1166: * @author S. Aubrecht jaroslav@1166: */ jaroslav@1166: static final class ResizeBtn extends ToggleButton { jaroslav@1166: jaroslav@1166: private final ResizeOption resizeOption; jaroslav@1166: jaroslav@1166: ResizeBtn(ResizeOption resizeOption) { jaroslav@1166: super(null, new ImageView(toImage(resizeOption))); jaroslav@1166: this.resizeOption = resizeOption; jaroslav@1166: setTooltip(new Tooltip(resizeOption.getToolTip())); jaroslav@1166: } jaroslav@1166: jaroslav@1166: ResizeOption getResizeOption() { jaroslav@1166: return resizeOption; jaroslav@1166: } jaroslav@1166: jaroslav@1166: static Image toImage(ResizeOption ro) { jaroslav@1166: if (ro == ResizeOption.SIZE_TO_FIT) { jaroslav@1166: return ResizeOption.Type.CUSTOM.getImage(); jaroslav@1166: } jaroslav@1166: return ro.getType().getImage(); jaroslav@1166: } jaroslav@1166: } jaroslav@1166: jaroslav@1166: /** jaroslav@1166: * Immutable value class describing a single button to resize web browser window. jaroslav@1166: * Taken from NetBeans. Kept GPLwithCPEx license. jaroslav@1166: * Portions Copyrighted 2012 Sun Microsystems, Inc. jaroslav@1166: * jaroslav@1166: * @author S. Aubrecht jaroslav@1166: */ jaroslav@1166: static final class ResizeOption { jaroslav@1166: jaroslav@1166: private final Type type; jaroslav@1166: private final String displayName; jaroslav@1166: private final int width; jaroslav@1166: private final int height; jaroslav@1166: private final boolean isDefault; jaroslav@1166: jaroslav@1166: enum Type { jaroslav@1166: DESKTOP("desktop.png"), jaroslav@1166: TABLET_PORTRAIT("tabletPortrait.png"), jaroslav@1166: TABLET_LANDSCAPE("tabletLandscape.png"), jaroslav@1166: SMARTPHONE_PORTRAIT("handheldPortrait.png"), jaroslav@1166: SMARTPHONE_LANDSCAPE("handheldLandscape.png"), jaroslav@1166: WIDESCREEN("widescreen.png"), jaroslav@1166: NETBOOK("netbook.png"), jaroslav@1166: CUSTOM("sizeToFit.png"); jaroslav@1166: jaroslav@1166: jaroslav@1166: private final String resource; jaroslav@1166: jaroslav@1166: private Type(String r) { jaroslav@1166: resource = r; jaroslav@1166: } jaroslav@1166: jaroslav@1166: public Image getImage() { jaroslav@1166: return new Image(Type.class.getResourceAsStream(resource)); jaroslav@1166: } jaroslav@1166: } jaroslav@1166: jaroslav@1166: private ResizeOption(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) { jaroslav@1166: super(); jaroslav@1166: this.type = type; jaroslav@1166: this.displayName = displayName; jaroslav@1166: this.width = width; jaroslav@1166: this.height = height; jaroslav@1166: this.isDefault = isDefault; jaroslav@1166: } jaroslav@1166: jaroslav@1166: static List loadAll() { jaroslav@1166: List res = new ArrayList(10); jaroslav@1166: res.add(ResizeOption.create(ResizeOption.Type.DESKTOP, "Desktop", 1280, 1024, true, true)); jaroslav@1166: res.add(ResizeOption.create(ResizeOption.Type.TABLET_LANDSCAPE, "Tablet Landscape", 1024, 768, true, true)); jaroslav@1166: res.add(ResizeOption.create(ResizeOption.Type.TABLET_PORTRAIT, "Tablet Portrait", 768, 1024, true, true)); jaroslav@1166: res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_LANDSCAPE, "Smartphone Landscape", 480, 320, true, true)); jaroslav@1166: res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_PORTRAIT, "Smartphone Portrait", 320, 480, true, true)); jaroslav@1166: res.add(ResizeOption.create(ResizeOption.Type.WIDESCREEN, "Widescreen", 1680, 1050, false, true)); jaroslav@1166: res.add(ResizeOption.create(ResizeOption.Type.NETBOOK, "Netbook", 1024, 600, false, true)); jaroslav@1166: return res; jaroslav@1166: } jaroslav@1166: jaroslav@1166: /** jaroslav@1166: * Creates a new instance. jaroslav@1166: * @param type jaroslav@1166: * @param displayName Display name to show in tooltip, cannot be empty. jaroslav@1166: * @param width Screen width jaroslav@1166: * @param height Screen height jaroslav@1166: * @param showInToolbar True to show in web developer toolbar. jaroslav@1166: * @param isDefault True if this is a predefined option that cannot be removed. jaroslav@1166: * @return New instance. jaroslav@1166: */ jaroslav@1166: public static ResizeOption create(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) { jaroslav@1166: if (width <= 0 || height <= 0) { jaroslav@1166: throw new IllegalArgumentException("Invalid screen dimensions: " + width + " x " + height); //NOI18N jaroslav@1166: } jaroslav@1166: return new ResizeOption(type, displayName, width, height, showInToolbar, isDefault); jaroslav@1166: } jaroslav@1166: /** jaroslav@1166: * An extra option to size the browser content to fit its window. jaroslav@1166: */ jaroslav@1166: public static final ResizeOption SIZE_TO_FIT = new ResizeOption(Type.CUSTOM, "Size To Fit", -1, -1, true, true); jaroslav@1166: jaroslav@1166: public String getDisplayName() { jaroslav@1166: return displayName; jaroslav@1166: } jaroslav@1166: jaroslav@1166: public Type getType() { jaroslav@1166: return type; jaroslav@1166: } jaroslav@1166: jaroslav@1166: public int getWidth() { jaroslav@1166: return width; jaroslav@1166: } jaroslav@1166: jaroslav@1166: public int getHeight() { jaroslav@1166: return height; jaroslav@1166: } jaroslav@1166: jaroslav@1166: public boolean isDefault() { jaroslav@1166: return isDefault; jaroslav@1166: } jaroslav@1166: jaroslav@1166: @Override jaroslav@1166: public String toString() { jaroslav@1166: return displayName; jaroslav@1166: } jaroslav@1166: jaroslav@1166: public String getToolTip() { jaroslav@1166: if (width < 0 || height < 0) { jaroslav@1166: return displayName; jaroslav@1166: } jaroslav@1166: StringBuilder sb = new StringBuilder(); jaroslav@1166: sb.append(width); jaroslav@1166: sb.append(" x "); //NOI18N jaroslav@1166: sb.append(height); jaroslav@1166: sb.append(" ("); //NOI18N jaroslav@1166: sb.append(displayName); jaroslav@1166: sb.append(')'); //NOI18N jaroslav@1166: return sb.toString(); jaroslav@1166: } jaroslav@1166: jaroslav@1166: @Override jaroslav@1166: public boolean equals(Object obj) { jaroslav@1166: if (obj == null) { jaroslav@1166: return false; jaroslav@1166: } jaroslav@1166: if (getClass() != obj.getClass()) { jaroslav@1166: return false; jaroslav@1166: } jaroslav@1166: final ResizeOption other = (ResizeOption) obj; jaroslav@1166: if (this.type != other.type) { jaroslav@1166: return false; jaroslav@1166: } jaroslav@1166: if ((this.displayName == null) ? (other.displayName != null) : !this.displayName.equals(other.displayName)) { jaroslav@1166: return false; jaroslav@1166: } jaroslav@1166: if (this.width != other.width) { jaroslav@1166: return false; jaroslav@1166: } jaroslav@1166: if (this.height != other.height) { jaroslav@1166: return false; jaroslav@1166: } jaroslav@1166: if (this.isDefault != other.isDefault) { jaroslav@1166: return false; jaroslav@1166: } jaroslav@1166: return true; jaroslav@1166: } jaroslav@1166: jaroslav@1166: @Override jaroslav@1166: public int hashCode() { jaroslav@1166: int hash = 7; jaroslav@1166: hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0); jaroslav@1166: hash = 11 * hash + (this.displayName != null ? this.displayName.hashCode() : 0); jaroslav@1166: hash = 11 * hash + this.width; jaroslav@1166: hash = 11 * hash + this.height; jaroslav@1166: hash = 11 * hash + (this.isDefault ? 1 : 0); jaroslav@1166: return hash; jaroslav@1166: } jaroslav@1166: } jaroslav@1166: }