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.SetExpressionHelper; 029import javafx.beans.InvalidationListener; 030import javafx.beans.Observable; 031import javafx.beans.value.ChangeListener; 032import javafx.beans.value.ObservableValue; 033import javafx.collections.ObservableSet; 034import javafx.collections.SetChangeListener; 035 036/** 037 * The class {@code SetPropertyBase} is the base class for a property 038 * wrapping an {@link javafx.collections.ObservableSet}. 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.ObservableSet 045 * @see SetProperty 046 * 047 * @param <E> the type of the {@code Set} elements 048 */ 049public abstract class SetPropertyBase<E> extends SetProperty<E> { 050 051 private final SetChangeListener<E> setChangeListener = new SetChangeListener<E>() { 052 @Override 053 public void onChanged(Change<? extends E> change) { 054 invalidateProperties(); 055 invalidated(); 056 fireValueChangedEvent(change); 057 } 058 }; 059 060 private ObservableSet<E> value; 061 private ObservableValue<? extends ObservableSet<E>> observable = null; 062 private InvalidationListener listener = null; 063 private boolean valid = true; 064 private SetExpressionHelper<E> helper = null; 065 066 private SizeProperty size0; 067 private EmptyProperty empty0; 068 069 /** 070 * The Constructor of {@code SetPropertyBase} 071 */ 072 public SetPropertyBase() {} 073 074 /** 075 * The constructor of the {@code SetPropertyBase}. 076 * 077 * @param initialValue 078 * the initial value of the wrapped value 079 */ 080 public SetPropertyBase(ObservableSet<E> initialValue) { 081 this.value = initialValue; 082 if (initialValue != null) { 083 initialValue.addListener(setChangeListener); 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 SetPropertyBase.this; 104 } 105 106 @Override 107 public String getName() { 108 return "size"; 109 } 110 111 @Override 112 protected void fireValueChangedEvent() { 113 super.fireValueChangedEvent(); 114 } 115 } 116 117 @Override 118 public ReadOnlyBooleanProperty emptyProperty() { 119 if (empty0 == null) { 120 empty0 = new EmptyProperty(); 121 } 122 return empty0; 123 } 124 125 private class EmptyProperty extends ReadOnlyBooleanPropertyBase { 126 127 @Override 128 public boolean get() { 129 return isEmpty(); 130 } 131 132 @Override 133 public Object getBean() { 134 return SetPropertyBase.this; 135 } 136 137 @Override 138 public String getName() { 139 return "empty"; 140 } 141 142 @Override 143 protected void fireValueChangedEvent() { 144 super.fireValueChangedEvent(); 145 } 146 } 147 148 @Override 149 public void addListener(InvalidationListener listener) { 150 helper = SetExpressionHelper.addListener(helper, this, listener); 151 } 152 153 @Override 154 public void removeListener(InvalidationListener listener) { 155 helper = SetExpressionHelper.removeListener(helper, listener); 156 } 157 158 @Override 159 public void addListener(ChangeListener<? super ObservableSet<E>> listener) { 160 helper = SetExpressionHelper.addListener(helper, this, listener); 161 } 162 163 @Override 164 public void removeListener(ChangeListener<? super ObservableSet<E>> listener) { 165 helper = SetExpressionHelper.removeListener(helper, listener); 166 } 167 168 @Override 169 public void addListener(SetChangeListener<? super E> listener) { 170 helper = SetExpressionHelper.addListener(helper, this, listener); 171 } 172 173 @Override 174 public void removeListener(SetChangeListener<? super E> listener) { 175 helper = SetExpressionHelper.removeListener(helper, listener); 176 } 177 178 /** 179 * Sends notifications to all attached 180 * {@link javafx.beans.InvalidationListener InvalidationListeners}, 181 * {@link javafx.beans.value.ChangeListener ChangeListeners}, and 182 * {@link javafx.collections.SetChangeListener}. 183 * 184 * This method is called when the value is changed, either manually by 185 * calling {@link #set(javafx.collections.ObservableSet)} or in case of a bound property, if the 186 * binding becomes invalid. 187 */ 188 protected void fireValueChangedEvent() { 189 SetExpressionHelper.fireValueChangedEvent(helper); 190 } 191 192 /** 193 * Sends notifications to all attached 194 * {@link javafx.beans.InvalidationListener InvalidationListeners}, 195 * {@link javafx.beans.value.ChangeListener ChangeListeners}, and 196 * {@link javafx.collections.SetChangeListener}. 197 * 198 * This method is called when the content of the list changes. 199 * 200 * @param change the change that needs to be propagated 201 */ 202 protected void fireValueChangedEvent(SetChangeListener.Change<? extends E> change) { 203 SetExpressionHelper.fireValueChangedEvent(helper, change); 204 } 205 206 private void invalidateProperties() { 207 if (size0 != null) { 208 size0.fireValueChangedEvent(); 209 } 210 if (empty0 != null) { 211 empty0.fireValueChangedEvent(); 212 } 213 } 214 215 private void markInvalid(ObservableSet<E> oldValue) { 216 if (valid) { 217 if (oldValue != null) { 218 oldValue.removeListener(setChangeListener); 219 } 220 valid = false; 221 invalidateProperties(); 222 invalidated(); 223 fireValueChangedEvent(); 224 } 225 } 226 227 228 229 /** 230 * The method {@code invalidated()} can be overridden to receive 231 * invalidation notifications. This is the preferred option in 232 * {@code Objects} defining the property, because it requires less memory. 233 * 234 * The default implementation is empty. 235 */ 236 protected void invalidated() { 237 } 238 239 @Override 240 public ObservableSet<E> get() { 241 if (!valid) { 242 value = observable == null ? value : observable.getValue(); 243 valid = true; 244 if (value != null) { 245 value.addListener(setChangeListener); 246 } 247 } 248 return value; 249 } 250 251 @Override 252 public void set(ObservableSet<E> newValue) { 253 if (isBound()) { 254 throw new RuntimeException("A bound value cannot be set."); 255 } 256 if (value != newValue) { 257 final ObservableSet<E> oldValue = value; 258 value = newValue; 259 markInvalid(oldValue); 260 } 261 } 262 263 @Override 264 public boolean isBound() { 265 return observable != null; 266 } 267 268 @Override 269 public void bind(final ObservableValue<? extends ObservableSet<E>> newObservable) { 270 if (newObservable == null) { 271 throw new NullPointerException("Cannot bind to null"); 272 } 273 274 if (!newObservable.equals(this.observable)) { 275 unbind(); 276 observable = newObservable; 277 if (listener == null) { 278 listener = new Listener(); 279 } 280 observable.addListener(listener); 281 markInvalid(value); 282 } 283 } 284 285 @Override 286 public void unbind() { 287 if (observable != null) { 288 value = observable.getValue(); 289 observable.removeListener(listener); 290 observable = null; 291 } 292 } 293 294 /** 295 * Returns a string representation of this {@code SetPropertyBase} object. 296 * @return a string representation of this {@code SetPropertyBase} object. 297 */ 298 @Override 299 public String toString() { 300 final Object bean = getBean(); 301 final String name = getName(); 302 final StringBuilder result = new StringBuilder("SetProperty ["); 303 if (bean != null) { 304 result.append("bean: ").append(bean).append(", "); 305 } 306 if ((name != null) && (!name.equals(""))) { 307 result.append("name: ").append(name).append(", "); 308 } 309 if (isBound()) { 310 result.append("bound, "); 311 if (valid) { 312 result.append("value: ").append(get()); 313 } else { 314 result.append("invalid"); 315 } 316 } else { 317 result.append("value: ").append(get()); 318 } 319 result.append("]"); 320 return result.toString(); 321 } 322 323 private class Listener implements InvalidationListener { 324 @Override 325 public void invalidated(Observable valueModel) { 326 markInvalid(value); 327 } 328 } 329 330}