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.lang.reflect.Method; 28 import javafx.beans.property.ReadOnlyProperty; 29 import javafx.beans.value.ChangeListener; 30 import javafx.beans.value.ObservableValue; 31 import javafx.scene.control.Label; 32 import javafx.scene.control.TextField; 33 import javafx.scene.control.Tooltip; 34 import static javafx.scene.control.test.utils.ptables.StaticLogger.*; 35 import javafx.scene.layout.HBox; 36 37 /** 38 * @author Alexander Kirov 39 * 40 * How to use it: Use contructor to give this class owningObject (this is 41 * something, usually control, which has getter, and method, which returns 42 * property in API. And instance of property, which will be listened. Also, for 43 * testing purposes, you will need to give an ID, and Small text, which will be 44 * in the label, descripting, what this listener is doing. 45 * 46 * Listener will listen to changes of property values and put new values to the 47 * TextField. 48 * 49 * You can take formed HBox, where all needed controls will be added. 50 * 51 * NOTION: this class should be instantiated on JavaFX thread. 52 */ 53 public class PropertyValueListener<ValueType> extends HBox implements AbstractPropertyValueListener<ValueType> { 54 55 public final static String LISTENER_SUFFIX = "_LISTENER_ID"; 56 private ReadOnlyProperty listenedProperty; 57 private Object owningObject; 58 private TextField receivedValueTF = new TextField(); 59 private boolean someStateWasRemembered = false; 60 private ValueType rememberedState = null; 61 private int rememberedChangeCountValue = -1; 62 private AbstractPropertyValueChangeCounter counter; 63 64 public <ValueType> PropertyValueListener(ReadOnlyProperty bindableProperty, Object owningObject) { 65 this(bindableProperty, owningObject, true); 66 } 67 68 public <ValueType> PropertyValueListener(ReadOnlyProperty bindableProperty, Object owningObject, Boolean showCounters) { 69 this(bindableProperty.getName().toLowerCase() + " : ", bindableProperty, bindableProperty.getName().toUpperCase() + LISTENER_SUFFIX, owningObject, showCounters); 70 } 71 72 public <ValueType> PropertyValueListener(String labelDescription, ReadOnlyProperty listenedProperty, String textFieldId, Object owningObject) { 73 this(labelDescription, listenedProperty, textFieldId, owningObject, true); 74 } 75 76 public <ValueType> PropertyValueListener(String labelDescription, ReadOnlyProperty listenedProperty, String textFieldId, Object owningObject, Boolean showCounters) { 77 this.owningObject = owningObject; 78 receivedValueTF.setMinWidth(50); 79 receivedValueTF.setMaxWidth(110); 80 receivedValueTF.setId(textFieldId); 81 receivedValueTF.setTooltip(new Tooltip()); 82 if (listenedProperty.getName().contains("BOUNDS")) { 83 //Make text field width, because bounds - big. 84 receivedValueTF.setMinWidth(500); 85 } 86 this.listenedProperty = listenedProperty; 87 counter = new PropertyValueCounter(listenedProperty); 88 Label temp = new Label(labelDescription); 89 temp.setPrefWidth(100); 90 getChildren().add(temp); 91 if (showCounters) { 92 getChildren().add(counter.getVisualRepresentation()); 93 } 94 getChildren().add(receivedValueTF); 95 96 listenedProperty.addListener(new ChangeListener() { 97 public void changed(ObservableValue ov, Object t, Object t1) { 98 processNewValue(t1); 99 } 100 }); 101 processNewValue(listenedProperty.getValue()); 102 } 103 104 public final void setListener() { 105 } 106 107 private void processNewValue(Object t1) { 108 try { 109 if (t1 != null) { 110 receivedValueTF.getTooltip().setText(t1.toString() + "\n" + receivedValueTF.getTooltip().getText()); 111 112 String propertyName; 113 114 propertyName = listenedProperty.getName(); 115 116 String prefix = "get"; 117 if (t1 instanceof Boolean) { 118 prefix = "is"; 119 } 120 121 if (!propertyName.equals("impl_treeItemCount")) { 122 try { 123 if (owningObject != null) { 124 Method getter = owningObject.getClass().getMethod(prefix + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1, propertyName.length())); 125 receivedValueTF.setText(getter.invoke(owningObject).toString()); 126 } else { 127 receivedValueTF.setText(t1.toString()); 128 } 129 130 } catch (Exception ex) { 131 try { 132 if (prefix.equals("is")) { 133 //Let try with "get", because, java beans property naming convention allows to name getter of boolean property like "get..." 134 /* 135 * QnD 136 */ 137 Method getter; 138 if ("reorderable".equals(propertyName)) { 139 getter = owningObject.getClass().getMethod("impl_isReorderable"); 140 } else if ("fixed".equals(propertyName)) { 141 getter = owningObject.getClass().getMethod("impl_isFixed"); 142 } else { 143 getter = owningObject.getClass().getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1, propertyName.length())); 144 } 145 receivedValueTF.setText(getter.invoke(owningObject).toString()); 146 } 147 } catch (Exception ex1) { 148 log(ex); 149 log(ex1); 150 } 151 } 152 } 153 } else { 154 receivedValueTF.setText("null"); 155 } 156 } catch (Throwable t) { 157 log(t); 158 } 159 } 160 161 public javafx.scene.Node getVisualRepresentation() { 162 return this; 163 } 164 165 public void refresh() { 166 counter.refresh(); 167 someStateWasRemembered = false; 168 rememberedState = null; 169 rememberedChangeCountValue = -1; 170 } 171 172 public void rememberCurrentState() { 173 rememberedState = (ValueType) listenedProperty.getValue(); 174 rememberedChangeCountValue = getChangeListenerCounter(); 175 someStateWasRemembered = true; 176 } 177 178 public void checkCurrentStateEquality() throws StateChangedException { 179 if (!someStateWasRemembered) { 180 throw new StateChangedException("No state was remembered."); 181 } 182 if (getChangeListenerCounter() != rememberedChangeCountValue) { 183 throw new StateChangedException("Change listener was called, so value did change between fixing and checking. Now : <" + listenedProperty.getValue() + ">, but was <" + rememberedState + ">. Change listener was called <" + String.valueOf(getChangeListenerCounter() - rememberedChangeCountValue) + "> times."); 184 } 185 //If change listener didn't work: 186 if (listenedProperty.getValue() == null) { 187 if (rememberedState != null) { 188 throw new StateChangedException("Previous value : <" + rememberedState + ">; current state : <" + listenedProperty.getValue() + ">."); 189 } 190 } else { 191 if (!((ValueType) listenedProperty.getValue()).equals(rememberedState)) { 192 throw new StateChangedException("Previous value : " + rememberedState + "; current state : " + listenedProperty.getValue() + "."); 193 } 194 } 195 } 196 197 public String getPropertyName() { 198 return listenedProperty.getName(); 199 } 200 201 @Override 202 public String toString() { 203 return "Listener [Property : " + listenedProperty.getName() + "; Value : " + listenedProperty.getValue() + "; Remembered : " + rememberedState + "]."; 204 } 205 206 public int getChangeListenerCounter() { 207 return counter.getChangeCount(); 208 } 209 210 public int getInvalidationListenerCounter() { 211 return counter.getInvalidationCount(); 212 } 213 }