package com.revolsys.swing.table.object;
import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.annotation.PreDestroy;
import com.revolsys.collection.PropertyChangeArrayList;
import com.revolsys.collection.list.Lists;
import com.revolsys.swing.table.AbstractTableModel;
import com.revolsys.util.CaseConverter;
import com.revolsys.util.Property;
import com.revolsys.util.Reorderable;
public class ObjectListTableModel<T> extends AbstractTableModel
implements Reorderable, PropertyChangeListener {
private static final long serialVersionUID = 1L;
private final List<String> columnNames = new ArrayList<>();
private final List<String> columnTitles = new ArrayList<>();
private List<Class<?>> columnClasses;
private boolean editable;
private PropertyChangeArrayList<T> objects;
public ObjectListTableModel(final Collection<? extends T> objects,
final List<String> columnNames) {
this(objects, columnNames, columnNames);
}
public ObjectListTableModel(final Collection<? extends T> objects, final List<String> columnNames,
final List<String> columnTitles) {
this(objects, columnNames, columnTitles, Collections.emptyList());
}
@SuppressWarnings({
"rawtypes", "unchecked"
})
public ObjectListTableModel(final Collection<? extends T> objects, final List<String> columnNames,
final List<String> columnTitles, final List<Class<?>> columnClasses) {
if (objects == null) {
this.objects = new PropertyChangeArrayList<>();
} else if (objects instanceof PropertyChangeArrayList) {
this.objects = (PropertyChangeArrayList)objects;
} else {
this.objects = new PropertyChangeArrayList<>(objects);
}
Property.addListener(this.objects, this);
this.columnNames.addAll(columnNames);
for (int i = 0; i < columnNames.size(); i++) {
final String columnName = columnNames.get(i);
String columnTitle;
if (columnTitles == null || i >= columnTitles.size()) {
columnTitle = CaseConverter.toCapitalizedWords(columnName);
} else {
columnTitle = columnTitles.get(i);
}
this.columnTitles.add(columnTitle);
}
this.columnClasses = Lists.toArray(columnClasses);
setEditable(true);
}
public ObjectListTableModel(final List<String> columnNames, final List<String> columnTitles) {
this(Collections.<T> emptyList(), columnNames, columnTitles);
}
public ObjectListTableModel(final String... columnNames) {
this(Collections.<T> emptyList(), Arrays.asList(columnNames), null);
setEditable(false);
}
public void add(final int index, final T object) {
this.objects.add(index, object);
}
@SuppressWarnings("unchecked")
public void add(final T... objects) {
addAll(Arrays.asList(objects));
}
public void addAll(final Collection<? extends T> objects) {
this.objects.addAll(objects);
}
public void clear() {
this.objects.clear();
}
@Override
@PreDestroy
public void dispose() {
Property.removeListener(this.objects, this);
this.objects = null;
}
@Override
public Class<?> getColumnClass(final int columnIndex) {
if (columnIndex >= 0 && columnIndex < this.columnClasses.size()) {
return this.columnClasses.get(columnIndex);
} else {
return Object.class;
}
}
@Override
public int getColumnCount() {
return this.columnNames.size();
}
@Override
public String getColumnName(final int columnIndex) {
return this.columnTitles.get(columnIndex);
}
public String getFieldName(final int columnIndex) {
return this.columnNames.get(columnIndex);
}
public T getObject(final int index) {
if (this.objects != null) {
if (index < this.objects.size()) {
return this.objects.get(index);
}
}
return null;
}
/**
* @return the objects
*/
public List<T> getObjects() {
return this.objects;
}
public List<Object> getObjects(final int[] rows) {
final List<Object> objects = new ArrayList<>();
for (final int row : rows) {
final Object object = getObject(row);
if (object != null) {
objects.add(object);
}
}
return objects;
}
@Override
public PropertyChangeSupport getPropertyChangeSupport() {
return this.objects.getPropertyChangeSupport();
}
@Override
public int getRowCount() {
return this.objects.size();
}
@Override
public Object getValueAt(final int rowIndex, final int columnIndex) {
final Object object = getObject(rowIndex);
if (object == null) {
return null;
} else {
try {
final String name = getFieldName(columnIndex);
if (name.equals("#")) {
return rowIndex + 1;
} else {
return Property.get(object, name);
}
} catch (final Throwable t) {
return null;
}
}
}
@Override
public boolean isCellEditable(final int rowIndex, final int columnIndex) {
final String name = getFieldName(columnIndex);
if (name.equals("#")) {
return false;
} else {
return isEditable();
}
}
public boolean isEditable() {
return this.editable;
}
@Override
public void propertyChange(final PropertyChangeEvent event) {
if (event.getSource() == this.objects) {
if (event instanceof IndexedPropertyChangeEvent) {
final IndexedPropertyChangeEvent indexedEvent = (IndexedPropertyChangeEvent)event;
final int index = indexedEvent.getIndex();
if (indexedEvent.getNewValue() == null) {
fireTableRowsDeleted(index, index);
} else if (indexedEvent.getOldValue() == null) {
fireTableRowsInserted(index, index);
} else {
fireTableRowsUpdated(index, index);
}
} else {
fireTableDataChanged();
}
}
}
public void remove(final int... rows) {
final List<Object> rowsToRemove = getObjects(rows);
removeAll(rowsToRemove);
}
public void removeAll(final Collection<Object> objects) {
this.objects.removeAll(objects);
}
public void removeAll(final Object... removedFeatures) {
removeAll(Arrays.asList(removedFeatures));
}
public void removeObject(final Object object) {
this.objects.remove(object);
}
@Override
public void reorder(final int fromIndex, int toIndex) {
if (fromIndex < toIndex) {
toIndex--;
}
final T object = getObject(fromIndex);
removeAll(object);
add(toIndex, object);
}
public void setEditable(final boolean editable) {
this.editable = editable;
}
/**
* @param objects the objects to set
*/
public void setObjects(final Collection<? extends T> objects) {
this.objects.clear();
if (objects != null) {
this.objects.addAll(objects);
}
fireTableDataChanged();
}
@Override
public void setValueAt(final Object value, final int rowIndex, final int columnIndex) {
final Object object = getObject(rowIndex);
if (object != null) {
final String name = getColumnName(columnIndex);
final Object oldValue = Property.get(object, name);
Property.setSimple(object, name, value);
firePropertyChange(object, name, oldValue, value);
}
}
}