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.collections; 027 028import com.sun.javafx.collections.ListListenerHelper; 029import java.util.AbstractList; 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.Collection; 033import java.util.List; 034import javafx.beans.InvalidationListener; 035 036/** 037 * Abstract class that serves as a base class for {@link ObservableList} implementations. 038 * The base class provides two functionalities for the implementing classes. 039 * <ul> 040 * <li> Listener handling by implementing {@code addListener} and {@code removeListener} methods. 041 * {@link #fireChange(javafx.collections.ListChangeListener.Change) } method is provided 042 * for notifying the listeners with a {@code Change} object. 043 * <li> Methods for building up a {@link ListChangeListener.Change} object. There are various methods called 044 * {@code next*}, like {@link #nextAdd(int, int) } for new items in the lists or {@link #nextRemove(int, java.lang.Object) } for 045 * an item being removed from the list. 046 * <p><strong>These methods must be always enclosed in {@link #beginChange() } and {@link #endChange() } block.</strong> 047 * <p>See the example below. 048 * </ul> 049 * 050 * The following example shows how the Change build-up works: 051 * <pre> 052 * <strong>public void</strong> removeOddIndexes() { 053 * beginChange(); 054 * try { 055 * for (<strong>int</strong> i = 1; i < size(); ++i) { 056 * remove(i); 057 * } 058 * } finally { 059 * endChange(); 060 * } 061 * } 062 * 063 * <strong>public void</strong> remove(<strong>int</strong> i) { 064 * beginChange(); 065 * try { 066 * <strong>E</strong> removed = ... //do some stuff that will actually remove the element at index i 067 * nextRemove(i, removed); 068 * } finally { 069 * endChange(); 070 * } 071 * } 072 * 073 * </pre> 074 * 075 * The {@code try}/{@code finally} blocks in the example are needed only if there's a possibility for an exception to occur 076 * inside a {@code beginChange()} / {@code endChange()} block 077 * 078 * <p> 079 * Note: If you want to create modifiable {@link ObservableList} implementation, consider 080 * using {@link ModifiableObservableListBase} as a superclass. 081 * <p> 082 * Note: In order to create list with sequential access, you should override {@link #listIterator()}, 083 * {@link #iterator() } methods and use them in {@link #get}, {@link #size()} and other methods accordingly. 084 * 085 * @param <E> the type of the elements contained in the List 086 * @see ObservableList 087 * @see ListChangeListener.Change 088 * @see ModifiableObservableListBase 089 * @since 8.0 090 */ 091public abstract class ObservableListBase<E> extends AbstractList<E> implements ObservableList<E> { 092 093 private ListListenerHelper<E> listenerHelper; 094 private final ListChangeBuilder<E> changeBuilder = new ListChangeBuilder<E>(this); 095 096 /** 097 * Adds a new update operation to the change. 098 * <p><strong>Note</strong>: needs to be called inside {@code beginChange()} / {@code endChange()} block. 099 * <p><strong>Note</strong>: needs to reflect the <em>current</em> state of the list. 100 * @param pos the position in the list where the updated element resides. 101 */ 102 protected final void nextUpdate(int pos) { 103 changeBuilder.nextUpdate(pos); 104 } 105 106 /** 107 * Adds a new set operation to the change. 108 * Equivalent to {@code nextRemove(idx); nextAdd(idx, idx + 1); }. 109 * <p><strong>Note</strong>: needs to be called inside {@code beginChange()} / {@code endChange()} block. 110 * <p><strong>Note</strong>: needs to reflect the <em>current</em> state of the list. 111 * @param idx the index of the item that was set 112 * @param old the old value at the {@code idx} position. 113 */ 114 protected final void nextSet(int idx, E old) { 115 changeBuilder.nextSet(idx, old); 116 } 117 118 /** 119 * Adds a new replace operation to the change. 120 * Equivalent to {@code nextRemove(from, removed); nextAdd(from, to); } 121 * <p><strong>Note</strong>: needs to be called inside {@code beginChange()} / {@code endChange()} block. 122 * <p><strong>Note</strong>: needs to reflect the <em>current</em> state of the list. 123 * @param from the index where the items were replaced 124 * @param to the end index (exclusive) of the range where the new items reside 125 * @param removed the list of items that were removed 126 */ 127 protected final void nextReplace(int from, int to, ArrayList<? extends E> removed) { 128 changeBuilder.nextReplace(from, to, removed); 129 } 130 131 /** 132 * Adds a new remove operation to the change with multiple items removed. 133 * <p><strong>Note</strong>: needs to be called inside {@code beginChange()} / {@code endChange()} block. 134 * <p><strong>Note</strong>: needs to reflect the <em>current</em> state of the list. 135 * @param idx the index where the items were removed 136 * @param removed the list of items that were removed 137 */ 138 protected final void nextRemove(int idx, List<? extends E> removed) { 139 changeBuilder.nextRemove(idx, removed); 140 } 141 142 /** 143 * Adds a new remove operation to the change with single item removed. 144 * <p><strong>Note</strong>: needs to be called inside {@code beginChange()} / {@code endChange()} block. 145 * <p><strong>Note</strong>: needs to reflect the <em>current</em> state of the list. 146 * @param idx the index where the item was removed 147 * @param removed the item that was removed 148 */ 149 protected final void nextRemove(int idx, E removed) { 150 changeBuilder.nextRemove(idx, removed); 151 } 152 153 /** 154 * Adds a new permutation operation to the change. 155 * The permutation on index {@code "i"} contains the index, where the item from the index {@code "i"} was moved. 156 * <p>It's not necessary to provide the smallest permutation possible. It's correct to always call this method 157 * with {@code nextPermutation(0, size(), permutation); } 158 * <p><strong>Note</strong>: needs to be called inside {@code beginChange()} / {@code endChange()} block. 159 * <p><strong>Note</strong>: needs to reflect the <em>current</em> state of the list. 160 * @param from marks the beginning (inclusive) of the range that was permutated 161 * @param to marks the end (exclusive) of the range that was permutated 162 * @param perm the permutation in that range. Even if {@code from != 0}, the array should 163 * contain the indexes of the list. Therefore, such permutation would not contain indexes of range {@code (0, from)} 164 */ 165 protected final void nextPermutation(int from, int to, int[] perm) { 166 changeBuilder.nextPermutation(from, to, perm); 167 } 168 169 /** 170 * Adds a new add operation to the change. 171 * There's no need to provide the list of added items as they can be found directly in the list 172 * under the specified indexes. 173 * <p><strong>Note</strong>: needs to be called inside {@code beginChange()} / {@code endChange()} block. 174 * <p><strong>Note</strong>: needs to reflect the <em>current</em> state of the list. 175 * @param from marks the beginning (inclusive) of the range that was added 176 * @param to marks the end (exclusive) of the range that was added 177 */ 178 protected final void nextAdd(int from, int to) { 179 changeBuilder.nextAdd(from, to); 180 } 181 182 /** 183 * Begins a change block. 184 * 185 * Must be called before any of the {@code next*} methods is called. 186 * For every {@code beginChange()}, there must be a corresponding {@link #endChange() } call. 187 * <p>{@code beginChange()} calls can be nested in a {@code beginChange()}/{@code endChange()} block. 188 * 189 * @see #endChange() 190 */ 191 protected final void beginChange() { 192 changeBuilder.beginChange(); 193 } 194 195 /** 196 * Ends the change block. 197 * 198 * If the block is the outer-most block for the {@code ObservableList}, the 199 * {@code Change} is constructed and all listeners are notified. 200 * <p> Ending a nested block doesn't fire a notification. 201 * 202 * @see #beginChange() 203 */ 204 protected final void endChange() { 205 changeBuilder.endChange(); 206 } 207 208 @Override 209 public final void addListener(InvalidationListener listener) { 210 listenerHelper = ListListenerHelper.addListener(listenerHelper, listener); 211 } 212 213 @Override 214 public final void removeListener(InvalidationListener listener) { 215 listenerHelper = ListListenerHelper.removeListener(listenerHelper, listener); 216 } 217 218 @Override 219 public final void addListener(ListChangeListener<? super E> listener) { 220 listenerHelper = ListListenerHelper.addListener(listenerHelper, listener); 221 } 222 223 @Override 224 public final void removeListener(ListChangeListener<? super E> listener) { 225 listenerHelper = ListListenerHelper.removeListener(listenerHelper, listener); 226 } 227 228 /** 229 * Notifies all listeners of a change 230 * @param change 231 */ 232 protected final void fireChange(ListChangeListener.Change<? extends E> change) { 233 ListListenerHelper.fireValueChangedEvent(listenerHelper, change); 234 } 235 236 /** 237 * Returns true if there are some listeners registered for this list. 238 */ 239 protected final boolean hasListeners() { 240 return ListListenerHelper.hasListeners(listenerHelper); 241 } 242 243 @Override 244 public boolean addAll(E... elements) { 245 return addAll(Arrays.asList(elements)); 246 } 247 248 @Override 249 public boolean setAll(E... elements) { 250 return setAll(Arrays.asList(elements)); 251 } 252 253 @Override 254 public boolean setAll(Collection<? extends E> col) { 255 throw new UnsupportedOperationException(); 256 } 257 258 @Override 259 public boolean removeAll(E... elements) { 260 return removeAll(Arrays.asList(elements)); 261 } 262 263 @Override 264 public boolean retainAll(E... elements) { 265 return retainAll(Arrays.asList(elements)); 266 } 267 268 @Override 269 public void remove(int from, int to) { 270 removeRange(from, to); 271 } 272}