package sk.stuba.fiit.perconik.eclipse.swt.widgets;
import java.util.Comparator;
import java.util.List;
import javax.annotation.Nullable;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import sk.stuba.fiit.perconik.eclipse.swt.SortDirection;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Lists.newArrayList;
public abstract class TableSorter<T> {
static final String key = TableSorter.class.getName();
private final Table table;
@Nullable
private final Comparator<? super T> comparator;
private boolean enabled;
protected TableSorter(final Table table) {
this(table, null);
}
protected TableSorter(final Table table, @Nullable final Comparator<? super T> comparator) {
this.table = checkNotNull(table);
this.comparator = comparator;
this.enabled = true;
}
public final class Handle {
private final Switcher switcher;
Handle(final SortDirection direction) {
this.switcher = new Switcher(direction);
}
private final class Switcher implements Listener {
SortDirection direction;
Switcher(final SortDirection direction) {
this.direction = checkNotNull(direction);
}
public void handleEvent(final Event event) {
sort((TableColumn) event.widget, this.direction);
this.direction = this.direction.opposite();
}
}
public Handle attach(final TableColumn column) {
column.addListener(SWT.Selection, this.switcher);
column.setData(key, TableSorter.this);
return this;
}
public Handle detach(final TableColumn column) {
column.removeListener(SWT.Selection, this.switcher);
column.setData(key, null);
return this;
}
}
public final Handle attach(final TableColumn column) {
return this.attach(column, SortDirection.UP);
}
public final Handle attach(final TableColumn column, final SortDirection direction) {
return new Handle(direction).attach(column);
}
private static TableSorter<?> fetch(final TableColumn column) {
return ((TableSorter<?>) column.getData(key));
}
private static final void attachedSort(final TableColumn column, final SortDirection direction) {
fetch(column).sort(column, direction);
}
public static final void automaticSort(final Table table) {
automaticSort(table, table.getColumn(0), SortDirection.UP);
}
public static final void automaticSort(final Table table, final TableColumn defaultColumn, final SortDirection defaultDirection) {
TableColumn column = table.getSortColumn();
SortDirection direction = SortDirection.valueOf(table.getSortDirection());
attachedSort(column != null ? column : defaultColumn, direction != SortDirection.NONE ? direction : defaultDirection);
if (column == null) {
table.setSortColumn(null);
}
table.setSortDirection(direction.getValue());
}
public static final void enable(final Table table, final boolean value) {
for (TableColumn column: table.getColumns()) {
TableSorter<?> sorter = fetch(column);
if (sorter != null) {
sorter.setEnabled(value);
}
}
}
public static final void enable(final TableColumn column, final boolean value) {
fetch(column).setEnabled(value);
}
public final void sort(final TableColumn column, final SortDirection direction) {
if (!this.isEnabled()) {
return;
}
List<T> data = newArrayList(this.loadData());
this.directionSort(data, direction, this.comparator);
this.updateData(data);
this.table.setSortColumn(column);
this.table.setSortDirection(direction.getValue());
}
@SuppressWarnings("unchecked")
private void directionSort(final List<T> data, final SortDirection direction, final Comparator<? super T> comparator) {
if (comparator == null) {
direction.sort(List.class.cast(data));
} else {
direction.sort(data, comparator);
}
}
public abstract Iterable<T> loadData();
public abstract void updateData(Iterable<? extends T> data);
public final void setEnabled(final boolean value) {
this.enabled = value;
}
public final Table getTable() {
return this.table;
}
@Nullable
public final Comparator<? super T> getComparator() {
return this.comparator;
}
public final boolean isEnabled() {
return this.enabled;
}
}