Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.beans.property; 027 028import com.sun.javafx.binding.ListExpressionHelper; 029import javafx.beans.InvalidationListener; 030import javafx.beans.Observable; 031import javafx.beans.value.ChangeListener; 032import javafx.beans.value.ObservableValue; 033import javafx.collections.ListChangeListener; 034import javafx.collections.ObservableList; 035 036/** 037 * The class {@code ListPropertyBase} is the base class for a property 038 * wrapping an {@link javafx.collections.ObservableList}. 039 * 040 * It provides all the functionality required for a property except for the 041 * {@link #getBean()} and {@link #getName()} methods, which must be implemented 042 * by extending classes. 043 * 044 * @see javafx.collections.ObservableList 045 * @see ListProperty 046 * 047 * @param <E> the type of the {@code List} elements 048 */ 049public abstract class ListPropertyBase<E> extends ListProperty<E> { 050 051 private final ListChangeListener<E> listChangeListener = new ListChangeListener<E>() { 052 @Override 053 public void onChanged(Change<? extends E> change) { 054 invalidateProperties(); 055 invalidated(); 056 fireValueChangedEvent(change); 057 } 058 }; 059 060 private ObservableList<E> value; 061 private ObservableValue<? extends ObservableList<E>> observable = null; 062 private InvalidationListener listener = null; 063 private boolean valid = true; 064 private ListExpressionHelper<E> helper = null; 065 066 private SizeProperty size0; 067 private EmptyProperty empty0; 068 069 /** 070 * The Constructor of {@code ListPropertyBase} 071 */ 072 public ListPropertyBase() {} 073 074 /** 075 * The constructor of the {@code ListPropertyBase}. 076 * 077 * @param initialValue 078 * the initial value of the wrapped value 079 */ 080 public ListPropertyBase(ObservableList<E> initialValue) { 081 this.value = initialValue; 082 if (initialValue != null) { 083 initialValue.addListener(listChangeListener); 084 } 085 } 086 087 @Override 088 public ReadOnlyIntegerProperty sizeProperty() { 089 if (size0 == null) { 090 size0 = new SizeProperty(); 091 } 092 return size0; 093 } 094 095 private class SizeProperty extends ReadOnlyIntegerPropertyBase { 096 @Override 097 public int get() { 098 return size(); 099 } 100 101 @Override 102 public Object getBean() { 103 return ListPropertyBase.this; 104 } 105 106 @Override 107 public String getName() { 108 return "size"; 109 } 110 111 protected void fireValueChangedEvent() { 112 super.fireValueChangedEvent(); 113 } 114 } 115 116 @Override 117 public ReadOnlyBooleanProperty emptyProperty() { 118 if (empty0 == null) { 119 empty0 = new EmptyProperty(); 120 } 121 return empty0; 122 } 123 124 private class EmptyProperty extends ReadOnlyBooleanPropertyBase { 125 126 @Override 127 public boolean get() { 128 return isEmpty(); 129 } 130 131 @Override 132 public Object getBean() { 133 return ListPropertyBase.this; 134 } 135 136 @Override 137 public String getName() { 138 return "empty"; 139 } 140 141 protected void fireValueChangedEvent() { 142 super.fireValueChangedEvent(); 143 } 144 } 145 146 @Override 147 public void addListener(InvalidationListener listener) { 148 helper = ListExpressionHelper.addListener(helper, this, listener); 149 } 150 151 @Override 152 public void removeListener(InvalidationListener listener) { 153 helper = ListExpressionHelper.removeListener(helper, listener); 154 } 155 156 @Override 157 public void addListener(ChangeListener<? super ObservableList<E>> listener) { 158 helper = ListExpressionHelper.addListener(helper, this, listener); 159 } 160 161 @Override 162 public void removeListener(ChangeListener<? super ObservableList<E>> listener) { 163 helper = ListExpressionHelper.removeListener(helper, listener); 164 } 165 166 @Override 167 public void addListener(ListChangeListener<? super E> listener) { 168 helper = ListExpressionHelper.addListener(helper, this, listener); 169 } 170 171 @Override 172 public void removeListener(ListChangeListener<? super E> listener) { 173 helper = ListExpressionHelper.removeListener(helper, listener); 174 } 175 176 /** 177 * Sends notifications to all attached 178 * {@link javafx.beans.InvalidationListener InvalidationListeners}, 179 * {@link javafx.beans.value.ChangeListener ChangeListeners}, and 180 * {@link javafx.collections.ListChangeListener}. 181 * 182 * This method is called when the value is changed, either manually by 183 * calling {@link #set(ObservableList)} or in case of a bound property, if the 184 * binding becomes invalid. 185 */ 186 protected void fireValueChangedEvent() { 187 ListExpressionHelper.fireValueChangedEvent(helper); 188 } 189 190 /** 191 * Sends notifications to all attached 192 * {@link javafx.beans.InvalidationListener InvalidationListeners}, 193 * {@link javafx.beans.value.ChangeListener ChangeListeners}, and 194 * {@link javafx.collections.ListChangeListener}. 195 * 196 * This method is called when the content of the list changes. 197 * 198 * @param change the change that needs to be propagated 199 */ 200 protected void fireValueChangedEvent(ListChangeListener.Change<? extends E> change) { 201 ListExpressionHelper.fireValueChangedEvent(helper, change); 202 } 203 204 private void invalidateProperties() { 205 if (size0 != null) { 206 size0.fireValueChangedEvent(); 207 } 208 if (empty0 != null) { 209 empty0.fireValueChangedEvent(); 210 } 211 } 212 213 private void markInvalid(ObservableList<E> oldValue) { 214 if (valid) { 215 if (oldValue != null) { 216 oldValue.removeListener(listChangeListener); 217 } 218 valid = false; 219 invalidateProperties(); 220 invalidated(); 221 fireValueChangedEvent(); 222 } 223 } 224 225 226 227 /** 228 * The method {@code invalidated()} can be overridden to receive 229 * invalidation notifications. This is the preferred option in 230 * {@code Objects} defining the property, because it requires less memory. 231 * 232 * The default implementation is empty. 233 */ 234 protected void invalidated() { 235 } 236 237 @Override 238 public ObservableList<E> get() { 239 if (!valid) { 240 value = observable == null ? value : observable.getValue(); 241 valid = true; 242 if (value != null) { 243 value.addListener(listChangeListener); 244 } 245 } 246 return value; 247 } 248 249 @Override 250 public void set(ObservableList<E> newValue) { 251 if (isBound()) { 252 throw new java.lang.RuntimeException("A bound value cannot be set."); 253 } 254 if (value != newValue) { 255 final ObservableList<E> oldValue = value; 256 value = newValue; 257 markInvalid(oldValue); 258 } 259 } 260 261 @Override 262 public boolean isBound() { 263 return observable != null; 264 } 265 266 @Override 267 public void bind(final ObservableValue<? extends ObservableList<E>> newObservable) { 268 if (newObservable == null) { 269 throw new NullPointerException("Cannot bind to null"); 270 } 271 272 if (!newObservable.equals(observable)) { 273 unbind(); 274 observable = newObservable; 275 if (listener == null) { 276 listener = new Listener(); 277 } 278 observable.addListener(listener); 279 markInvalid(value); 280 } 281 } 282 283 @Override 284 public void unbind() { 285 if (observable != null) { 286 value = observable.getValue(); 287 observable.removeListener(listener); 288 observable = null; 289 } 290 } 291 292 /** 293 * Returns a string representation of this {@code ListPropertyBase} object. 294 * @return a string representation of this {@code ListPropertyBase} object. 295 */ 296 @Override 297 public String toString() { 298 final Object bean = getBean(); 299 final String name = getName(); 300 final StringBuilder result = new StringBuilder("ListProperty ["); 301 if (bean != null) { 302 result.append("bean: ").append(bean).append(", "); 303 } 304 if ((name != null) && (!name.equals(""))) { 305 result.append("name: ").append(name).append(", "); 306 } 307 if (isBound()) { 308 result.append("bound, "); 309 if (valid) { 310 result.append("value: ").append(get()); 311 } else { 312 result.append("invalid"); 313 } 314 } else { 315 result.append("value: ").append(get()); 316 } 317 result.append("]"); 318 return result.toString(); 319 } 320 321 private class Listener implements InvalidationListener { 322 @Override 323 public void invalidated(Observable valueModel) { 324 markInvalid(value); 325 } 326 } 327 328}