package org.tessell.widgets.cellview;
import static org.tessell.widgets.cellview.Cells.newCompositeCell;
import static org.tessell.widgets.cellview.Cells.newHeader;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.CompositeCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.HasCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
/**
* Renders multiple headers as one header.
*
* We reuse {@link CompositeCell}'s magic, however it was built assuming it was
* going to put together composite columns ({@link HasCell}s), which headers
* are not, so we have to cheat a little bit.
*
* <b>Note:</b> that to react to browser events, headers must extend {@link ExposedUpdaterHeader},
* which allows this implementation to get the header's {@link ValueUpdater}.
*/
public class CompositeHeader extends DelegateIsHeader<Object> {
public CompositeHeader(final IsHeader<?>... headers) {
super(newHeader(new ConstantHeaderValue<Object>(null), newCompositeCell(toHasCells(headers))));
}
public CompositeHeader(final IsCompositeCell<Object> cell) {
super(newHeader(new ConstantHeaderValue<Object>(null), cell));
}
/** @return {@code headers} wrapped into fake {@link HasCell}s for {@link CompositeCell}. */
public static List<HasCell<Object, ?>> toHasCells(final IsHeader<?>... headers) {
final List<HasCell<Object, ?>> cells = new ArrayList<HasCell<Object, ?>>();
for (final IsHeader<?> header : headers) {
cells.add(newHasCell(header));
}
return cells;
}
/** Creates a fake {@link HasCell} for {@code header} to satisfy the {@link CompositeCell} cstr. */
private static <X> HasCell<Object, X> newHasCell(final IsHeader<X> header) {
return new HeaderHasCell<X>(header);
}
public static final class HeaderHasCell<X> implements HasCell<Object, X> {
private final IsHeader<X> header;
private final Cell<X> headerCell;
private HeaderHasCell(final IsHeader<X> header) {
this.header = header;
headerCell = new DelegateCell<X>(header.getCell()) {
/** Instead of rendering the cell directly, give the header a chance to run it's render logic. */
@Override
public void render(Cell.Context context, X value, SafeHtmlBuilder sb) {
header.asHeader().render(context, sb);
}
/** Instead of passing the event to the cell directly, give the header a chance to run it's event logic. */
@Override
public void onBrowserEvent(Context context, Element parent, X value, NativeEvent event, ValueUpdater<X> valueUpdater) {
header.asHeader().onBrowserEvent(context, parent, event);
}
};
}
@Override
public Cell<X> getCell() {
return headerCell;
}
@Override
public FieldUpdater<Object, X> getFieldUpdater() {
if (header.getUpdater() == null) {
return null;
}
return new FieldUpdater<Object, X>() {
public void update(final int index, final Object object, final X value) {
header.getUpdater().update(value);
}
};
}
@Override
public X getValue(final Object object) {
return header.getValue();
}
}
}