1 /* 2 * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.scene.control; 27 28 import java.util.Arrays; 29 import java.util.Collection; 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.ListIterator; 33 import java.util.NoSuchElementException; 34 35 import javafx.beans.InvalidationListener; 36 import com.sun.javafx.collections.ListListenerHelper; 37 import javafx.collections.ListChangeListener; 38 import javafx.collections.ListChangeListener.Change; 39 import javafx.collections.ObservableList; 40 import javafx.collections.ObservableListBase; 41 42 import java.util.Collections; 43 import java.util.function.Consumer; 44 45 import static com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent; 46 47 /** 48 * A read-only and unbacked ObservableList - the data is retrieved on demand by 49 * subclasses via the get method. A combination of ObservableList, ObservableListWrapper 50 * and GenericObservableList. 51 * 52 */ 53 public abstract class ReadOnlyUnbackedObservableList<E> extends ObservableListBase<E> { 54 55 @Override public abstract E get(int i); 56 57 @Override public abstract int size(); 58 59 public void _beginChange() { 60 beginChange(); 61 } 62 63 public void _endChange() { 64 endChange(); 65 } 66 67 public void _nextUpdate(int pos) { 68 nextUpdate(pos); 69 } 70 71 public void _nextSet(int idx, E old) { 72 nextSet(idx, old); 73 } 74 75 public void _nextReplace(int from, int to, List<? extends E> removed) { 76 nextReplace(from, to, removed); 77 } 78 79 public void _nextRemove(int idx, List<? extends E> removed) { 80 nextRemove(idx, removed); 81 } 82 83 public void _nextRemove(E o) { 84 int indexOfObject = indexOf(o); 85 _nextRemove(indexOfObject, o); 86 } 87 88 public void _nextRemove(int idx, E removed) { 89 nextRemove(idx, removed); 90 } 91 92 public void _nextPermutation(int from, int to, int[] perm) { 93 nextPermutation(from, to, perm); 94 } 95 96 public void _nextAdd(int from, int to) { 97 nextAdd(from, to); 98 } 99 100 public void fireChange(Runnable r) { 101 _beginChange(); 102 r.run(); 103 _endChange(); 104 } 105 106 107 108 109 public void callObservers(Change<E> c) { 110 fireChange(c); 111 } 112 113 @Override public int indexOf(Object o) { 114 if (o == null) return -1; 115 116 for (int i = 0; i < size(); i++) { 117 Object obj = get(i); 118 if (o.equals(obj)) return i; 119 } 120 121 return -1; 122 } 123 124 @Override public int lastIndexOf(Object o) { 125 if (o == null) return -1; 126 127 for (int i = size() - 1; i >= 0; i--) { 128 Object obj = get(i); 129 if (o.equals(obj)) return i; 130 } 131 132 return -1; 133 } 134 135 @Override public boolean contains(Object o) { 136 return indexOf(o) != -1; 137 } 138 139 @Override public boolean containsAll(Collection<?> c) { 140 for (Object o : c) { 141 if (! contains(o)) { 142 return false; 143 } 144 } 145 return true; 146 } 147 148 @Override public boolean isEmpty() { 149 return size() == 0; 150 } 151 152 @Override public ListIterator<E> listIterator() { 153 return new SelectionListIterator<E>(this); 154 } 155 156 @Override public ListIterator<E> listIterator(int index) { 157 return new SelectionListIterator<E>(this, index); 158 } 159 160 @Override 161 public Iterator<E> iterator() { 162 return new SelectionListIterator<E>(this); 163 } 164 165 /** 166 * NOTE: This method does not fulfill the subList contract from Collections, 167 * it simply returns a list containing the values in the given range. 168 */ 169 @Override public List<E> subList(final int fromIndex, final int toIndex) { 170 if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex) { 171 throw new IndexOutOfBoundsException("[ fromIndex: " + fromIndex + ", toIndex: " + toIndex + ", size: " + size() + " ]"); 172 } 173 174 final List<E> outer = this; 175 return new ReadOnlyUnbackedObservableList<E>() { 176 @Override public E get(int i) { 177 return outer.get(i + fromIndex); 178 } 179 180 @Override public int size() { 181 return toIndex - fromIndex; 182 } 183 }; 184 } 185 186 @Override 187 public Object[] toArray() { 188 Object[] arr = new Object[size()]; 189 for (int i = 0; i < size(); i++) { 190 arr[i] = get(i); 191 } 192 return arr; 193 } 194 195 @SuppressWarnings("unchecked") 196 @Override 197 public <T> T[] toArray(T[] a) { 198 Object[] elementData = toArray(); 199 int size = elementData.length; 200 201 if (a.length < size) 202 // Make a new array of a's runtime type, but my contents: 203 return (T[]) Arrays.copyOf(elementData, size, a.getClass()); 204 System.arraycopy(elementData, 0, a, 0, size); 205 if (a.length > size) 206 a[size] = null; 207 return a; 208 } 209 210 @Override 211 public String toString() { 212 // copied from AbstractCollection 213 Iterator<E> i = iterator(); 214 if (! i.hasNext()) 215 return "[]"; 216 217 StringBuilder sb = new StringBuilder(); 218 sb.append('['); 219 for (;;) { 220 E e = i.next(); 221 sb.append(e == this ? "(this Collection)" : e); 222 if (! i.hasNext()) 223 return sb.append(']').toString(); 224 sb.append(", "); 225 } 226 } 227 228 @Override public boolean add(E e) { 229 throw new UnsupportedOperationException("Not supported."); 230 } 231 232 @Override public void add(int index, E element) { 233 throw new UnsupportedOperationException("Not supported."); 234 } 235 236 @Override public boolean addAll(Collection<? extends E> c) { 237 throw new UnsupportedOperationException("Not supported."); 238 } 239 240 @Override public boolean addAll(int index, Collection<? extends E> c) { 241 throw new UnsupportedOperationException("Not supported."); 242 } 243 244 @Override public boolean addAll(E... elements) { 245 throw new UnsupportedOperationException("Not supported."); 246 } 247 248 @Override public E set(int index, E element) { 249 throw new UnsupportedOperationException("Not supported."); 250 } 251 252 @Override public boolean setAll(Collection<? extends E> col) { 253 throw new UnsupportedOperationException("Not supported."); 254 } 255 256 @Override public boolean setAll(E... elements) { 257 throw new UnsupportedOperationException("Not supported."); 258 } 259 260 @Override public void clear() { 261 throw new UnsupportedOperationException("Not supported."); 262 } 263 264 @Override public E remove(int index) { 265 throw new UnsupportedOperationException("Not supported."); 266 } 267 268 @Override public boolean remove(Object o) { 269 throw new UnsupportedOperationException("Not supported."); 270 } 271 272 @Override public boolean removeAll(Collection<?> c) { 273 throw new UnsupportedOperationException("Not supported."); 274 } 275 276 @Override public boolean retainAll(Collection<?> c) { 277 throw new UnsupportedOperationException("Not supported."); 278 } 279 280 @Override public void remove(int from, int to) { 281 throw new UnsupportedOperationException("Not supported."); 282 } 283 284 @Override public boolean removeAll(E... elements) { 285 throw new UnsupportedOperationException("Not supported."); 286 } 287 288 @Override public boolean retainAll(E... elements) { 289 throw new UnsupportedOperationException("Not supported."); 290 } 291 292 // Iterator to traverse the list of selected indices in both directions. 293 private static class SelectionListIterator<E> implements ListIterator<E> { 294 private int pos; 295 private final ReadOnlyUnbackedObservableList<E> list; 296 297 public SelectionListIterator(ReadOnlyUnbackedObservableList<E> list) { 298 this(list, 0); 299 } 300 301 public SelectionListIterator(ReadOnlyUnbackedObservableList<E> list, int pos) { 302 this.list = list; 303 this.pos = pos; 304 } 305 306 @Override public boolean hasNext() { 307 return pos < list.size(); 308 } 309 310 @Override public E next() { 311 if (!hasNext()) { 312 throw new NoSuchElementException(); 313 } 314 return list.get(pos++); 315 } 316 317 @Override public boolean hasPrevious() { 318 return pos > 0; 319 } 320 321 @Override public E previous() { 322 if (!hasPrevious()) { 323 throw new NoSuchElementException(); 324 } 325 return list.get(--pos); 326 } 327 328 @Override public int nextIndex() { 329 return pos; 330 } 331 332 @Override public int previousIndex() { 333 return pos - 1; 334 } 335 336 @Override public void remove() { 337 throw new UnsupportedOperationException("Not supported."); 338 } 339 340 @Override public void set(E e) { 341 throw new UnsupportedOperationException("Not supported."); 342 } 343 344 @Override public void add(E e) { 345 throw new UnsupportedOperationException("Not supported."); 346 } 347 } 348 }