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.value.ChangeListener;
031import javafx.beans.value.ObservableValue;
032
033import com.sun.javafx.binding.ExpressionHelper;
034
035/**
036 * The class {@code StringPropertyBase} is the base class for a property
037 * wrapping a {@code String} value.
038 * 
039 * It provides all the functionality required for a property except for the
040 * {@link #getBean()} and {@link #getName()} methods, which must be implemented
041 * by extending classes.
042 * 
043 * @see StringProperty
044 * 
045 * 
046 */
047public abstract class StringPropertyBase extends StringProperty {
048
049    private String value;
050    private ObservableValue<? extends String> observable = null;
051    private InvalidationListener listener = null;
052    private boolean valid = true;
053    private ExpressionHelper<String> helper = null;
054
055    /**
056     * The constructor of the {@code StringPropertyBase}.
057     */
058    public StringPropertyBase() {
059    }
060
061    /**
062     * The constructor of the {@code StringPropertyBase}.
063     * 
064     * @param initialValue
065     *            the initial value of the wrapped {@code String}
066     */
067    public StringPropertyBase(String 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 String> listener) {
083        helper = ExpressionHelper.addListener(helper, this, listener);
084    }
085
086    @Override 
087    public void removeListener(ChangeListener<? super String> 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} 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 String get() {
127        valid = true;
128        return observable == null ? value : observable.getValue();
129    }
130
131    /**
132     * {@inheritDoc}
133     */
134    @Override
135    public void set(String newValue) {
136        if (isBound()) {
137            throw new java.lang.RuntimeException("A bound value cannot be set.");
138        }
139        if ((value == null)? newValue != null : !value.equals(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(ObservableValue<? extends String> newObservable) {
158        if (newObservable == null) {
159            throw new NullPointerException("Cannot bind to null");
160        }
161        if (!newObservable.equals(observable)) {
162            unbind();
163            observable = newObservable;
164            if (listener == null) {
165                listener = new Listener();
166            }
167            observable.addListener(listener);
168            markInvalid();
169        }
170    }
171
172    /**
173     * {@inheritDoc}
174     */
175    @Override
176    public void unbind() {
177        if (observable != null) {
178            value = observable.getValue();
179            observable.removeListener(listener);
180            observable = null;
181        }
182    }
183
184    /**
185     * Returns a string representation of this {@code StringPropertyBase} object.
186     * @return a string representation of this {@code StringPropertyBase} object.
187     */ 
188    @Override
189    public String toString() {
190        final Object bean = getBean();
191        final String name = getName();
192        final StringBuilder result = new StringBuilder("StringProperty [");
193        if (bean != null) {
194            result.append("bean: ").append(bean).append(", ");
195        }
196        if ((name != null) && (!name.equals(""))) {
197            result.append("name: ").append(name).append(", ");
198        }
199        if (isBound()) {
200            result.append("bound, ");
201            if (valid) {
202                result.append("value: ").append(get());
203            } else {
204                result.append("invalid");
205            }
206        } else {
207            result.append("value: ").append(get());
208        }
209        result.append("]");
210        return result.toString();
211    }
212
213    private class Listener implements InvalidationListener {
214        @Override
215        public void invalidated(Observable valueModel) {
216            markInvalid();
217        }
218    }
219}