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 javafx.scene.control.skin.AccordionSkin; 32 import com.sun.javafx.scene.control.skin.resources.ControlResources; 33 import hello.HelloAccordion; 34 import javafx.beans.binding.DoubleBinding; 35 import javafx.collections.ListChangeListener; 36 import javafx.event.ActionEvent; 37 import javafx.event.EventHandler; 38 import javafx.geometry.Insets; 39 import javafx.geometry.Pos; 40 import javafx.geometry.VPos; 41 import javafx.scene.Node; 42 import javafx.scene.control.Button; 43 import javafx.scene.control.ButtonBar.ButtonData; 44 import javafx.scene.control.ButtonType; 45 import javafx.scene.control.Dialog; 46 import javafx.scene.control.DialogPane; 47 import javafx.scene.control.Label; 48 import javafx.scene.image.Image; 49 import javafx.scene.image.ImageView; 50 import javafx.scene.layout.GridPane; 51 import javafx.scene.layout.Priority; 52 53 public class CommandLinksDialog extends Dialog<ButtonType> { 54 55 private final static int gapSize = 10; 56 57 private final List<Button> buttons = new ArrayList<>(); 58 59 private GridPane grid = new GridPane() { 60 @Override protected double computePrefWidth(double height) { 61 double pw = 0; 62 63 for (int i = 0; i < buttons.size(); i++) { 64 Button btn = buttons.get(i); 65 pw = Math.min(pw, btn.prefWidth(-1)); 66 } 67 return pw + gapSize; 68 } 69 70 @Override protected double computePrefHeight(double width) { 71 double ph = getDialogPane().getHeader() == null ? 0 : 10; 72 73 for (int i = 0; i < buttons.size(); i++) { 74 Button btn = buttons.get(i); 75 ph += btn.prefHeight(width) + gapSize; 76 } 77 return ph * 1.5; 78 } 79 }; 80 81 public CommandLinksDialog(ButtonType... links) { 82 this(Arrays.asList(links)); 83 } 84 85 public CommandLinksDialog(List<ButtonType> links) { 86 this.grid.setHgap(gapSize); 87 this.grid.setVgap(gapSize); 88 89 final DialogPane dialogPane = new DialogPane() { 90 @Override protected Node createButtonBar() { 91 return null; 92 } 93 }; 94 setDialogPane(dialogPane); 95 96 dialogPane.getStylesheets().add(getClass().getResource("commandlink.css").toExternalForm()); 97 98 setTitle(ControlResources.getString("Dialog.info.title")); 99 100 // FIXME extract to CSS 101 dialogPane.setGraphic(new ImageView(new Image(AccordionSkin.class.getResource("modena/dialog-information.png").toExternalForm()))); 102 dialogPane.getButtonTypes().addAll(links); 103 104 dialogPane.contentProperty().addListener(o -> updateGrid()); 105 106 updateGrid(); 107 dialogPane.getButtonTypes().addListener((ListChangeListener<? super ButtonType>)c -> { 108 updateGrid(); 109 }); 110 } 111 112 private void updateGrid() { 113 final Node content = getDialogPane().getContent(); 114 final boolean dialogContentIsGrid = grid == content; 115 116 if (! dialogContentIsGrid) { 117 if (content != null) { 118 content.getStyleClass().add("command-link-message"); 119 grid.add(content, 0, 0); 120 } 121 } 122 123 grid.getChildren().removeAll(buttons); 124 int row = 1; 125 for (final ButtonType action : getDialogPane().getButtonTypes()) { 126 if (action == null) continue; 127 128 // if (! (action instanceof DialogButton)) { 129 // throw new IllegalArgumentException("All actions in CommandLinksDialog must be instances of DialogAction"); 130 // } 131 // 132 // DialogButton commandLink = (DialogButton) action; 133 134 // //replace link's event handler with a proper one 135 // commandLink.setOnAction(new EventHandler<ActionEvent>() { 136 // @Override public void handle(ActionEvent ae) { 137 // setResult(commandLink); 138 // } 139 // }); 140 141 final Button button = buildCommandLinkButton(action); 142 final ButtonData buttonType = action.getButtonData(); 143 button.setDefaultButton(buttonType != null && buttonType.isDefaultButton()); 144 // button.setOnAction(commandLink); 145 146 button.setOnAction(new EventHandler<ActionEvent>() { 147 @Override public void handle(ActionEvent ae) { 148 setResult(action); 149 } 150 }); 151 152 GridPane.setHgrow(button, Priority.ALWAYS); 153 GridPane.setVgrow(button, Priority.ALWAYS); 154 grid.add(button, 0, row++); 155 buttons.add(button); 156 } 157 158 // last button gets some extra padding (hacky) 159 GridPane.setMargin(buttons.get(buttons.size() - 1), new Insets(0,0,10,0)); 160 161 if (! dialogContentIsGrid) { 162 getDialogPane().setContent(grid); 163 } 164 } 165 166 private Button buildCommandLinkButton(ButtonType commandLink) { 167 // put the content inside a button 168 final Button button = new Button(); 169 button.getStyleClass().addAll("command-link-button"); 170 button.setMaxHeight(Double.MAX_VALUE); 171 button.setMaxWidth(Double.MAX_VALUE); 172 button.setAlignment(Pos.CENTER_LEFT); 173 174 final Label titleLabel = new Label(commandLink.getText() ); 175 titleLabel.minWidthProperty().bind(new DoubleBinding() { 176 { 177 bind(titleLabel.prefWidthProperty()); 178 } 179 180 @Override protected double computeValue() { 181 return titleLabel.getPrefWidth() + 400; 182 } 183 }); 184 titleLabel.getStyleClass().addAll("line-1"); 185 titleLabel.setWrapText(true); 186 titleLabel.setAlignment(Pos.TOP_LEFT); 187 GridPane.setVgrow(titleLabel, Priority.NEVER); 188 189 // TODO no support in DialogButton for long text or graphic 190 // Label messageLabel = new Label(commandLink.getLongText() ); 191 // messageLabel.getStyleClass().addAll("line-2"); 192 // messageLabel.setWrapText(true); 193 // messageLabel.setAlignment(Pos.TOP_LEFT); 194 // messageLabel.setMaxHeight(Double.MAX_VALUE); 195 // GridPane.setVgrow(messageLabel, Priority.SOMETIMES); 196 // 197 // Image commandLinkImage = commandLink.getGraphic(); 198 // Node view = commandLinkImage == null ? 199 // new ImageView(getClass().getResource("arrow-green-right.png").toExternalForm()) : 200 // new ImageView(commandLinkImage); 201 // Pane graphicContainer = new Pane(view); 202 // graphicContainer.getStyleClass().add("graphic-container"); 203 ImageView arrow = new ImageView(HelloAccordion.class.getResource("about_16.png").toExternalForm()); 204 GridPane.setValignment(arrow, VPos.TOP); 205 GridPane.setMargin(arrow, new Insets(0,10,0,0)); 206 207 GridPane grid = new GridPane(); 208 grid.minWidthProperty().bind(titleLabel.prefWidthProperty()); 209 grid.setMaxHeight(Double.MAX_VALUE); 210 grid.setMaxWidth(Double.MAX_VALUE); 211 grid.getStyleClass().add("container"); 212 grid.add(arrow, 0, 0, 1, 2); 213 grid.add(titleLabel, 1, 0); 214 // grid.add(messageLabel, 1, 1); 215 216 button.setGraphic(grid); 217 button.minWidthProperty().bind(titleLabel.prefWidthProperty()); 218 219 return button; 220 } 221 }