1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package hello.dialog.dialogs; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.List; 30 31 import com.sun.javafx.scene.control.skin.resources.ControlResources; 32 import hello.HelloAccordion; 33 import javafx.beans.binding.DoubleBinding; 34 import javafx.collections.ListChangeListener; 35 import javafx.event.ActionEvent; 36 import javafx.event.EventHandler; 37 import javafx.geometry.Insets; 38 import javafx.geometry.Pos; 39 import javafx.geometry.VPos; 40 import javafx.scene.Node; 41 import javafx.scene.control.Button; 42 import javafx.scene.control.ButtonBar.ButtonData; 43 import javafx.scene.control.ButtonType; 44 import javafx.scene.control.Dialog; 45 import javafx.scene.control.DialogPane; 46 import javafx.scene.control.Label; 47 import javafx.scene.image.Image; 48 import javafx.scene.image.ImageView; 49 import javafx.scene.layout.GridPane; 50 import javafx.scene.layout.Priority; 51 52 public class CommandLinksDialog extends Dialog<ButtonType> { 53 54 private final static int gapSize = 10; 55 56 private final List<Button> buttons = new ArrayList<>(); 57 58 private GridPane grid = new GridPane() { 59 @Override protected double computePrefWidth(double height) { 60 double pw = 0; 61 62 for (int i = 0; i < buttons.size(); i++) { 63 Button btn = buttons.get(i); 64 pw = Math.min(pw, btn.prefWidth(-1)); 65 } 66 return pw + gapSize; 67 } 68 69 @Override protected double computePrefHeight(double width) { 70 double ph = getDialogPane().getHeader() == null ? 0 : 10; 71 72 for (int i = 0; i < buttons.size(); i++) { 73 Button btn = buttons.get(i); 74 ph += btn.prefHeight(width) + gapSize; 75 } 76 return ph * 1.5; 77 } 78 }; 79 80 public CommandLinksDialog(ButtonType... links) { 81 this(Arrays.asList(links)); 82 } 83 84 public CommandLinksDialog(List<ButtonType> links) { 85 this.grid.setHgap(gapSize); 86 this.grid.setVgap(gapSize); 87 88 final DialogPane dialogPane = new DialogPane() { 89 @Override protected Node createButtonBar() { 90 return null; 91 } 92 }; 93 setDialogPane(dialogPane); 94 95 dialogPane.getStylesheets().add(getClass().getResource("commandlink.css").toExternalForm()); 96 97 setTitle(ControlResources.getString("Dialog.info.title")); 98 99 // FIXME extract to CSS 100 dialogPane.setGraphic(new ImageView(new Image(HelloAccordion.class.getResource("dialog/dialog-information.png").toExternalForm()))); 101 dialogPane.getButtonTypes().addAll(links); 102 103 dialogPane.contentProperty().addListener(o -> updateGrid()); 104 105 updateGrid(); 106 dialogPane.getButtonTypes().addListener((ListChangeListener<? super ButtonType>)c -> { 107 updateGrid(); 108 }); 109 } 110 111 private void updateGrid() { 112 final Node content = getDialogPane().getContent(); 113 final boolean dialogContentIsGrid = grid == content; 114 115 if (! dialogContentIsGrid) { 116 if (content != null) { 117 content.getStyleClass().add("command-link-message"); 118 grid.add(content, 0, 0); 119 } 120 } 121 122 grid.getChildren().removeAll(buttons); 123 int row = 1; 124 for (final ButtonType action : getDialogPane().getButtonTypes()) { 125 if (action == null) continue; 126 127 // if (! (action instanceof DialogButton)) { 128 // throw new IllegalArgumentException("All actions in CommandLinksDialog must be instances of DialogAction"); 129 // } 130 // 131 // DialogButton commandLink = (DialogButton) action; 132 133 // //replace link's event handler with a proper one 134 // commandLink.setOnAction(new EventHandler<ActionEvent>() { 135 // @Override public void handle(ActionEvent ae) { 136 // setResult(commandLink); 137 // } 138 // }); 139 140 final Button button = buildCommandLinkButton(action); 141 final ButtonData buttonType = action.getButtonData(); 142 button.setDefaultButton(buttonType != null && buttonType.isDefaultButton()); 143 // button.setOnAction(commandLink); 144 145 button.setOnAction(new EventHandler<ActionEvent>() { 146 @Override public void handle(ActionEvent ae) { 147 setResult(action); 148 } 149 }); 150 151 GridPane.setHgrow(button, Priority.ALWAYS); 152 GridPane.setVgrow(button, Priority.ALWAYS); 153 grid.add(button, 0, row++); 154 buttons.add(button); 155 } 156 157 // last button gets some extra padding (hacky) 158 GridPane.setMargin(buttons.get(buttons.size() - 1), new Insets(0,0,10,0)); 159 160 if (! dialogContentIsGrid) { 161 getDialogPane().setContent(grid); 162 } 163 } 164 165 private Button buildCommandLinkButton(ButtonType commandLink) { 166 // put the content inside a button 167 final Button button = new Button(); 168 button.getStyleClass().addAll("command-link-button"); 169 button.setMaxHeight(Double.MAX_VALUE); 170 button.setMaxWidth(Double.MAX_VALUE); 171 button.setAlignment(Pos.CENTER_LEFT); 172 173 final Label titleLabel = new Label(commandLink.getText() ); 174 titleLabel.minWidthProperty().bind(new DoubleBinding() { 175 { 176 bind(titleLabel.prefWidthProperty()); 177 } 178 179 @Override protected double computeValue() { 180 return titleLabel.getPrefWidth() + 400; 181 } 182 }); 183 titleLabel.getStyleClass().addAll("line-1"); 184 titleLabel.setWrapText(true); 185 titleLabel.setAlignment(Pos.TOP_LEFT); 186 GridPane.setVgrow(titleLabel, Priority.NEVER); 187 188 // TODO no support in DialogButton for long text or graphic 189 // Label messageLabel = new Label(commandLink.getLongText() ); 190 // messageLabel.getStyleClass().addAll("line-2"); 191 // messageLabel.setWrapText(true); 192 // messageLabel.setAlignment(Pos.TOP_LEFT); 193 // messageLabel.setMaxHeight(Double.MAX_VALUE); 194 // GridPane.setVgrow(messageLabel, Priority.SOMETIMES); 195 // 196 // Image commandLinkImage = commandLink.getGraphic(); 197 // Node view = commandLinkImage == null ? 198 // new ImageView(getClass().getResource("arrow-green-right.png").toExternalForm()) : 199 // new ImageView(commandLinkImage); 200 // Pane graphicContainer = new Pane(view); 201 // graphicContainer.getStyleClass().add("graphic-container"); 202 ImageView arrow = new ImageView(HelloAccordion.class.getResource("about_16.png").toExternalForm()); 203 GridPane.setValignment(arrow, VPos.TOP); 204 GridPane.setMargin(arrow, new Insets(0,10,0,0)); 205 206 GridPane grid = new GridPane(); 207 grid.minWidthProperty().bind(titleLabel.prefWidthProperty()); 208 grid.setMaxHeight(Double.MAX_VALUE); 209 grid.setMaxWidth(Double.MAX_VALUE); 210 grid.getStyleClass().add("container"); 211 grid.add(arrow, 0, 0, 1, 2); 212 grid.add(titleLabel, 1, 0); 213 // grid.add(messageLabel, 1, 1); 214 215 button.setGraphic(grid); 216 button.minWidthProperty().bind(titleLabel.prefWidthProperty()); 217 218 return button; 219 } 220 }