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 javafx.beans.InvalidationListener;
029import javafx.beans.Observable;
030import javafx.beans.binding.BooleanBinding;
031import javafx.beans.value.ChangeListener;
032import javafx.beans.value.ObservableBooleanValue;
033import javafx.beans.value.ObservableValue;
034
035import com.sun.javafx.binding.ExpressionHelper;
036
037/**
038 * The class {@code BooleanPropertyBase} is the base class for a property
039 * wrapping a {@code boolean} value.
040 * 
041 * It provides all the functionality required for a property except for the
042 * {@link #getBean()} and {@link #getName()} methods, which must be implemented
043 * by extending classes.
044 * 
045 * @see BooleanProperty
046 */
047public abstract class BooleanPropertyBase extends BooleanProperty {
048
049    private boolean value;
050    private ObservableBooleanValue observable = null;
051    private InvalidationListener listener = null;
052    private boolean valid = true;
053    private ExpressionHelper<Boolean> helper = null;
054
055    /**
056     * The constructor of the {@code BooleanPropertyBase}.
057     */
058    public BooleanPropertyBase() {
059    }
060
061    /**
062     * The constructor of the {@code BooleanPropertyBase}.
063     * 
064     * @param initialValue
065     *            the initial value of the wrapped value
066     */
067    public BooleanPropertyBase(boolean initialValue) {
068        this.value = initialValue;
069    }
070
071    @Override 
072    public void addListener(InvalidationListener listener) {
073        helper = ExpressionHelper.addListener(helper, this, listener);
074    }
075
076    @Override 
077    public void removeListener(InvalidationListener listener) {
078        helper = ExpressionHelper.removeListener(helper, listener);
079    }
080    
081    @Override
082    public void addListener(ChangeListener<? super Boolean> listener) {
083        helper = ExpressionHelper.addListener(helper, this, listener);
084    }
085
086    @Override 
087    public void removeListener(ChangeListener<? super Boolean> listener) {
088        helper = ExpressionHelper.removeListener(helper, listener);
089    }
090    
091    /**
092     * Sends notifications to all attached
093     * {@link javafx.beans.InvalidationListener InvalidationListeners} and
094     * {@link javafx.beans.value.ChangeListener ChangeListeners}.
095     *
096     * This method is called when the value is changed, either manually by
097     * calling {@link #set(boolean)} or in case of a bound property, if the
098     * binding becomes invalid.
099     */
100    protected void fireValueChangedEvent() {
101        ExpressionHelper.fireValueChangedEvent(helper);
102    }
103    
104    private void markInvalid() {
105        if (valid) {
106            valid = false;
107            invalidated();
108            fireValueChangedEvent();
109        }
110    }
111
112    /**
113     * The method {@code invalidated()} can be overridden to receive
114     * invalidation notifications. This is the preferred option in
115     * {@code Objects} defining the property, because it requires less memory.
116     * 
117     * The default implementation is empty.
118     */
119    protected void invalidated() {
120    }
121
122    /**
123     * {@inheritDoc}
124     */
125    @Override
126    public boolean get() {
127        valid = true;
128        return observable == null ? value : observable.get();
129    }
130
131    /**
132     * {@inheritDoc}
133     */
134    @Override
135    public void set(boolean newValue) {
136        if (isBound()) {
137            throw new java.lang.RuntimeException("A bound value cannot be set.");
138        }
139        if (value != newValue) {
140            value = newValue;
141            markInvalid();
142        }
143    }
144
145    /**
146     * {@inheritDoc}
147     */
148    @Override
149    public boolean isBound() {
150        return observable != null;
151    }
152
153    /**
154     * {@inheritDoc}
155     */
156    @Override
157    public void bind(final ObservableValue<? extends Boolean> rawObservable) {
158        if (rawObservable == null) {
159            throw new NullPointerException("Cannot bind to null");
160        }
161
162        final ObservableBooleanValue newObservable = (rawObservable instanceof ObservableBooleanValue) ? (ObservableBooleanValue) rawObservable
163                : new BooleanBinding() {
164                    {
165                        super.bind(rawObservable);
166                    }
167
168                    @Override
169                    protected boolean computeValue() {
170                        final Boolean value = rawObservable.getValue();
171                        return (value == null)? false : value;
172                    }
173                };
174
175        if (!newObservable.equals(observable)) {
176            unbind();
177            observable = newObservable;
178            if (listener == null) {
179                listener = new Listener();
180            }
181            observable.addListener(listener);
182            markInvalid();
183        }
184    }
185
186    /**
187     * {@inheritDoc}
188     */
189    @Override
190    public void unbind() {
191        if (observable != null) {
192            value = observable.get();
193            observable.removeListener(listener);
194            observable = null;
195        }
196    }
197
198    /**
199     * Returns a string representation of this {@code BooleanPropertyBase} object.
200     * @return a string representation of this {@code BooleanPropertyBase} object.
201     */ 
202    @Override
203    public String toString() {
204        final Object bean = getBean();
205        final String name = getName();
206        final StringBuilder result = new StringBuilder("BooleanProperty [");
207        if (bean != null) {
208            result.append("bean: ").append(bean).append(", ");
209        }
210        if ((name != null) && (!name.equals(""))) {
211            result.append("name: ").append(name).append(", ");
212        }
213        if (isBound()) {
214            result.append("bound, ");
215            if (valid) {
216                result.append("value: ").append(get());
217            } else {
218                result.append("invalid");
219            }
220        } else {
221            result.append("value: ").append(get());
222        }
223        result.append("]");
224        return result.toString();
225    }
226
227    private class Listener implements InvalidationListener {
228        @Override
229        public void invalidated(Observable valueModel) {
230            markInvalid();
231        }
232    }
233
234}