All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.javafx.collections.VetoableListDecorator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.javafx.collections;

import java.util.*;
import javafx.beans.InvalidationListener;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.util.Callback;

public abstract class VetoableListDecorator implements ObservableList {

    private final ObservableList list;
    private int modCount;
    private ListListenerHelper helper;

    private static interface ModCountAccessor {
        public int get();
        public int incrementAndGet();
    }

    /**
     * The type of the change can be observed from the combination of arguments.
     * 
    *
  • If something is going to be added toBeAdded is non-empty * and indexes contain two indexes that are pointing to the position, e.g. {2, 2} *
  • If something is going to be removed, the indexes are paired by two: * from(inclusive)-to(exclusive) and are pointing to the current list. *
    E.g. if we remove 2,3,5 from list {0,1,2,3,4,5}, the indexes * will be {2, 4, 5, 6}. If there's more than one pair of indexes, toBeAdded is always empty. *
  • for set toBeAdded contains 1 element and indexes are like with removal: {index, index + 1} *
  • for setAll, toBeAdded contains all new elements and indexes looks like this: {0, size()} *
* * Note that it's always safe to iterate over toBeAdded and use indexes as pairs of * from-to, as there's always at least one pair. * * @param toBeAdded the list to be added * @throws IllegalArgumentException when the change is vetoed */ protected abstract void onProposedChange(List toBeAdded, int... indexes); public VetoableListDecorator(ObservableList decorated) { this.list = decorated; this.list.addListener(new ListChangeListener() { @Override public void onChanged(ListChangeListener.Change c) { ListListenerHelper.fireValueChangedEvent(helper, new SourceAdapterChange(VetoableListDecorator.this, c)); } }); } @Override public void addListener(ListChangeListener listener) { helper = ListListenerHelper.addListener(helper, listener); } @Override public void removeListener(ListChangeListener listener) { helper = ListListenerHelper.removeListener(helper, listener); } @Override public void addListener(InvalidationListener listener) { helper = ListListenerHelper.addListener(helper, listener); } @Override public void removeListener(InvalidationListener listener) { helper = ListListenerHelper.removeListener(helper, listener); } @Override public boolean addAll(E... elements) { return addAll(Arrays.asList(elements)); } @Override public boolean setAll(E... elements) { return setAll(Arrays.asList(elements)); } @Override public boolean setAll(Collection col) { onProposedChange(Collections.unmodifiableList(new ArrayList(col)), 0, size()); boolean ret = list.setAll(col); modCount++; return ret; } private void removeFromList(List backingList, int offset, Collection col, boolean complement) { int[] toBeRemoved = new int[2]; int pointer = -1; for (int i = 0; i < backingList.size(); ++i) { final E el = backingList.get(i); if (col.contains(el) ^ complement) { if (pointer == -1) { toBeRemoved[pointer + 1] = offset + i; toBeRemoved[pointer + 2] = offset + i + 1; pointer += 2; } else { if (toBeRemoved[pointer - 1] == offset + i) { toBeRemoved[pointer - 1] = offset + i + 1; } else { int[] tmp = new int[toBeRemoved.length + 2]; System.arraycopy(toBeRemoved, 0, tmp, 0, toBeRemoved.length); toBeRemoved = tmp; toBeRemoved[pointer + 1] = offset + i; toBeRemoved[pointer + 2] = offset + i + 1; pointer += 2; } } } } if (pointer != -1) { onProposedChange(Collections.emptyList(), toBeRemoved); } } @Override public boolean removeAll(E... elements) { return removeAll(Arrays.asList(elements)); } @Override public boolean retainAll(E... elements) { return retainAll(Arrays.asList(elements)); } @Override public void remove(int from, int to) { onProposedChange(Collections.emptyList(), from, to); list.remove(from, to); modCount++; } @Override public int size() { return list.size(); } @Override public boolean isEmpty() { return list.isEmpty(); } @Override public boolean contains(Object o) { return list.contains(o); } @Override public Iterator iterator() { return new VetoableIteratorDecorator(new ModCountAccessorImpl(),list.iterator(), 0); } @Override public Object[] toArray() { return list.toArray(); } @Override public T[] toArray(T[] a) { return list.toArray(a); } @Override public boolean add(E e) { onProposedChange(Collections.singletonList(e), size(), size()); boolean ret = list.add(e); modCount++; return ret; } @Override public boolean remove(Object o) { int i = list.indexOf(o); if (i != - 1) { remove(i); return true; } return false; } @Override public boolean containsAll(Collection c) { return list.containsAll(c); } @Override public boolean addAll(Collection c) { onProposedChange(Collections.unmodifiableList(new ArrayList(c)), size(), size()); boolean ret = list.addAll(c); if (ret) modCount++; return ret; } @Override public boolean addAll(int index, Collection c) { onProposedChange(Collections.unmodifiableList(new ArrayList(c)), index, index); boolean ret = list.addAll(index, c); if (ret) modCount++; return ret; } @Override public boolean removeAll(Collection c) { removeFromList(this, 0, c, false); boolean ret = list.removeAll(c); if (ret) modCount++; return ret; } @Override public boolean retainAll(Collection c) { removeFromList(this, 0, c, true); boolean ret = list.retainAll(c); if (ret) modCount++; return ret; } @Override public void clear() { onProposedChange(Collections.emptyList(), 0, size()); list.clear(); modCount++; } @Override public E get(int index) { return list.get(index); } @Override public E set(int index, E element) { onProposedChange(Collections.singletonList(element), index, index + 1); return list.set(index, element); } @Override public void add(int index, E element) { onProposedChange(Collections.singletonList(element), index, index); list.add(index, element); modCount++; } @Override public E remove(int index) { onProposedChange(Collections.emptyList(), index, index + 1); E ret = list.remove(index); modCount++; return ret; } @Override public int indexOf(Object o) { return list.indexOf(o); } @Override public int lastIndexOf(Object o) { return lastIndexOf(o); } @Override public ListIterator listIterator() { return new VetoableListIteratorDecorator(new ModCountAccessorImpl(), list.listIterator(), 0); } @Override public ListIterator listIterator(int index) { return new VetoableListIteratorDecorator(new ModCountAccessorImpl(), list.listIterator(index), index); } @Override public List subList(int fromIndex, int toIndex) { return new VetoableSubListDecorator(new ModCountAccessorImpl(), list.subList(fromIndex, toIndex), fromIndex); } @Override public String toString() { return list.toString(); } @Override public boolean equals(Object obj) { return list.equals(obj); } @Override public int hashCode() { return list.hashCode(); } /** * Creates a {@link javafx.collections.transformation.FilteredList} wrapper of this list using * the specified predicate. * @param predicate the predicate to use * @return new {@code FilteredList} */ public FilteredList filtered(Callback predicate) { return new FilteredList(this, predicate); } /** * Creates a {@link javafx.collections.transformation.SortedList} wrapper of this list using * the specified comparator. * @param comparator the comparator to use or null for the natural order * @return new {@code SortedList} */ public SortedList sorted(Comparator comparator) { return new SortedList(this, comparator); } /** * Creates a {@link SortedList} wrapper of this list with the natural * ordering. * @return new {@code SortedList} */ public SortedList sorted() { return sorted(null); } private class VetoableSubListDecorator implements List { private final List subList; private final int offset; private final ModCountAccessor modCountAccessor; private int modCount; public VetoableSubListDecorator(ModCountAccessor modCountAccessor, List subList, int offset) { this.modCountAccessor = modCountAccessor; this.modCount = modCountAccessor.get(); this.subList = subList; this.offset = offset; } @Override public int size() { checkForComodification(); return subList.size(); } @Override public boolean isEmpty() { checkForComodification(); return subList.isEmpty(); } @Override public boolean contains(Object o) { checkForComodification(); return subList.contains(o); } @Override public Iterator iterator() { checkForComodification(); return new VetoableIteratorDecorator(new ModCountAccessorImplSub(), subList.iterator(), offset); } @Override public Object[] toArray() { checkForComodification(); return subList.toArray(); } @Override public T[] toArray(T[] a) { checkForComodification(); return subList.toArray(a); } @Override public boolean add(E e) { checkForComodification(); onProposedChange(Collections.singletonList(e), offset + size(), offset + size()); boolean res = subList.add(e); incrementModCount(); return res; } @Override public boolean remove(Object o) { checkForComodification(); int i = indexOf(o); if (i != -1) { remove(i); return true; } return false; } @Override public boolean containsAll(Collection c) { checkForComodification(); return subList.containsAll(c); } @Override public boolean addAll(Collection c) { checkForComodification(); onProposedChange(Collections.unmodifiableList(new ArrayList(c)), offset + size(), offset + size()); boolean res = subList.addAll(c); if (res) incrementModCount(); return res; } @Override public boolean addAll(int index, Collection c) { checkForComodification(); onProposedChange(Collections.unmodifiableList(new ArrayList(c)), offset + index, offset + index); boolean res = subList.addAll(index, c); if (res) incrementModCount(); return res; } @Override public boolean removeAll(Collection c) { checkForComodification(); removeFromList(this, offset, c, false); boolean res = subList.removeAll(c); if (res) incrementModCount(); return res; } @Override public boolean retainAll(Collection c) { checkForComodification(); removeFromList(this, offset, c, true); boolean res = subList.retainAll(c); if (res) incrementModCount(); return res; } @Override public void clear() { checkForComodification(); onProposedChange(Collections.emptyList(), offset, offset + size()); subList.clear(); incrementModCount(); } @Override public E get(int index) { checkForComodification(); return subList.get(index); } @Override public E set(int index, E element) { checkForComodification(); onProposedChange(Collections.singletonList(element), offset + index, offset + index + 1); return subList.set(index, element); } @Override public void add(int index, E element) { checkForComodification(); onProposedChange(Collections.singletonList(element), offset + index, offset + index); subList.add(index, element); incrementModCount(); } @Override public E remove(int index) { checkForComodification(); onProposedChange(Collections.emptyList(), offset + index, offset + index + 1); E res = subList.remove(index); incrementModCount(); return res; } @Override public int indexOf(Object o) { checkForComodification(); return subList.indexOf(o); } @Override public int lastIndexOf(Object o) { checkForComodification(); return subList.lastIndexOf(o); } @Override public ListIterator listIterator() { checkForComodification(); return new VetoableListIteratorDecorator(new ModCountAccessorImplSub(), subList.listIterator(), offset); } @Override public ListIterator listIterator(int index) { checkForComodification(); return new VetoableListIteratorDecorator(new ModCountAccessorImplSub(), subList.listIterator(index), offset + index); } @Override public List subList(int fromIndex, int toIndex) { checkForComodification(); return new VetoableSubListDecorator(new ModCountAccessorImplSub(), subList.subList(fromIndex, toIndex), offset + fromIndex); } @Override public String toString() { checkForComodification(); return subList.toString(); } @Override public boolean equals(Object obj) { checkForComodification(); return subList.equals(obj); } @Override public int hashCode() { checkForComodification(); return subList.hashCode(); } private void checkForComodification() { if (modCount != modCountAccessor.get()) { throw new ConcurrentModificationException(); } } private void incrementModCount() { modCount = modCountAccessor.incrementAndGet(); } private class ModCountAccessorImplSub implements ModCountAccessor{ @Override public int get() { return modCount; } @Override public int incrementAndGet() { return modCount = modCountAccessor.incrementAndGet(); } } } private class VetoableIteratorDecorator implements Iterator { private final Iterator it; private final ModCountAccessor modCountAccessor; private int modCount; protected final int offset; protected int cursor; protected int lastReturned; public VetoableIteratorDecorator(ModCountAccessor modCountAccessor, Iterator it, int offset) { this.modCountAccessor = modCountAccessor; this.modCount = modCountAccessor.get(); this.it = it; this.offset = offset; } @Override public boolean hasNext() { checkForComodification(); return it.hasNext(); } @Override public E next() { checkForComodification(); E e = it.next(); lastReturned = cursor++; return e; } @Override public void remove() { checkForComodification(); if (lastReturned == -1) { throw new IllegalStateException(); } onProposedChange(Collections.emptyList(), offset + lastReturned, offset + lastReturned + 1); it.remove(); incrementModCount(); lastReturned = -1; --cursor; } protected void checkForComodification() { if (modCount != modCountAccessor.get()) { throw new ConcurrentModificationException(); } } protected void incrementModCount() { modCount = modCountAccessor.incrementAndGet(); } } private class VetoableListIteratorDecorator extends VetoableIteratorDecorator implements ListIterator { private final ListIterator lit; public VetoableListIteratorDecorator(ModCountAccessor modCountAccessor, ListIterator it, int offset) { super(modCountAccessor, it, offset); this.lit = it; } @Override public boolean hasPrevious() { checkForComodification(); return lit.hasPrevious(); } @Override public E previous() { checkForComodification(); E e = lit.previous(); lastReturned = --cursor; return e; } @Override public int nextIndex() { checkForComodification(); return lit.nextIndex(); } @Override public int previousIndex() { checkForComodification(); return lit.previousIndex(); } @Override public void set(E e) { checkForComodification(); if (lastReturned == -1) { throw new IllegalStateException(); } onProposedChange(Collections.singletonList(e), offset + lastReturned, offset + lastReturned + 1); lit.set(e); } @Override public void add(E e) { checkForComodification(); onProposedChange(Collections.singletonList(e), offset + cursor, offset + cursor); lit.add(e); incrementModCount(); ++cursor; } } private class ModCountAccessorImpl implements ModCountAccessor { public ModCountAccessorImpl() { } @Override public int get() { return modCount; } @Override public int incrementAndGet() { return ++modCount; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy