package com.revolsys.swing.list;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import com.revolsys.collection.list.Lists;
import com.revolsys.datatype.DataType;
import com.revolsys.swing.parallel.Invoke;
import com.revolsys.util.Property;
import com.revolsys.util.Reorderable;
public class ArrayListModel<T> extends ArrayList<T>
implements ListModel<T>, Serializable, Reorderable {
private static final long serialVersionUID = 1L;
private final List<ListDataListener> listeners = new ArrayList<>();
public ArrayListModel() {
}
public ArrayListModel(final Collection<? extends T> values) {
addAll(values);
}
@Override
public void add(final int index, final T value) {
Invoke.andWait(() -> {
super.add(index, value);
fireIntervalAdded(index, index);
});
}
@Override
public boolean add(final T value) {
final int index = size();
add(index, value);
return true;
}
@Override
public boolean addAll(final Collection<? extends T> values) {
final int index = size();
return addAll(index, values);
}
@Override
public boolean addAll(final int index, final Collection<? extends T> values) {
if (Property.hasValue(values)) {
Invoke.andWait(() -> {
super.addAll(index, values);
fireIntervalAdded(index, index + values.size());
});
return true;
} else {
return false;
}
}
@Override
public void addListDataListener(final ListDataListener listener) {
synchronized (this.listeners) {
this.listeners.add(listener);
}
}
@Override
public void clear() {
Invoke.andWait(() -> {
if (size() > 0) {
final int index1 = size() - 1;
super.clear();
if (index1 >= 0) {
fireIntervalRemoved(0, index1);
}
}
});
}
protected void fireContentsChanged(final int index0, final int index1) {
Invoke.later(() -> {
synchronized (this.listeners) {
if (!this.listeners.isEmpty()) {
final ListDataEvent e = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index0,
index1);
for (int i = 0; i < this.listeners.size(); i++) {
final ListDataListener listener = this.listeners.get(i);
listener.contentsChanged(e);
}
}
}
});
}
protected void fireIntervalAdded(final int index0, final int index1) {
Invoke.later(() -> {
synchronized (this.listeners) {
if (!this.listeners.isEmpty()) {
final ListDataEvent e = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index0,
index1);
for (int i = 0; i < this.listeners.size(); i++) {
final ListDataListener listener = this.listeners.get(i);
try {
listener.intervalAdded(e);
} catch (final Throwable t) {
}
}
}
}
});
}
protected void fireIntervalRemoved(final int index0, final int index1) {
Invoke.later(() -> {
synchronized (this.listeners) {
if (!this.listeners.isEmpty()) {
final ListDataEvent e = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index0,
index1);
for (int i = 0; i < this.listeners.size(); i++) {
final ListDataListener listener = this.listeners.get(i);
listener.intervalRemoved(e);
}
}
}
});
}
@Override
public T getElementAt(final int index) {
if (index >= 0) {
return super.get(index);
} else {
return null;
}
}
public List<T> getElements() {
return Lists.toArray(this);
}
@Override
public int getSize() {
return size();
}
@Override
public T remove(final int index) {
final T oldValue = get(index);
Invoke.andWait(() -> {
super.remove(index);
fireIntervalRemoved(index, index);
});
return oldValue;
}
@Override
public boolean remove(final Object element) {
final int index = indexOf(element);
final T value = remove(index);
return value != null;
}
@Override
public boolean removeAll(final Collection<?> values) {
boolean removed = false;
for (final Object object : values) {
removed |= remove(object);
}
return removed;
}
public boolean removeAll(final Object... values) {
boolean removed = false;
for (final Object object : values) {
removed |= remove(object);
}
return removed;
}
@Override
public void removeListDataListener(final ListDataListener listener) {
synchronized (this.listeners) {
this.listeners.remove(listener);
}
}
@Override
public void removeRange(final int fromIndex, final int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException("fromIndex must be <= toIndex");
}
Invoke.andWait(() -> {
super.removeRange(fromIndex, toIndex);
fireIntervalRemoved(fromIndex, toIndex);
});
}
@Override
public void reorder(final int fromIndex, int toIndex) {
if (fromIndex < toIndex) {
toIndex--;
}
final T value = get(fromIndex);
remove(fromIndex);
add(toIndex, value);
}
@Override
public T set(final int index, final T element) {
final T oldValue = get(index);
Invoke.andWait(() -> {
super.set(index, element);
fireContentsChanged(index, index);
});
return oldValue;
}
public void setAll(final Iterable<? extends T> elements) {
Invoke.andWait(() -> {
if (Property.isEmpty(elements)) {
clear();
} else if (!DataType.equal(elements, this)) {
final int oldSize = size();
super.clear();
super.addAll(Lists.toArray(elements));
final int newSize = size();
if (newSize > oldSize) {
fireIntervalAdded(oldSize, newSize - 1);
} else if (newSize < oldSize) {
fireIntervalRemoved(newSize, oldSize - 1);
}
if (newSize > 0) {
fireContentsChanged(0, newSize - 1);
}
}
});
}
}