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.test.combobox;
  26 
  27 import java.text.FieldPosition;
  28 import java.text.Format;
  29 import java.text.MessageFormat;
  30 import java.text.ParsePosition;
  31 import javafx.event.ActionEvent;
  32 import javafx.event.Event;
  33 import javafx.event.EventHandler;
  34 import javafx.scene.Scene;
  35 import javafx.scene.control.*;
  36 import javafx.scene.control.test.utils.CommonPropertiesScene;
  37 import javafx.scene.control.test.utils.CustomStringConverter;
  38 import javafx.scene.control.test.utils.SingleSelectionModelImpl;
  39 import javafx.scene.control.test.utils.ptables.PropertiesTable;
  40 import javafx.scene.control.test.utils.ptables.PropertyTablesFactory;
  41 import javafx.scene.layout.HBox;
  42 import javafx.scene.layout.VBox;
  43 import javafx.scene.text.Font;
  44 import javafx.util.Callback;
  45 import test.javaclient.shared.InteroperabilityApp;
  46 import test.javaclient.shared.Utils;
  47 
  48 /**
  49  * @author Alexander Kirov
  50  */
  51 public class ComboBoxApp extends InteroperabilityApp {
  52 
  53     public final static String TESTED_COMBOBOX_ID = "TESTED_COMBOBOX_ID";
  54     public final static String HARD_RESET_BUTTON_ID = "HARD_RESET_COMBOBOX_BUTTON_ID";
  55     public final static String SOFT_RESET_BUTTON_ID = "SOFT_RESET_COMBOBOX_BUTTON_ID";
  56     public final static String ADD_ITEM_BUTTON_ID = "ADD_ITEM_BUTTON_ID";
  57     public final static String ADD_ITEM_POSITION_TEXT_FIELD_ID = "ADD_ITEM_POSITION_TEXT_FIELD_ID";
  58     public final static String ADD_ITEM_TEXT_FIELD_ID = "ADD_ITEM_TEXT_FIELD_ID";
  59     public final static String REMOVE_BUTTON_ID = "REMOVE_BUTTON_ID";
  60     public final static String REMOVE_ITEM_POS_TEXT_FIELD_ID = "REMOVE_ITEM_POS_TEXT_FIELD_ID";
  61     public final static String ON_ACTION_EVENT_COUNTER_ID = "ON_ACTION_EVENT_COUNTER";
  62     public final static String APPLY_CUSTOM_SELECTION_MODEL_BUTTON_ID = "APPLY_CUSTOM_SELECTION_MODEL_BUTTON_ID";
  63     public final static String APPLY_CUSTOM_STRING_CONVERTER_BUTTON_ID = "APPLY_CUSTOM_STRING_CONVERTER_BUTTON_ID";
  64     public final static String CUSTOM_CELL_START_EDIT_COUNTER = "CELL START EDIT";
  65     public final static String CUSTOM_CELL_CANCEL_EDIT_COUNTER = "CELL CANCEL EDIT";
  66     public final static String CUSTOM_CELL_UPDATE_EDIT_COUNTER = "CELL UPDATE EDIT";
  67     public final static String APPLY_CUSTOM_CELL_FACTORY_BUTTON_ID = "APPLIED CUSTOM CELL FACTORY";
  68     public final static String CALLBACK_CALLED_ID = "CALLBACK CALLED";
  69     public final static String CUSTOM_CELL_UPDATE_EDIT_FOR_EDITABLE_CELL_COUNTER = "UPDATE EDIT FOR EDITABLE CELL";
  70     public final static String CUSTOM_CELL_FACTORY_ITEM_SUFFIX = "Custom";
  71     public final static String INITIAL_VALUE = "Initial value";
  72     public final static String SET_ON_SHOWING_COUNTER = "SET_ON_SHOWING_COUNTER";
  73     public final static String SET_ON_SHOWN_COUNTER = "SET_ON_SHOWN_COUNTER";
  74     public final static String SET_ON_HIDING_COUNTER = "SET_ON_HIDING_COUNTER";
  75     public final static String SET_ON_HIDEN_COUNTER = "SET_ON_HIDEN_COUNTER";
  76     public final static String SET_ADDING_ELEMENTS_ON_SHOWING = "SET_ADDING_ELEMENTS_ON_SHOWING";
  77     public final static String RESTORE_ON_SHOWING_EVENT_HANDLER = "RESTORE_ON_SHOWING_EVENT_HANDLER";
  78     public final static String POPULATE_COMBOBOX_WITH_FONT_SIZES = "POPULATE_COMBOBOX_WITH_FONT_SIZES";
  79     public final static String SET_ITEMS_NULL_BUTTON_ID = "SET_ITEMS_NULL_BUTTON_ID";
  80     public final static int INITIAL_FONT_SIZE = 8;
  81     public final static int MAX_FONT_SIZE = 36;
  82 
  83     public static void main(String[] args) {
  84         Utils.launch(ComboBoxApp.class, args);
  85     }
  86 
  87     @Override
  88     protected Scene getScene() {
  89         Utils.setTitleToStage(stage, "ComboBoxTestApp");
  90         return new ComboBoxScene();
  91     }
  92 
  93     class ComboBoxScene extends CommonPropertiesScene {
  94 
  95         PropertiesTable tb;
  96         //ComboBox to be tested.
  97         ComboBox<String> testedComboBox;
  98 
  99         public ComboBoxScene() {
 100             super("ComboBox", 800, 600);
 101 
 102             prepareScene();
 103         }
 104 
 105         @Override
 106         final protected void prepareScene() {
 107             Utils.addBrowser(this);
 108             testedComboBox = new ComboBox<String>();
 109             testedComboBox.setId(TESTED_COMBOBOX_ID);
 110 
 111             tb = new PropertiesTable(testedComboBox);
 112             tb.addSimpleListener(testedComboBox.getSelectionModel().selectedIndexProperty(), testedComboBox.getSelectionModel());
 113             tb.addSimpleListener(testedComboBox.getSelectionModel().selectedItemProperty(), testedComboBox.getSelectionModel());
 114             tb.addSimpleListener(testedComboBox.getEditor().parentProperty(), testedComboBox.getEditor());
 115             tb.addStringLine(testedComboBox.getEditor().textProperty(), "", testedComboBox.getEditor());
 116             tb.addStringLine(testedComboBox.valueProperty(), INITIAL_VALUE);
 117             PropertyTablesFactory.explorePropertiesList(testedComboBox, tb);
 118 
 119             tb.addCounter(SET_ON_SHOWING_COUNTER);
 120             testedComboBox.setOnShowing(new EventHandler<Event>() {
 121                 public void handle(Event t) {
 122                     tb.incrementCounter(SET_ON_SHOWING_COUNTER);
 123                 }
 124             });
 125 
 126             tb.addCounter(SET_ON_SHOWN_COUNTER);
 127             testedComboBox.setOnShown(new EventHandler<Event>() {
 128                 public void handle(Event t) {
 129                     tb.incrementCounter(SET_ON_SHOWN_COUNTER);
 130                 }
 131             });
 132 
 133             tb.addCounter(SET_ON_HIDING_COUNTER);
 134             testedComboBox.setOnHiding(new EventHandler<Event>() {
 135                 public void handle(Event t) {
 136                     tb.incrementCounter(SET_ON_HIDING_COUNTER);
 137                 }
 138             });
 139 
 140             tb.addCounter(SET_ON_HIDEN_COUNTER);
 141             testedComboBox.setOnHidden(new EventHandler<Event>() {
 142                 public void handle(Event t) {
 143                     tb.incrementCounter(SET_ON_HIDEN_COUNTER);
 144                 }
 145             });
 146 
 147             tb.addCounter(ON_ACTION_EVENT_COUNTER_ID);
 148             testedComboBox.setOnAction(new EventHandler() {
 149                 public void handle(Event t) {
 150                     tb.incrementCounter(ON_ACTION_EVENT_COUNTER_ID);
 151                 }
 152             });
 153 
 154             tb.addCounter(CUSTOM_CELL_CANCEL_EDIT_COUNTER);
 155             tb.addCounter(CUSTOM_CELL_START_EDIT_COUNTER);
 156             tb.addCounter(CUSTOM_CELL_UPDATE_EDIT_COUNTER);
 157             tb.addCounter(CALLBACK_CALLED_ID);
 158 
 159             final SingleSelectionModel<String> selectionModel = new SingleSelectionModelImpl<String>(testedComboBox.getItems());
 160             Button flushCalledMethodsInSelectionModel = new Button("Flush called methods");
 161 //            flushCalledMethodsInSelectionModel.setOnAction(new EventHandler<ActionEvent>() {
 162 //
 163 //                public void handle(ActionEvent t) {
 164 //                    CMSM.setLogBuf(PropertyValueController.getLogger().textProperty());
 165 //                    CMSM.flushCalledMethods();
 166 //                    testedComboBox.setSelectionModel(selectionModel);
 167 //                }
 168 //            });
 169 
 170             Button applyCustomSelectionModel = ButtonBuilder.create().text("Apply custom selection model").id(APPLY_CUSTOM_SELECTION_MODEL_BUTTON_ID).build();
 171             applyCustomSelectionModel.setOnAction(new EventHandler<ActionEvent>() {
 172                 public void handle(ActionEvent t) {
 173                     testedComboBox.selectionModelProperty().setValue(selectionModel);
 174                 }
 175             });
 176 
 177             Button applyCustomStringConverter = ButtonBuilder.create().text("Apply custom string converter").id(APPLY_CUSTOM_STRING_CONVERTER_BUTTON_ID).build();
 178             applyCustomStringConverter.setOnAction(new EventHandler<ActionEvent>() {
 179                 public void handle(ActionEvent t) {
 180                     testedComboBox.setConverter(new CustomStringConverter());
 181                 }
 182             });
 183 
 184             Button applyCustomCellFactory = ButtonBuilder.create().text("Apply custom cell factory").id(APPLY_CUSTOM_CELL_FACTORY_BUTTON_ID).build();
 185             applyCustomCellFactory.setOnAction(new EventHandler<ActionEvent>() {
 186                 public void handle(ActionEvent t) {
 187                     testedComboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
 188                         public ListCell<String> call(ListView<String> p) {
 189                             tb.incrementCounter(CALLBACK_CALLED_ID);
 190                             return new TextFieldListCell();
 191                         }
 192                     });
 193                 }
 194             });
 195 
 196             Button hardResetButton = ButtonBuilder.create().id(HARD_RESET_BUTTON_ID).text("Hard reset").build();
 197             hardResetButton.setOnAction(new EventHandler<ActionEvent>() {
 198                 public void handle(ActionEvent t) {
 199                     HBox hb = (HBox) getRoot();
 200                     hb.getChildren().clear();
 201                     prepareMainSceneStructure();
 202                     prepareScene();
 203                 }
 204             });
 205 
 206             Button softResetButton = ButtonBuilder.create().id(SOFT_RESET_BUTTON_ID).text("Soft reset").build();
 207             softResetButton.setOnAction(new EventHandler<ActionEvent>() {
 208                 public void handle(ActionEvent t) {
 209                     tb.refresh();
 210                     ComboBox<String> newOne = new ComboBox<String>();
 211                     //testedComboBox.setItems(FXCollections.observableArrayList());//RT-18945
 212                     while (testedComboBox.getItems().size() != 0) {
 213                         testedComboBox.getItems().remove(0);
 214                     }
 215                     testedComboBox.setPrefHeight(newOne.getPrefHeight());
 216                     testedComboBox.setPrefWidth(newOne.getPrefWidth());
 217                     testedComboBox.setVisibleRowCount(newOne.getVisibleRowCount());
 218                     testedComboBox.setPromptText(newOne.getPromptText());
 219                     testedComboBox.setValue(null);
 220                     testedComboBox.setEditable(newOne.isEditable());
 221                     testedComboBox.setVisible(newOne.isVisible());
 222                     //testedComboBox.showingProperty().setValue(newOne.isShowing());//Showing is readonly from 2.1.0b10.
 223                     testedComboBox.setConverter(newOne.getConverter());
 224                     testedComboBox.setCellFactory(newOne.getCellFactory());
 225                 }
 226             });
 227 
 228             HBox resetButtonsHBox = new HBox();
 229             resetButtonsHBox.getChildren().addAll(hardResetButton, softResetButton);
 230 
 231             Button setAddingElementsOnShowing = ButtonBuilder.create()
 232                     .id(SET_ADDING_ELEMENTS_ON_SHOWING)
 233                     .text("Set adding elements on showing")
 234                     .build();
 235 
 236             setAddingElementsOnShowing.setOnAction(new EventHandler<ActionEvent>() {
 237                 public void handle(ActionEvent t) {
 238                     testedComboBox.setOnShowing(new EventHandler<Event>() {
 239                         public void handle(Event t) {
 240                             int index = ((ComboBox) testedComboBox).getItems().size();
 241                             ((ComboBox) testedComboBox).getItems().add(index, INITIAL_VALUE);
 242 
 243                             tb.incrementCounter(SET_ON_SHOWING_COUNTER);
 244                         }
 245                     });
 246                 }
 247             });
 248 
 249             Button restoreDefaultOnShowingHandler = ButtonBuilder.create()
 250                     .id(RESTORE_ON_SHOWING_EVENT_HANDLER)
 251                     .text("Restore default onShowing handler")
 252                     .build();
 253 
 254             restoreDefaultOnShowingHandler.setOnAction(new EventHandler<ActionEvent>() {
 255                 public void handle(ActionEvent t) {
 256                     testedComboBox.setOnShowing(new EventHandler<Event>() {
 257                         public void handle(Event t) {
 258                             tb.incrementCounter(SET_ON_SHOWING_COUNTER);
 259                         }
 260                     });
 261                 }
 262             });
 263 
 264             Button populateComboBoxWithFontSizes = ButtonBuilder.create()
 265                     .id(POPULATE_COMBOBOX_WITH_FONT_SIZES)
 266                     .text("Populate ComboBox with font sizes")
 267                     .build();
 268 
 269             populateComboBoxWithFontSizes.setOnAction(new EventHandler<ActionEvent>() {
 270                 public void handle(ActionEvent t) {
 271 
 272                     testedComboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
 273                         @Override
 274                         public ListCell<String> call(ListView<String> p) {
 275                             return new ListCell<String>() {
 276                                 {
 277                                     setContentDisplay(ContentDisplay.TEXT_ONLY);
 278                                 }
 279 
 280                                 @Override
 281                                 protected void updateItem(String item, boolean empty) {
 282                                     super.updateItem(item, empty);
 283 
 284                                     if (item == null || empty) {
 285                                         setText(null);
 286                                     } else {
 287                                         setText(item);
 288                                         setFont(new Font(Double.valueOf(item)));
 289                                     }
 290                                 }
 291                             };
 292                         }
 293                     });
 294 
 295                     for (int i = INITIAL_FONT_SIZE; i <= MAX_FONT_SIZE; i += 2) {
 296                         testedComboBox.getItems().add(String.valueOf(i));
 297                     }
 298                 }
 299             });
 300 
 301             setTestedControl(testedComboBox);
 302 
 303             VBox vb = new VBox();
 304             vb.setSpacing(5);
 305             vb.getChildren().addAll(resetButtonsHBox, getAddItemHBox(), getRemoveItemHBox(),
 306                     applyCustomSelectionModel, applyCustomStringConverter,
 307                     flushCalledMethodsInSelectionModel, applyCustomCellFactory,
 308                     setAddingElementsOnShowing,
 309                     restoreDefaultOnShowingHandler,
 310                     populateComboBoxWithFontSizes,
 311                     getSetItemsNullHBox());
 312             setControllersContent(vb);
 313 
 314             setPropertiesContent(tb);
 315         }
 316 
 317         private HBox getAddItemHBox() {
 318             HBox hb = new HBox();
 319             Label lb = new Label("Add item");
 320             final TextField tf = TextFieldBuilder.create().prefWidth(50).id(ADD_ITEM_TEXT_FIELD_ID).build();
 321             Label atLb = new Label("at pos");
 322             final TextField tfPos = TextFieldBuilder.create().prefWidth(50).id(ADD_ITEM_POSITION_TEXT_FIELD_ID).build();
 323             Button bt = ButtonBuilder.create().text("Add!").id(ADD_ITEM_BUTTON_ID).build();
 324             bt.setOnAction(new EventHandler() {
 325                 public void handle(Event t) {
 326                     int index = Integer.parseInt(tfPos.getText());
 327                     ((ComboBox) testedComboBox).getItems().add(index, tf.getText());
 328                 }
 329             });
 330             hb.getChildren().addAll(lb, tf, atLb, tfPos, bt);
 331             return hb;
 332         }
 333 
 334         private HBox getRemoveItemHBox() {
 335             HBox hb = new HBox();
 336             Label lb = new Label("From position");
 337             final TextField tf = TextFieldBuilder.create().text("0").prefWidth(50).id(REMOVE_ITEM_POS_TEXT_FIELD_ID).build();
 338             Button bt = ButtonBuilder.create().text("Remove!").id(REMOVE_BUTTON_ID).build();
 339             bt.setOnAction(new EventHandler() {
 340                 public void handle(Event t) {
 341                     int index = Integer.parseInt(tf.getText());
 342                     ((ComboBox) testedComboBox).getItems().remove(index);
 343                 }
 344             });
 345             hb.getChildren().addAll(lb, tf, bt);
 346             return hb;
 347         }
 348 
 349         private HBox getSetItemsNullHBox() {
 350             HBox hb = new HBox();
 351 
 352             Button bt = ButtonBuilder.create().text("Set items null").id(SET_ITEMS_NULL_BUTTON_ID).build();
 353             bt.setOnAction(new EventHandler() {
 354                 public void handle(Event t) {
 355                     ((ComboBox) testedComboBox).setItems(null);
 356                 }
 357             });
 358             hb.getChildren().addAll(bt);
 359             return hb;
 360         }
 361 
 362         class TextFieldListCell extends ListCell<String> {
 363 
 364             public TextFieldListCell() {
 365                 setEditable(true);
 366             }
 367 
 368             @Override
 369             public void startEdit() {
 370                 tb.incrementCounter(CUSTOM_CELL_START_EDIT_COUNTER);
 371                 super.startEdit();
 372 
 373                 setText(null);
 374                 setGraphic(null);
 375             }
 376 
 377             @Override
 378             public void cancelEdit() {
 379                 tb.incrementCounter(CUSTOM_CELL_CANCEL_EDIT_COUNTER);
 380                 super.cancelEdit();
 381 
 382                 setText(null);
 383                 setGraphic(null);
 384             }
 385 
 386             @Override
 387             public void updateItem(String item, boolean empty) {
 388                 tb.incrementCounter(CUSTOM_CELL_UPDATE_EDIT_COUNTER);
 389                 super.updateItem(item, empty);
 390 
 391                 if (empty) {
 392                     setText(null);
 393                     setGraphic(null);
 394                 } else {
 395                     if (isEditing()) {
 396                         tb.incrementCounter(CUSTOM_CELL_UPDATE_EDIT_FOR_EDITABLE_CELL_COUNTER);
 397                     } else {
 398                         setText(CUSTOM_CELL_FACTORY_ITEM_SUFFIX + item);
 399                         setGraphic(null);
 400                     }
 401                 }
 402             }
 403         }
 404     }
 405 
 406     /**
 407      * MyMessageFormat wraps java.text.MessageFormat to provide a possibility to
 408      * format only one object, in order to be used by
 409      * javafx.util.converter.FormatStringConverter, because
 410      * java.text.MessageFormat works only with array of objects.
 411      *
 412      * @see java.text.MessageFormat
 413      * @see javafx.util.converter.FormatStringConverter
 414      */
 415     public static class MyMessageFormat extends Format {
 416 
 417         private MessageFormat fmt;
 418 
 419         public MyMessageFormat(MessageFormat fmt) {
 420             this.fmt = fmt;
 421         }
 422 
 423         @Override
 424         public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
 425             if (!obj.getClass().isAssignableFrom(Object[].class)) {
 426                 return fmt.format(new Object[]{obj}, toAppendTo, pos);
 427             } else {
 428                 return fmt.format(obj, toAppendTo, pos);
 429             }
 430         }
 431 
 432         @Override
 433         public Object parseObject(String source, ParsePosition pos) {
 434             Object parseObject = fmt.parseObject(source, pos);
 435             if (parseObject.getClass().isAssignableFrom(Object[].class)) {
 436                 int length = ((Object[]) parseObject).length;
 437                 if (length == 1) {
 438                     return ((Object[]) parseObject)[0];
 439                 }
 440             }
 441             return parseObject;
 442         }
 443     }
 444 }