1 /*
   2  * Copyright (c) 2010, 2013, 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 javafx.collections;
  27 
  28 import java.util.Collection;
  29 import java.util.Iterator;
  30 import java.util.List;
  31 import java.util.ListIterator;
  32 
  33 /**
  34  * Abstract class that serves as a base class for {@link ObservableList} implementations that are modifiable.
  35  *
  36  * To implement a modifiable {@code ObservableList} class, you just need to implement the following set of methods:
  37  * <ul>
  38  * <li> {@link #get(int)  get(int)}
  39  * <li> {@link #size() size()}
  40  * <li> {@link #doAdd(int, java.lang.Object) doAdd(int, Object)}
  41  * <li> {@link #doRemove(int) doRemove(int)}
  42  * <li> {@link #doSet(int, java.lang.Object) doSet(int, Object)}
  43  * </ul>
  44  *
  45  * and the notifications and built and fired automatically for you.
  46  *
  47  * <p>Example of a simple {@code ObservableList} delegating to another {@code List} would look like this:
  48  *
  49  * <pre>
  50  *
  51  *   <strong>public class</strong> ArrayObservableList&lt;E&gt; <strong>extends</strong> ModifiableObservableList&lt;E&gt; {
  52  *
  53  *   <strong>private final List</strong>&lt;E&gt; delegate = new <strong>ArrayList</strong>&lt;&gt;();
  54  *
  55  *   <strong>public E</strong> get(int index) {
  56  *       <strong>return</strong> delegate.get(index);
  57  *   }
  58  *
  59  *   <strong>public int</strong> size() {
  60  *       <strong>return</strong> delegate.size();
  61  *   }
  62  *
  63  *   <strong>protected void</strong> doAdd(<strong>int</strong> index, <strong>E</strong> element) {
  64  *       delegate.add(index, element);
  65  *   }
  66  *
  67  *   <strong>protected E</strong> doSet(<strong>int</strong> index, <strong>E</strong> element) {
  68  *       <strong>return</strong> delegate.set(index, element);
  69  *   }
  70  *
  71  *   <strong>protected E</strong> doRemove(<strong>int</strong> index) {
  72  *       <strong>return</strong> delegate.remove(index);
  73  *   }
  74  *
  75  * </pre>
  76  *
  77  * @param <E> the type of the elements contained in the List
  78  * @see ObservableListBase
  79  * @since JavaFX 8.0
  80  */
  81 public abstract class ModifiableObservableListBase<E> extends ObservableListBase<E> {
  82 
  83     @Override
  84     public boolean setAll(Collection<? extends E> col) {
  85         beginChange();
  86         try {
  87             clear();
  88             addAll(col);
  89         } finally {
  90             endChange();
  91         }
  92         return true;
  93     }
  94 
  95     @Override
  96     public boolean addAll(Collection<? extends E> c) {
  97         beginChange();
  98         try {
  99             boolean res = super.addAll(c);
 100             return res;
 101         } finally {
 102             endChange();
 103         }
 104     }
 105 
 106     @Override
 107     public boolean addAll(int index, Collection<? extends E> c) {
 108         beginChange();
 109         try {
 110             boolean res = super.addAll(index, c);
 111             return res;
 112         } finally {
 113             endChange();
 114         }
 115     }
 116 
 117     @Override
 118     protected void removeRange(int fromIndex, int toIndex) {
 119         beginChange();
 120         try {
 121             super.removeRange(fromIndex, toIndex);
 122         } finally {
 123             endChange();
 124         }
 125     }
 126 
 127     @Override
 128     public boolean removeAll(Collection<?> c) {
 129         beginChange();
 130         try {
 131             boolean res = super.removeAll(c);
 132             return res;
 133         } finally {
 134             endChange();
 135         }
 136     }
 137 
 138     @Override
 139     public boolean retainAll(Collection<?> c) {
 140         beginChange();
 141         try {
 142             boolean res = super.retainAll(c);
 143             return res;
 144         } finally {
 145             endChange();
 146         }
 147     }
 148 
 149     @Override
 150     public void add(int index, E element) {
 151         doAdd(index, element);
 152         beginChange();
 153         nextAdd(index, index + 1);
 154         ++modCount;
 155         endChange();
 156     }
 157 
 158     @Override
 159     public E set(int index, E element) {
 160         E old = doSet(index, element);
 161         beginChange();
 162         nextSet(index, old);
 163         endChange();
 164         return old;
 165     }
 166 
 167     @Override
 168     public boolean remove(Object o) {
 169         int i = indexOf(o);
 170         if (i != - 1) {
 171             remove(i);
 172             return true;
 173         }
 174         return false;
 175     }
 176 
 177     @Override
 178     public E remove(int index) {
 179         E old = doRemove(index);
 180         beginChange();
 181         nextRemove(index, old);
 182         ++modCount;
 183         endChange();
 184         return old;
 185     }
 186 
 187     @Override
 188     public List<E> subList(int fromIndex, int toIndex) {
 189         return new SubObservableList(super.subList(fromIndex, toIndex));
 190     }
 191 
 192     @Override
 193     public abstract E get(int index);
 194 
 195     @Override
 196     public abstract int size();
 197 
 198     /**
 199      * Adds the {@code element} to the List at the position of {@code index}.
 200      *
 201      * <p>For the description of possible exceptions, please refer to the documentation
 202      * of {@link #add(java.lang.Object) } method.
 203      *
 204      * @param index the position where to add the element
 205      * @param element the element that will be added
 206 
 207      * @throws ClassCastException
 208      * @throws NullPointerException
 209      * @throws IllegalArgumentException
 210      * @throws IndexOutOfBoundsException if the index is out of range
 211      *         (<tt>index &lt; 0 || index &gt; size()</tt>)
 212      */
 213     protected abstract void doAdd(int index, E element);
 214 
 215     /**
 216      * Sets the {@code element} in the List at the position of {@code index}.
 217      *
 218      * <p>For the description of possible exceptions, please refer to the documentation
 219      * of {@link #set(int, java.lang.Object) } method.
 220      *
 221      * @param index the position where to set the element
 222      * @param element the element that will be set at the specified position
 223      * @return the old element at the specified position
 224      *
 225      * @throws ClassCastException
 226      * @throws NullPointerException
 227      * @throws IllegalArgumentException
 228      * @throws IndexOutOfBoundsException if the index is out of range
 229      *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
 230      */
 231     protected abstract E doSet(int index, E element);
 232 
 233     /**
 234      * Removes the element at position of {@code index}.
 235      *
 236      * @param index the index of the removed element
 237      * @return the removed element
 238      *
 239      * @throws IndexOutOfBoundsException if the index is out of range
 240      *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
 241      */
 242     protected abstract E doRemove(int index);
 243 
 244     private class SubObservableList implements List<E> {
 245 
 246         public SubObservableList(List<E> sublist) {
 247             this.sublist = sublist;
 248         }
 249         private List<E> sublist;
 250 
 251         @Override
 252         public int size() {
 253             return sublist.size();
 254         }
 255 
 256         @Override
 257         public boolean isEmpty() {
 258             return sublist.isEmpty();
 259         }
 260 
 261         @Override
 262         public boolean contains(Object o) {
 263             return sublist.contains(o);
 264         }
 265 
 266         @Override
 267         public Iterator<E> iterator() {
 268             return sublist.iterator();
 269         }
 270 
 271         @Override
 272         public Object[] toArray() {
 273             return sublist.toArray();
 274         }
 275 
 276         @Override
 277         public <T> T[] toArray(T[] a) {
 278             return sublist.toArray(a);
 279         }
 280 
 281         @Override
 282         public boolean add(E e) {
 283             return sublist.add(e);
 284         }
 285 
 286         @Override
 287         public boolean remove(Object o) {
 288             return sublist.remove(o);
 289         }
 290 
 291         @Override
 292         public boolean containsAll(Collection<?> c) {
 293             return sublist.containsAll(c);
 294         }
 295 
 296         @Override
 297         public boolean addAll(Collection<? extends E> c) {
 298             beginChange();
 299             try {
 300                 boolean res = sublist.addAll(c);
 301                 return res;
 302             } finally {
 303                 endChange();
 304             }
 305         }
 306 
 307         @Override
 308         public boolean addAll(int index, Collection<? extends E> c) {
 309             beginChange();
 310             try {
 311                 boolean res = sublist.addAll(index, c);
 312                 return res;
 313             } finally {
 314                 endChange();
 315             }
 316         }
 317 
 318         @Override
 319         public boolean removeAll(Collection<?> c) {
 320             beginChange();
 321             try {
 322                 boolean res = sublist.removeAll(c);
 323                 return res;
 324             } finally {
 325                 endChange();
 326             }
 327         }
 328 
 329         @Override
 330         public boolean retainAll(Collection<?> c) {
 331             beginChange();
 332             try {
 333                 boolean res = sublist.retainAll(c);
 334                 return res;
 335             } finally {
 336                 endChange();
 337             }
 338         }
 339 
 340         @Override
 341         public void clear() {
 342             beginChange();
 343             try {
 344                 sublist.clear();
 345             } finally {
 346                 endChange();
 347             }
 348         }
 349 
 350         @Override
 351         public E get(int index) {
 352             return sublist.get(index);
 353         }
 354 
 355         @Override
 356         public E set(int index, E element) {
 357             return sublist.set(index, element);
 358         }
 359 
 360         @Override
 361         public void add(int index, E element) {
 362             sublist.add(index, element);
 363         }
 364 
 365         @Override
 366         public E remove(int index) {
 367             return sublist.remove(index);
 368         }
 369 
 370         @Override
 371         public int indexOf(Object o) {
 372             return sublist.indexOf(o);
 373         }
 374 
 375         @Override
 376         public int lastIndexOf(Object o) {
 377             return sublist.lastIndexOf(o);
 378         }
 379 
 380         @Override
 381         public ListIterator<E> listIterator() {
 382             return sublist.listIterator();
 383         }
 384 
 385         @Override
 386         public ListIterator<E> listIterator(int index) {
 387             return sublist.listIterator(index);
 388         }
 389 
 390         @Override
 391         public List<E> subList(int fromIndex, int toIndex) {
 392             return new SubObservableList(sublist.subList(fromIndex, toIndex));
 393         }
 394 
 395         @Override
 396         public boolean equals(Object obj) {
 397             return sublist.equals(obj);
 398         }
 399 
 400         @Override
 401         public int hashCode() {
 402             return sublist.hashCode();
 403         }
 404 
 405         @Override
 406         public String toString() {
 407             return sublist.toString();
 408         }
 409     }
 410 }