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.utils.ptables;
  26 
  27 import java.util.ArrayList;
  28 import java.util.Arrays;
  29 import java.util.Collection;
  30 import java.util.HashMap;
  31 import java.util.List;
  32 import javafx.beans.property.DoubleProperty;
  33 import javafx.beans.property.IntegerProperty;
  34 import javafx.beans.property.ObjectProperty;
  35 import javafx.beans.property.Property;
  36 import javafx.beans.property.ReadOnlyProperty;
  37 import javafx.scene.Node;
  38 import javafx.scene.layout.FlowPane;
  39 import javafx.scene.layout.FlowPaneBuilder;
  40 import javafx.scene.layout.VBox;
  41 import static javafx.scene.control.test.utils.ptables.AbstractApplicationPropertiesRegystry.DEFAULT_DOMAIN_NAME;
  42 
  43 /**
  44  * @author Alexander Kirov
  45  *
  46  * This class provide functionality, which is used for creating scene component,
  47  * which provide control over different tested control's (node's) properties.
  48  *
  49  * NOTION: this class should be instantiated on JavaFX thread.
  50  *
  51  * Use case: PropertiesTable axisProperties = new PropertiesTable(axis);
  52  * axisProperties.addBooleanPropertyLine(axis.animatedProperty());
  53  * axisProperties.addDoublePropertyLine(axis.tickLengthProperty(), -5, 50, 5);
  54  * axisProperties.addStringLine(axis.labelProperty(), "Label");
  55  * axisProperties.addSimpleListener(axis.hoverProperty(), axis);
  56  * axisProperties.addObjectEnumPropertyLine(axis.sideProperty(),
  57  * Arrays.asList(Side.values()));
  58  * someContainer.getChildren().add(axisProperties.getContent());//To see it on
  59  * scene.
  60  *
  61  * Automated PropertiesTable generation can be used: PropertiesTable tb = new
  62  * PropertiesTable(testedSlider); Slider testedSlider = new Slider();
  63  * PropertyTablesFactory.explorePropertiesList(testedSlider, tb);
  64  * SpecialTablePropertiesProvider.provideForControl(testedSlider, tb); Thus you
  65  * can get control over all properties of slider.
  66  *
  67  * Also you can use functionality of counter. Counters can count increments:
  68  * tb.addCounter(SET_ON_HIDING_COUNTER); testedComboBox.setOnHiding(new
  69  * EventHandler<Event>() { public void handle(Event t) {
  70  * tb.incrementCounter(SET_ON_HIDING_COUNTER); } }); Thus, you can count, how
  71  * many times onHiding event happend.
  72  *
  73  * Look at class javafx.scene.control.test.util.UtilTestFunctions to see, which
  74  * functionality of this PropertiesTable can be accessed from tests side (it
  75  * contains different checkers, value setters, etc).
  76  */
  77 public class PropertiesTable extends VBox implements AbstractPropertiesTable, Refreshable {
  78 
  79     public final static String PROPERTIES_TABLE_SUFFIX_ID = "_PROPERTY_TABLE_ID";
  80     private final VBox linesVBox = new VBox(5);
  81     private final FlowPane countersFlowPane = FlowPaneBuilder.create().vgap(5).hgap(5).build();
  82     private final FlowPane listenersFlowPane = FlowPaneBuilder.create().vgap(5).hgap(5).build();
  83     private final Object testedControl;
  84     private String domainName;
  85     /**
  86      * Matches property name, on its controller.
  87      */
  88     private HashMap<String, AbstractPropertyController> propertyControllers = new HashMap<String, AbstractPropertyController>();
  89     /**
  90      * Matches counter name on its counter representation.
  91      */
  92     private HashMap<String, AbstractEventsCounter> eventCounters = new HashMap<String, AbstractEventsCounter>();
  93     /**
  94      * Matches property name on its listener (for read-only properties).
  95      */
  96     private HashMap<String, AbstractPropertyValueListener> readonlyPropertyListeners = new HashMap<String, AbstractPropertyValueListener>();
  97 
  98     public PropertiesTable(Object testedControl) {
  99         super(5);
 100         this.domainName = DEFAULT_DOMAIN_NAME;
 101         this.setId(DEFAULT_DOMAIN_NAME + PROPERTIES_TABLE_SUFFIX_ID);
 102         getChildren().add(0, countersFlowPane);
 103         getChildren().add(1, listenersFlowPane);
 104         getChildren().add(2, linesVBox);
 105         this.testedControl = testedControl;
 106     }
 107 
 108     public void refresh() {
 109         for (AbstractPropertyController controller : propertyControllers.values()) {
 110             controller.refresh();
 111         }
 112         for (AbstractEventsCounter counter : eventCounters.values()) {
 113             counter.refresh();
 114         }
 115         for (AbstractPropertyValueListener listener : readonlyPropertyListeners.values()) {
 116             listener.refresh();
 117         }
 118     }
 119 
 120     @Override
 121     public void addBooleanPropertyLine(Property bindableProperty) {
 122         AbstractPropertyController controller = new PropertyValueController(bindableProperty, testedControl);
 123         propertyControllers.put(bindableProperty.getName().toUpperCase(), controller);
 124         linesVBox.getChildren().add(controller.getVisualRepresentation());
 125     }
 126 
 127     @Override
 128     public void addBooleanPropertyLine(Property bindableProperty, Object owningObject) {
 129         AbstractPropertyController controller = new PropertyValueController(bindableProperty, owningObject);
 130         propertyControllers.put(bindableProperty.getName().toUpperCase(), controller);
 131         linesVBox.getChildren().add(controller.getVisualRepresentation());
 132     }
 133 
 134     @Override
 135     public void addStringLine(Property bindableProperty, String initialText) {
 136         addStringLine(bindableProperty, initialText, testedControl);
 137     }
 138 
 139     @Override
 140     public void addStringLine(Property bindableProperty, String initialText, Object owningObject) {
 141         AbstractPropertyController controller = new PropertyValueController(bindableProperty, owningObject, initialText);
 142         propertyControllers.put(bindableProperty.getName().toUpperCase(), controller);
 143         linesVBox.getChildren().add(controller.getVisualRepresentation());
 144     }
 145 
 146     @Override
 147     public void addDoublePropertyLine(final DoubleProperty bindableProperty, double min, double max, double initial) {
 148         addDoublePropertyLine(bindableProperty, min, max, initial, testedControl);
 149     }
 150 
 151     @Override
 152     public void addDoublePropertyLine(final DoubleProperty bindableProperty, double min, double max, double initial, Object owningObject) {
 153         AbstractPropertyController controller = new PropertyValueController(bindableProperty, testedControl, min, initial, max);
 154         propertyControllers.put(bindableProperty.getName().toUpperCase(), controller);
 155         linesVBox.getChildren().add(controller.getVisualRepresentation());
 156     }
 157 
 158     @Override
 159     public void addIntegerPropertyLine(final IntegerProperty bindableProperty, int min, int max, int initial) {
 160         AbstractPropertyController controller = new PropertyValueController(bindableProperty, testedControl, min, initial, max);
 161         propertyControllers.put(bindableProperty.getName().toUpperCase(), controller);
 162         linesVBox.getChildren().add(controller.getVisualRepresentation());
 163     }
 164 
 165     @Override
 166     public <T> void addObjectEnumPropertyLine(ObjectProperty<T> bindableProperty, List<T> valuesList) {
 167         addObjectEnumPropertyLine(bindableProperty, valuesList, testedControl);
 168     }
 169 
 170     @Override
 171     public <T> void addObjectEnumPropertyLine(ObjectProperty<T> bindableProperty, List<T> valuesList, Object owningObject) {
 172         AbstractPropertyController controller = new PropertyValueController<T>(bindableProperty, owningObject, valuesList);
 173         propertyControllers.put(bindableProperty.getName().toUpperCase(), controller);
 174         linesVBox.getChildren().add(controller.getVisualRepresentation());
 175     }
 176 
 177     @Override
 178     public void addSimpleListener(ReadOnlyProperty<? extends Object> bindableProperty, Object owningObject) {
 179         AbstractPropertyValueListener listener = new PropertyValueListener(bindableProperty, owningObject);
 180         readonlyPropertyListeners.put(bindableProperty.getName().toUpperCase(), listener);
 181         listenersFlowPane.getChildren().add(listener.getVisualRepresentation());
 182     }
 183 
 184     @Override
 185     public void addCounter(String counterName) {
 186         AbstractEventsCounter counter = new TextFieldEventsCounter(counterName);
 187         eventCounters.put(counterName.toUpperCase(), counter);
 188         countersFlowPane.getChildren().add(counter.getVisualRepresentation());
 189     }
 190 
 191     @Override
 192     public void incrementCounter(String counterName) {
 193         eventCounters.get(counterName.toUpperCase()).increment();
 194     }
 195 
 196     public Collection<AbstractEventsCounter> getCounters() {
 197         return eventCounters.values();
 198     }
 199 
 200     public List<AbstractPropertyValueListener> getListeners() {
 201         List<AbstractPropertyValueListener> temp = new ArrayList<AbstractPropertyValueListener>(Arrays.asList(readonlyPropertyListeners.values().toArray(new AbstractPropertyValueListener[0])));
 202         for (AbstractPropertyController controller : propertyControllers.values()) {
 203             temp.add(controller.getListener());
 204         }
 205         return temp;
 206     }
 207 
 208     public Node getVisualRepresentation() {
 209         return this;
 210     }
 211 
 212     public String getDomainName() {
 213         return this.domainName;
 214     }
 215 
 216     public void setDomainName(String domainName) {
 217         this.domainName = domainName;
 218     }
 219 }