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 import java.util.Collections; 30 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.geometry.Pos; 36 import javafx.scene.control.ButtonBar.ButtonData; 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, 95 choices == null ? Collections.emptyList() : Arrays.asList(choices)); 96 } 97 98 /** 99 * Creates a new ChoiceDialog instance with the first argument specifying the 100 * default choice that should be shown to the user, and the second argument 101 * specifying a collection of all available choices for the user. It is 102 * expected that the defaultChoice be one of the elements in the choices 103 * collection. If this is not true, then defaultChoice will be set to null and the 104 * dialog will show with the initial choice set to the first item in the list 105 * of choices. 106 * 107 * @param defaultChoice The item to display as the pre-selected choice in the dialog. 108 * This item must be contained within the choices varargs array. 109 * @param choices All possible choices to present to the user. 110 */ 111 public ChoiceDialog(T defaultChoice, Collection<T> choices) { 112 final DialogPane dialogPane = getDialogPane(); 113 114 // -- grid 115 this.grid = new GridPane(); 116 this.grid.setHgap(10); 117 this.grid.setMaxWidth(Double.MAX_VALUE); 118 this.grid.setAlignment(Pos.CENTER_LEFT); 119 120 // -- label 121 label = DialogPane.createContentLabel(dialogPane.getContentText()); 122 label.setPrefWidth(Region.USE_COMPUTED_SIZE); 123 label.textProperty().bind(dialogPane.contentTextProperty()); 124 125 dialogPane.contentTextProperty().addListener(o -> updateGrid()); 126 127 setTitle(ControlResources.getString("Dialog.confirm.title")); 128 dialogPane.setHeaderText(ControlResources.getString("Dialog.confirm.header")); 129 dialogPane.getStyleClass().add("choice-dialog"); 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) -> { 154 ButtonData data = dialogButton == null ? null : dialogButton.getButtonData(); 155 return data == ButtonData.OK_DONE ? getSelectedItem() : null; 156 }); 157 } 158 159 160 161 /************************************************************************** 162 * 163 * Public API 164 * 165 **************************************************************************/ 166 167 /** 168 * Returns the currently selected item in the dialog. 169 * @return the currently selected item 170 */ 171 public final T getSelectedItem() { 172 return comboBox.getSelectionModel().getSelectedItem(); 173 } 174 175 /** 176 * Returns the property representing the currently selected item in the dialog. 177 * @return the currently selected item property 178 */ 179 public final ReadOnlyObjectProperty<T> selectedItemProperty() { 180 return comboBox.getSelectionModel().selectedItemProperty(); 181 } 182 183 /** 184 * Sets the currently selected item in the dialog. 185 * @param item The item to select in the dialog. 186 */ 187 public final void setSelectedItem(T item) { 188 comboBox.getSelectionModel().select(item); 189 } 190 191 /** 192 * Returns the list of all items that will be displayed to users. This list 193 * can be modified by the developer to add, remove, or reorder the items 194 * to present to the user. 195 * @return the list of all items that will be displayed to users 196 */ 197 public final ObservableList<T> getItems() { 198 return comboBox.getItems(); 199 } 200 201 /** 202 * Returns the default choice that was specified in the constructor. 203 * @return the default choice 204 */ 205 public final T getDefaultChoice() { 206 return defaultChoice; 207 } 208 209 210 211 /************************************************************************** 212 * 213 * Private Implementation 214 * 215 **************************************************************************/ 216 217 private void updateGrid() { 218 grid.getChildren().clear(); 219 220 grid.add(label, 0, 0); 221 grid.add(comboBox, 1, 0); 222 getDialogPane().setContent(grid); 223 224 Platform.runLater(() -> comboBox.requestFocus()); 225 } 226 }