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 = new Button("Apply custom selection model");
 171             applyCustomSelectionModel.setId(APPLY_CUSTOM_SELECTION_MODEL_BUTTON_ID);
 172             applyCustomSelectionModel.setOnAction(new EventHandler<ActionEvent>() {
 173                 public void handle(ActionEvent t) {
 174                     testedComboBox.selectionModelProperty().setValue(selectionModel);
 175                 }
 176             });
 177 
 178             Button applyCustomStringConverter = new Button("Apply custom string converter");
 179             applyCustomStringConverter.setId(APPLY_CUSTOM_STRING_CONVERTER_BUTTON_ID);
 180             applyCustomStringConverter.setOnAction(new EventHandler<ActionEvent>() {
 181                 public void handle(ActionEvent t) {
 182                     testedComboBox.setConverter(new CustomStringConverter());
 183                 }
 184             });
 185 
 186             Button applyCustomCellFactory = new Button("Apply custom cell factory");
 187             applyCustomCellFactory.setId(APPLY_CUSTOM_CELL_FACTORY_BUTTON_ID);
 188             applyCustomCellFactory.setOnAction(new EventHandler<ActionEvent>() {
 189                 public void handle(ActionEvent t) {
 190                     testedComboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
 191                         public ListCell<String> call(ListView<String> p) {
 192                             tb.incrementCounter(CALLBACK_CALLED_ID);
 193                             return new TextFieldListCell();
 194                         }
 195                     });
 196                 }
 197             });
 198 
 199             Button hardResetButton = new Button("Hard reset");
 200             hardResetButton.setId(HARD_RESET_BUTTON_ID);
 201             hardResetButton.setOnAction(new EventHandler<ActionEvent>() {
 202                 public void handle(ActionEvent t) {
 203                     HBox hb = (HBox) getRoot();
 204                     hb.getChildren().clear();
 205                     prepareMainSceneStructure();
 206                     prepareScene();
 207                 }
 208             });
 209 
 210             Button softResetButton = new Button("Soft reset");
 211             softResetButton.setId(SOFT_RESET_BUTTON_ID);
 212             softResetButton.setOnAction(new EventHandler<ActionEvent>() {
 213                 public void handle(ActionEvent t) {
 214                     tb.refresh();
 215                     ComboBox<String> newOne = new ComboBox<String>();
 216                     //testedComboBox.setItems(FXCollections.observableArrayList());//RT-18945
 217                     while (testedComboBox.getItems().size() != 0) {
 218                         testedComboBox.getItems().remove(0);
 219                     }
 220                     testedComboBox.setPrefHeight(newOne.getPrefHeight());
 221                     testedComboBox.setPrefWidth(newOne.getPrefWidth());
 222                     testedComboBox.setVisibleRowCount(newOne.getVisibleRowCount());
 223                     testedComboBox.setPromptText(newOne.getPromptText());
 224                     testedComboBox.setValue(null);
 225                     testedComboBox.setEditable(newOne.isEditable());
 226                     testedComboBox.setVisible(newOne.isVisible());
 227                     //testedComboBox.showingProperty().setValue(newOne.isShowing());//Showing is readonly from 2.1.0b10.
 228                     testedComboBox.setConverter(newOne.getConverter());
 229                     testedComboBox.setCellFactory(newOne.getCellFactory());
 230                 }
 231             });
 232 
 233             HBox resetButtonsHBox = new HBox();
 234             resetButtonsHBox.getChildren().addAll(hardResetButton, softResetButton);
 235 
 236             Button setAddingElementsOnShowing = new Button("Set adding elements on showing");
 237             setAddingElementsOnShowing.setId(SET_ADDING_ELEMENTS_ON_SHOWING);
 238             setAddingElementsOnShowing.setOnAction(new EventHandler<ActionEvent>() {
 239                 public void handle(ActionEvent t) {
 240                     testedComboBox.setOnShowing(new EventHandler<Event>() {
 241                         public void handle(Event t) {
 242                             int index = ((ComboBox) testedComboBox).getItems().size();
 243                             ((ComboBox) testedComboBox).getItems().add(index, INITIAL_VALUE);
 244 
 245                             tb.incrementCounter(SET_ON_SHOWING_COUNTER);
 246                         }
 247                     });
 248                 }
 249             });
 250 
 251             Button restoreDefaultOnShowingHandler = new Button("Restore default onShowing handler");
 252             restoreDefaultOnShowingHandler.setId(RESTORE_ON_SHOWING_EVENT_HANDLER);
 253             restoreDefaultOnShowingHandler.setOnAction(new EventHandler<ActionEvent>() {
 254                 public void handle(ActionEvent t) {
 255                     testedComboBox.setOnShowing(new EventHandler<Event>() {
 256                         public void handle(Event t) {
 257                             tb.incrementCounter(SET_ON_SHOWING_COUNTER);
 258                         }
 259                     });
 260                 }
 261             });
 262 
 263             Button populateComboBoxWithFontSizes = new Button("Populate ComboBox with font sizes");
 264             populateComboBoxWithFontSizes.setId(POPULATE_COMBOBOX_WITH_FONT_SIZES);
 265             populateComboBoxWithFontSizes.setOnAction(new EventHandler<ActionEvent>() {
 266                 public void handle(ActionEvent t) {
 267 
 268                     testedComboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
 269                         @Override
 270                         public ListCell<String> call(ListView<String> p) {
 271                             return new ListCell<String>() {
 272                                 {
 273                                     setContentDisplay(ContentDisplay.TEXT_ONLY);
 274                                 }
 275 
 276                                 @Override
 277                                 protected void updateItem(String item, boolean empty) {
 278                                     super.updateItem(item, empty);
 279 
 280                                     if (item == null || empty) {
 281                                         setText(null);
 282                                     } else {
 283                                         setText(item);
 284                                         setFont(new Font(Double.valueOf(item)));
 285                                     }
 286                                 }
 287                             };
 288                         }
 289                     });
 290 
 291                     for (int i = INITIAL_FONT_SIZE; i <= MAX_FONT_SIZE; i += 2) {
 292                         testedComboBox.getItems().add(String.valueOf(i));
 293                     }
 294                 }
 295             });
 296 
 297             setTestedControl(testedComboBox);
 298 
 299             VBox vb = new VBox();
 300             vb.setSpacing(5);
 301             vb.getChildren().addAll(resetButtonsHBox, getAddItemHBox(), getRemoveItemHBox(),
 302                     applyCustomSelectionModel, applyCustomStringConverter,
 303                     flushCalledMethodsInSelectionModel, applyCustomCellFactory,
 304                     setAddingElementsOnShowing,
 305                     restoreDefaultOnShowingHandler,
 306                     populateComboBoxWithFontSizes,
 307                     getSetItemsNullHBox());
 308             setControllersContent(vb);
 309 
 310             setPropertiesContent(tb);
 311         }
 312 
 313         private HBox getAddItemHBox() {
 314             HBox hb = new HBox();
 315             Label lb = new Label("Add item");
 316             final TextField tf = new TextField();
 317             tf.setPrefWidth(50);
 318             tf.setId(ADD_ITEM_TEXT_FIELD_ID);
 319             Label atLb = new Label("at pos");
 320             final TextField tfPos = new TextField();
 321             tfPos.setPrefWidth(50);
 322             tfPos.setId(ADD_ITEM_POSITION_TEXT_FIELD_ID);
 323             Button bt = new Button("Add!");
 324             bt.setId(ADD_ITEM_BUTTON_ID);
 325             bt.setOnAction(new EventHandler() {
 326                 public void handle(Event t) {
 327                     int index = Integer.parseInt(tfPos.getText());
 328                     ((ComboBox) testedComboBox).getItems().add(index, tf.getText());
 329                 }
 330             });
 331             hb.getChildren().addAll(lb, tf, atLb, tfPos, bt);
 332             return hb;
 333         }
 334 
 335         private HBox getRemoveItemHBox() {
 336             HBox hb = new HBox();
 337             Label lb = new Label("From position");
 338             final TextField tf = new TextField("0");
 339             tf.setPrefWidth(50);
 340             tf.setId(REMOVE_ITEM_POS_TEXT_FIELD_ID);
 341             Button bt = new Button("Remove!");
 342             bt.setId(REMOVE_BUTTON_ID);
 343             bt.setOnAction(new EventHandler() {
 344                 public void handle(Event t) {
 345                     int index = Integer.parseInt(tf.getText());
 346                     ((ComboBox) testedComboBox).getItems().remove(index);
 347                 }
 348             });
 349             hb.getChildren().addAll(lb, tf, bt);
 350             return hb;
 351         }
 352 
 353         private HBox getSetItemsNullHBox() {
 354             HBox hb = new HBox();
 355 
 356             Button bt = new Button("Set items null");
 357             bt.setId(SET_ITEMS_NULL_BUTTON_ID);
 358             bt.setOnAction(new EventHandler() {
 359                 public void handle(Event t) {
 360                     ((ComboBox) testedComboBox).setItems(null);
 361                 }
 362             });
 363             hb.getChildren().addAll(bt);
 364             return hb;
 365         }
 366 
 367         class TextFieldListCell extends ListCell<String> {
 368 
 369             public TextFieldListCell() {
 370                 setEditable(true);
 371             }
 372 
 373             @Override
 374             public void startEdit() {
 375                 tb.incrementCounter(CUSTOM_CELL_START_EDIT_COUNTER);
 376                 super.startEdit();
 377 
 378                 setText(null);
 379                 setGraphic(null);
 380             }
 381 
 382             @Override
 383             public void cancelEdit() {
 384                 tb.incrementCounter(CUSTOM_CELL_CANCEL_EDIT_COUNTER);
 385                 super.cancelEdit();
 386 
 387                 setText(null);
 388                 setGraphic(null);
 389             }
 390 
 391             @Override
 392             public void updateItem(String item, boolean empty) {
 393                 tb.incrementCounter(CUSTOM_CELL_UPDATE_EDIT_COUNTER);
 394                 super.updateItem(item, empty);
 395 
 396                 if (empty) {
 397                     setText(null);
 398                     setGraphic(null);
 399                 } else {
 400                     if (isEditing()) {
 401                         tb.incrementCounter(CUSTOM_CELL_UPDATE_EDIT_FOR_EDITABLE_CELL_COUNTER);
 402                     } else {
 403                         setText(CUSTOM_CELL_FACTORY_ITEM_SUFFIX + item);
 404                         setGraphic(null);
 405                     }
 406                 }
 407             }
 408         }
 409     }
 410 
 411     /**
 412      * MyMessageFormat wraps java.text.MessageFormat to provide a possibility to
 413      * format only one object, in order to be used by
 414      * javafx.util.converter.FormatStringConverter, because
 415      * java.text.MessageFormat works only with array of objects.
 416      *
 417      * @see java.text.MessageFormat
 418      * @see javafx.util.converter.FormatStringConverter
 419      */
 420     public static class MyMessageFormat extends Format {
 421 
 422         private MessageFormat fmt;
 423 
 424         public MyMessageFormat(MessageFormat fmt) {
 425             this.fmt = fmt;
 426         }
 427 
 428         @Override
 429         public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
 430             if (!obj.getClass().isAssignableFrom(Object[].class)) {
 431                 return fmt.format(new Object[]{obj}, toAppendTo, pos);
 432             } else {
 433                 return fmt.format(obj, toAppendTo, pos);
 434             }
 435         }
 436 
 437         @Override
 438         public Object parseObject(String source, ParsePosition pos) {
 439             Object parseObject = fmt.parseObject(source, pos);
 440             if (parseObject.getClass().isAssignableFrom(Object[].class)) {
 441                 int length = ((Object[]) parseObject).length;
 442                 if (length == 1) {
 443                     return ((Object[]) parseObject)[0];
 444                 }
 445             }
 446             return parseObject;
 447         }
 448     }
 449 }