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.binding;
027
028import com.sun.javafx.binding.StringFormatter;
029import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
030import javafx.beans.property.ReadOnlyBooleanProperty;
031import javafx.beans.property.ReadOnlyIntegerProperty;
032import javafx.beans.value.ObservableIntegerValue;
033import javafx.beans.value.ObservableListValue;
034import javafx.collections.FXCollections;
035import javafx.collections.ObservableList;
036
037import java.util.Collection;
038import java.util.Iterator;
039import java.util.List;
040import java.util.ListIterator;
041
042/**
043 * A {@code ListExpression} is a
044 * {@link javafx.beans.value.ObservableListValue} plus additional convenience
045 * methods to generate bindings in a fluent style.
046 * <p>
047 * A concrete sub-class of {@code ListExpression} has to implement the method
048 * {@link javafx.beans.value.ObservableListValue#get()}, which provides the
049 * actual value of this expression.
050 * <p>
051 * If the wrapped list of a {@code ListExpression} is {@code null}, all methods implementing the {@code List}
052 * interface will behave as if they were applied to an immutable empty list.
053 *
054 * @param <E> the type of the {@code List} elements.
055 */
056public abstract class ListExpression<E> implements ObservableListValue<E> {
057
058    private static final ObservableList EMPTY_LIST = FXCollections.emptyObservableList();
059
060    @Override
061    public ObservableList<E> getValue() {
062        return get();
063    }
064
065    /**
066     * Returns a {@code ListExpression} that wraps a
067     * {@link javafx.beans.value.ObservableListValue}. If the
068     * {@code ObservableListValue} is already a {@code ListExpression}, it
069     * will be returned. Otherwise a new
070     * {@link javafx.beans.binding.ListBinding} is created that is bound to
071     * the {@code ObservableListValue}.
072     *
073     * @param value
074     *            The source {@code ObservableListValue}
075     * @return A {@code ListExpression} that wraps the
076     *         {@code ObservableListValue} if necessary
077     * @throws NullPointerException
078     *             if {@code value} is {@code null}
079     */
080    public static <E> ListExpression<E> listExpression(final ObservableListValue<E> value) {
081        if (value == null) {
082            throw new NullPointerException("List must be specified.");
083        }
084        return value instanceof ListExpression ? (ListExpression<E>) value
085                : new ListBinding<E>() {
086            {
087                super.bind(value);
088            }
089
090            @Override
091            public void dispose() {
092                super.unbind(value);
093            }
094
095            @Override
096            protected ObservableList<E> computeValue() {
097                return value.get();
098            }
099
100            @Override
101            @ReturnsUnmodifiableCollection
102            public ObservableList<ObservableListValue<E>> getDependencies() {
103                return FXCollections.singletonObservableList(value);
104            }
105        };
106    }
107
108    /**
109     * The size of the list
110     */
111    public int getSize() {
112        return size();
113    }
114    public abstract ReadOnlyIntegerProperty sizeProperty();
115
116    /**
117     * A boolean property that is {@code true}, if the list is empty.
118     */
119    public abstract ReadOnlyBooleanProperty emptyProperty();
120
121    /**
122     * Creates a new {@link ObjectBinding} that contains the element at the specified position.
123     * If {@code index} points behind the list, the {@code ObjectBinding} contains {@code null}.
124     *
125     * @param index the index of the element
126     * @return the {@code ObjectBinding}
127     * @throws IllegalArgumentException if {@code index < 0}
128     */
129    public ObjectBinding<E> valueAt(int index) {
130        return Bindings.valueAt(this, index);
131    }
132
133    /**
134     * Creates a new {@link ObjectBinding} that contains the element at the specified position.
135     * If {@code index} points outside of the list, the {@code ObjectBinding} contains {@code null}.
136     *
137     * @param index the index of the element
138     * @return the {@code ObjectBinding}
139     * @throws NullPointerException if {@code index} is {@code null}
140     */
141    public ObjectBinding<E> valueAt(ObservableIntegerValue index) {
142        return Bindings.valueAt(this, index);
143    }
144
145    /**
146     * Creates a new {@link BooleanBinding} that holds {@code true} if this list is equal to
147     * another {@link javafx.collections.ObservableList}.
148     *
149     * @param other
150     *            the other {@code ObservableList}
151     * @return the new {@code BooleanBinding}
152     * @throws NullPointerException
153     *             if {@code other} is {@code null}
154     */
155    public BooleanBinding isEqualTo(final ObservableList<?> other) {
156        return Bindings.equal(this, other);
157    }
158
159    /**
160     * Creates a new {@link BooleanBinding} that holds {@code true} if this list is not equal to
161     * another {@link javafx.collections.ObservableList}.
162     *
163     * @param other
164     *            the other {@code ObservableList}
165     * @return the new {@code BooleanBinding}
166     * @throws NullPointerException
167     *             if {@code other} is {@code null}
168     */
169    public BooleanBinding isNotEqualTo(final ObservableList<?> other) {
170        return Bindings.notEqual(this, other);
171    }
172
173    /**
174     * Creates a new {@link BooleanBinding} that holds {@code true} if the wrapped list is {@code null}.
175     *
176     * @return the new {@code BooleanBinding}
177     */
178    public BooleanBinding isNull() {
179        return Bindings.isNull(this);
180    }
181
182    /**
183     * Creates a new {@link BooleanBinding} that holds {@code true} if the wrapped list is not {@code null}.
184     *
185     * @return the new {@code BooleanBinding}
186     */
187    public BooleanBinding isNotNull() {
188        return Bindings.isNotNull(this);
189    }
190
191    /**
192     * Creates a {@link javafx.beans.binding.StringBinding} that holds the value
193     * of the {@code ListExpression} turned into a {@code String}. If the
194     * value of this {@code ListExpression} changes, the value of the
195     * {@code StringBinding} will be updated automatically.
196     *
197     * @return the new {@code StringBinding}
198     */
199    public StringBinding asString() {
200        return (StringBinding) StringFormatter.convert(this);
201    }
202
203    @Override
204    public int size() {
205        final ObservableList<E> list = get();
206        return (list == null)? EMPTY_LIST.size() : list.size();
207    }
208
209    @Override
210    public boolean isEmpty() {
211        final ObservableList<E> list = get();
212        return (list == null)? EMPTY_LIST.isEmpty() : list.isEmpty();
213    }
214
215    @Override
216    public boolean contains(Object obj) {
217        final ObservableList<E> list = get();
218        return (list == null)? EMPTY_LIST.contains(obj) : list.contains(obj);
219    }
220
221    @Override
222    public Iterator<E> iterator() {
223        final ObservableList<E> list = get();
224        return (list == null)? EMPTY_LIST.iterator() : list.iterator();
225    }
226
227    @Override
228    public Object[] toArray() {
229        final ObservableList<E> list = get();
230        return (list == null)? EMPTY_LIST.toArray() : list.toArray();
231    }
232
233    @Override
234    public <T> T[] toArray(T[] array) {
235        final ObservableList<E> list = get();
236        return (list == null)? (T[]) EMPTY_LIST.toArray(array) : list.toArray(array);
237     }
238
239    @Override
240    public boolean add(E element) {
241        final ObservableList<E> list = get();
242        return (list == null)? EMPTY_LIST.add(element) : list.add(element);
243    }
244
245    @Override
246    public boolean remove(Object obj) {
247        final ObservableList<E> list = get();
248        return (list == null)? EMPTY_LIST.remove(obj) : list.remove(obj);
249    }
250
251    @Override
252    public boolean containsAll(Collection<?> objects) {
253        final ObservableList<E> list = get();
254        return (list == null)? EMPTY_LIST.contains(objects) : list.containsAll(objects);
255    }
256
257    @Override
258    public boolean addAll(Collection<? extends E> elements) {
259        final ObservableList<E> list = get();
260        return (list == null)? EMPTY_LIST.addAll(elements) : list.addAll(elements);
261    }
262
263    @Override
264    public boolean addAll(int i, Collection<? extends E> elements) {
265        final ObservableList<E> list = get();
266        return (list == null)? EMPTY_LIST.addAll(i, elements) : list.addAll(i, elements);
267    }
268
269    @Override
270    public boolean removeAll(Collection<?> objects) {
271        final ObservableList<E> list = get();
272        return (list == null)? EMPTY_LIST.removeAll(objects) : list.removeAll(objects);
273    }
274
275    @Override
276    public boolean retainAll(Collection<?> objects) {
277        final ObservableList<E> list = get();
278        return (list == null)? EMPTY_LIST.retainAll(objects) : list.retainAll(objects);
279    }
280
281    @Override
282    public void clear() {
283        final ObservableList<E> list = get();
284        if (list == null) {
285            EMPTY_LIST.clear();
286        } else {
287            list.clear();
288        }
289    }
290
291    @Override
292    public E get(int i) {
293        final ObservableList<E> list = get();
294        return (list == null)? (E) EMPTY_LIST.get(i) : list.get(i);
295    }
296
297    @Override
298    public E set(int i, E element) {
299        final ObservableList<E> list = get();
300        return (list == null)? (E) EMPTY_LIST.set(i, element) : list.set(i, element);
301    }
302
303    @Override
304    public void add(int i, E element) {
305        final ObservableList<E> list = get();
306        if (list == null) {
307            EMPTY_LIST.add(i, element);
308        } else {
309            list.add(i, element);
310        }
311    }
312
313    @Override
314    public E remove(int i) {
315        final ObservableList<E> list = get();
316        return (list == null)? (E) EMPTY_LIST.remove(i) : list.remove(i);
317    }
318
319    @Override
320    public int indexOf(Object obj) {
321        final ObservableList<E> list = get();
322        return (list == null)? EMPTY_LIST.indexOf(obj) : list.indexOf(obj);
323    }
324
325    @Override
326    public int lastIndexOf(Object obj) {
327        final ObservableList<E> list = get();
328        return (list == null)? EMPTY_LIST.lastIndexOf(obj) : list.lastIndexOf(obj);
329    }
330
331    @Override
332    public ListIterator<E> listIterator() {
333        final ObservableList<E> list = get();
334        return (list == null)? EMPTY_LIST.listIterator() : list.listIterator();
335    }
336
337    @Override
338    public ListIterator<E> listIterator(int i) {
339        final ObservableList<E> list = get();
340        return (list == null)? EMPTY_LIST.listIterator(i) : list.listIterator(i);
341    }
342
343    @Override
344    public List<E> subList(int from, int to) {
345        final ObservableList<E> list = get();
346        return (list == null)? EMPTY_LIST.subList(from, to) : list.subList(from, to);
347    }
348
349    @Override
350    public boolean addAll(E... elements) {
351        final ObservableList<E> list = get();
352        return (list == null)? EMPTY_LIST.addAll(elements) : list.addAll(elements);
353    }
354
355    @Override
356    public boolean setAll(E... elements) {
357        final ObservableList<E> list = get();
358        return (list == null)? EMPTY_LIST.setAll(elements) : list.setAll(elements);
359    }
360
361    @Override
362    public boolean setAll(Collection<? extends E> elements) {
363        final ObservableList<E> list = get();
364        return (list == null)? EMPTY_LIST.setAll(elements) : list.setAll(elements);
365    }
366
367    @Override
368    public boolean removeAll(E... elements) {
369        final ObservableList<E> list = get();
370        return (list == null)? EMPTY_LIST.removeAll(elements) : list.removeAll(elements);
371    }
372
373    @Override
374    public boolean retainAll(E... elements) {
375        final ObservableList<E> list = get();
376        return (list == null)? EMPTY_LIST.retainAll(elements) : list.retainAll(elements);
377    }
378
379    @Override
380    public void remove(int from, int to) {
381        final ObservableList<E> list = get();
382        if (list == null) {
383            EMPTY_LIST.remove(from, to);
384        } else {
385            list.remove(from, to);
386        }
387    }
388
389}