Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 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.binding;
027
028import javafx.beans.InvalidationListener;
029import javafx.beans.Observable;
030import javafx.beans.value.ChangeListener;
031import javafx.collections.FXCollections;
032import javafx.collections.ObservableList;
033import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
034
035import com.sun.javafx.binding.BindingHelperObserver;
036import com.sun.javafx.binding.ExpressionHelper;
037
038/**
039 * Base class that provides most of the functionality needed to implement a
040 * {@link Binding} of a {@code boolean} value.
041 * <p>
042 * {@code BooleanBinding} provides a simple invalidation-scheme. An extending
043 * class can register dependencies by calling {@link #bind(Observable...)}.
044 * If One of the registered dependencies becomes invalid, this
045 * {@code BooleanBinding} is marked as invalid. With
046 * {@link #unbind(Observable...)} listening to dependencies can be stopped.
047 * <p>
048 * To provide a concrete implementation of this class, the method
049 * {@link #computeValue()} has to be implemented to calculate the value of this
050 * binding based on the current state of the dependencies. It is called when
051 * {@link #get()} is called for an invalid binding.
052 * <p>
053 * See {@link DoubleBinding} for an example how this base class can be extended.
054 * 
055 * @see Binding
056 * @see javafx.beans.binding.BooleanExpression
057 * 
058 */
059public abstract class BooleanBinding extends BooleanExpression implements
060        Binding<Boolean> {
061
062    private boolean value;
063    private boolean valid = false;
064    private BindingHelperObserver observer;
065    private ExpressionHelper<Boolean> helper = null;
066
067    @Override 
068    public void addListener(InvalidationListener listener) {
069        helper = ExpressionHelper.addListener(helper, this, listener);
070    }
071
072    @Override 
073    public void removeListener(InvalidationListener listener) {
074        helper = ExpressionHelper.removeListener(helper, listener);
075    }
076    
077    @Override
078    public void addListener(ChangeListener<? super Boolean> listener) {
079        helper = ExpressionHelper.addListener(helper, this, listener);
080    }
081
082    @Override 
083    public void removeListener(ChangeListener<? super Boolean> listener) {
084        helper = ExpressionHelper.removeListener(helper, listener);
085    }
086    
087    /**
088     * Start observing the dependencies for changes. If the value of one of the
089     * dependencies changes, the binding is marked as invalid.
090     * 
091     * @param dependencies
092     *            the dependencies to observe
093     */
094    protected final void bind(Observable... dependencies) {
095        if ((dependencies != null) && (dependencies.length > 0)) {
096            if (observer == null) {
097                observer = new BindingHelperObserver(this);
098            }
099            for (final Observable dep : dependencies) {
100                dep.addListener(observer);
101            }
102        }
103    }
104
105    /**
106     * Stop observing the dependencies for changes.
107     * 
108     * @param dependencies
109     *            the dependencies to stop observing
110     */
111    protected final void unbind(Observable... dependencies) {
112        if (observer != null) {
113            for (final Observable dep : dependencies) {
114                dep.removeListener(observer);
115            }
116            observer = null;
117        }
118    }
119
120    /**
121     * A default implementation of {@code dispose()} that is empty.
122     */
123    @Override
124    public void dispose() {
125    }
126
127    /**
128     * A default implementation of {@code getDependencies()} that returns an
129     * empty {@link javafx.collections.ObservableList}.
130     * 
131     * @return an empty {@code ObservableList}
132     */
133    @Override
134    @ReturnsUnmodifiableCollection
135    public ObservableList<?> getDependencies() {
136        return FXCollections.emptyObservableList();
137    }
138
139    /**
140     * Returns the result of {@link #computeValue()}. The method
141     * {@code computeValue()} is only called if the binding is invalid. The
142     * result is cached and returned if the binding did not become invalid since
143     * the last call of {@code get()}.
144     * 
145     * @return the current value
146     */
147    @Override
148    public final boolean get() {
149        if (!valid) {
150            value = computeValue();
151            valid = true;
152        }
153        return value;
154    }
155
156    /**
157     * The method onInvalidating() can be overridden by extending classes to
158     * react, if this binding becomes invalid. The default implementation is
159     * empty.
160     */
161    protected void onInvalidating() {
162    }
163
164    @Override
165    public final void invalidate() {
166        if (valid) {
167            valid = false;
168            onInvalidating();
169            ExpressionHelper.fireValueChangedEvent(helper);
170        }
171    }
172
173    @Override
174    public final boolean isValid() {
175        return valid;
176    }
177
178    /**
179     * Calculates the current value of this binding.
180     * <p>
181     * Classes extending {@code BooleanBinding} have to provide an
182     * implementation of {@code computeValue}.
183     * 
184     * @return the current value
185     */
186    protected abstract boolean computeValue();
187
188    /**
189     * Returns a string representation of this {@code BooleanBinding} object.
190     * @return a string representation of this {@code BooleanBinding} object.
191     */ 
192    @Override
193    public String toString() {
194        return valid ? "BooleanBinding [value: " + get() + "]"
195                : "BooleanBinding [invalid]";
196    }
197
198}