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 javafx.scene.control; 26 27 import java.util.Arrays; 28 import java.util.Collection; 29 30 import com.sun.javafx.scene.control.skin.AccordionSkin; 31 import com.sun.javafx.scene.control.skin.resources.ControlResources; 32 import javafx.application.Platform; 33 import javafx.beans.property.ReadOnlyObjectProperty; 34 import javafx.collections.ObservableList; 35 import javafx.scene.image.Image; 36 import javafx.scene.image.ImageView; 37 import javafx.scene.layout.GridPane; 38 import javafx.scene.layout.Priority; 39 import javafx.scene.layout.Region; 40 41 /** 42 * A dialog that shows a list of choices to the user, from which they can pick 43 * one item at most. 44 * 45 * @see Dialog 46 * @param <T> The type of the items to show to the user, and the type that is returned 47 * via {@link #getResult()} when the dialog is dismissed. 48 * @since JavaFX 8u40 49 */ 50 public class ChoiceDialog<T> extends Dialog<T> { 51 52 /************************************************************************** 53 * 54 * Fields 55 * 56 **************************************************************************/ 57 58 private final GridPane grid; 59 private final Label label; 60 private final ComboBox<T> comboBox; 61 private final T defaultChoice; 62 63 64 65 /************************************************************************** 66 * 67 * Constructors 68 * 69 **************************************************************************/ 70 71 /** 72 * Creates a default, empty instance of ChoiceDialog with no set items and a 73 * null default choice. Users of this constructor will subsequently need to 74 * call {@link #getItems()} to specify which items to show to the user. 75 */ 76 public ChoiceDialog() { 77 this((T)null, (T[])null); 78 } 79 80 /** 81 * Creates a new ChoiceDialog instance with the first argument specifying the 82 * default choice that should be shown to the user, and all following arguments 83 * considered a varargs array of all available choices for the user. It is 84 * expected that the defaultChoice be one of the elements in the choices varargs 85 * array. If this is not true, then defaultChoice will be set to null and the 86 * dialog will show with the initial choice set to the first item in the list 87 * of choices. 88 * 89 * @param defaultChoice The item to display as the pre-selected choice in the dialog. 90 * This item must be contained within the choices varargs array. 91 * @param choices All possible choices to present to the user. 92 */ 93 public ChoiceDialog(T defaultChoice, @SuppressWarnings("unchecked") T... choices) { 94 this(defaultChoice, Arrays.asList(choices)); 95 } 96 97 /** 98 * Creates a new ChoiceDialog instance with the first argument specifying the 99 * default choice that should be shown to the user, and the second argument 100 * specifying a collection of all available choices for the user. It is 101 * expected that the defaultChoice be one of the elements in the choices 102 * collection. If this is not true, then defaultChoice will be set to null and the 103 * dialog will show with the initial choice set to the first item in the list 104 * of choices. 105 * 106 * @param defaultChoice The item to display as the pre-selected choice in the dialog. 107 * This item must be contained within the choices varargs array. 108 * @param choices All possible choices to present to the user. 109 */ 110 public ChoiceDialog(T defaultChoice, Collection<T> choices) { 111 final DialogPane dialogPane = getDialogPane(); 112 113 // -- grid 114 this.grid = new GridPane(); 115 this.grid.setHgap(10); 116 this.grid.setMaxWidth(Double.MAX_VALUE); 117 118 // -- label 119 label = DialogPane.createContentLabel(dialogPane.getContentText()); 120 label.setPrefWidth(Region.USE_COMPUTED_SIZE); 121 label.textProperty().bind(dialogPane.contentTextProperty()); 122 123 dialogPane.contentTextProperty().addListener(o -> updateGrid()); 124 125 setTitle(ControlResources.getString("Dialog.confirm.title")); 126 dialogPane.setHeaderText(ControlResources.getString("Dialog.confirm.header")); 127 128 // TODO extract out to CSS 129 dialogPane.setGraphic(new ImageView(new Image(AccordionSkin.class.getResource("modena/dialog-confirm.png").toExternalForm()))); 130 dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); 131 132 final double MIN_WIDTH = 150; 133 134 comboBox = new ComboBox<T>(); 135 comboBox.setMinWidth(MIN_WIDTH); 136 if (choices != null) { 137 comboBox.getItems().addAll(choices); 138 } 139 comboBox.setMaxWidth(Double.MAX_VALUE); 140 GridPane.setHgrow(comboBox, Priority.ALWAYS); 141 GridPane.setFillWidth(comboBox, true); 142 143 this.defaultChoice = comboBox.getItems().contains(defaultChoice) ? defaultChoice : null; 144 145 if (defaultChoice == null) { 146 comboBox.getSelectionModel().selectFirst(); 147 } else { 148 comboBox.getSelectionModel().select(defaultChoice); 149 } 150 151 updateGrid(); 152 153 setResultConverter(dialogButton -> dialogButton == ButtonType.OK ? getSelectedItem() : null); 154 } 155 156 157 158 /************************************************************************** 159 * 160 * Public API 161 * 162 **************************************************************************/ 163 164 /** 165 * Returns the currently selected item in the dialog. 166 */ 167 public final T getSelectedItem() { 168 return comboBox.getSelectionModel().getSelectedItem(); 169 } 170 171 /** 172 * Returns the property representing the currently selected item in the dialog. 173 */ 174 public final ReadOnlyObjectProperty<T> selectedItemProperty() { 175 return comboBox.getSelectionModel().selectedItemProperty(); 176 } 177 178 /** 179 * Sets the currently selected item in the dialog. 180 * @param item The item to select in the dialog. 181 */ 182 public final void setSelectedItem(T item) { 183 comboBox.getSelectionModel().select(item); 184 } 185 186 /** 187 * Returns the list of all items that will be displayed to users. This list 188 * can be modified by the developer to add, remove, or reorder the items 189 * to present to the user. 190 */ 191 public final ObservableList<T> getItems() { 192 return comboBox.getItems(); 193 } 194 195 /** 196 * Returns the default choice that was specified in the constructor. 197 */ 198 public final T getDefaultChoice() { 199 return defaultChoice; 200 } 201 202 203 204 /************************************************************************** 205 * 206 * Private Implementation 207 * 208 **************************************************************************/ 209 210 private void updateGrid() { 211 grid.getChildren().clear(); 212 213 grid.add(label, 0, 0); 214 grid.add(comboBox, 1, 0); 215 getDialogPane().setContent(grid); 216 217 Platform.runLater(() -> comboBox.requestFocus()); 218 } 219 }