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