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