Created
June 1, 2012 05:04
-
-
Save fastnsilver/2848969 to your computer and use it in GitHub Desktop.
WrapperCell is a "knock-off" of GWT's CompositeCell. Provides access to inner cells. Used by CompositeValidatableColumn.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
import com.google.gwt.cell.client.AbstractCell; | |
import com.google.gwt.cell.client.Cell; | |
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.EventTarget; | |
import com.google.gwt.dom.client.NativeEvent; | |
import com.google.gwt.safehtml.shared.SafeHtmlBuilder; | |
/** | |
* A re-imagination of GWT's {@link CompositeCell} that uses {@link AbstractCell}'s <code>getConsumedEvents()</code> instead. | |
* Provides access to "wrapped" cells. Furthermore, cell data type is restricted to String. | |
* | |
* @param <C> the type that this Cell represents | |
*/ | |
public class WrapperCell<C> extends AbstractCell<C> { | |
/** | |
* Indicates whether or not this cell depends on selection. | |
*/ | |
private boolean dependsOnSelection; | |
/** | |
* Indicates whether or not this cell handles selection. | |
*/ | |
private boolean handlesSelection; | |
/** | |
* The cells that compose this {@link Cell}. | |
* | |
* NOTE: Do not add add/insert/remove hasCells methods to the API. This cell | |
* assumes that the index of the cellParent corresponds to the index in the | |
* hasCells array. | |
*/ | |
private final List<HasCell<C, String>> hasCells; | |
/** | |
* Construct a new {@link WrapperCell}. | |
* | |
* @param hasCells the cells that makeup the composite | |
*/ | |
public WrapperCell(List<HasCell<C, String>> hasCells) { | |
super(new ConsumedEventsFactory<C>().getEvents(hasCells)); | |
// Create a new array so cells cannot be added or removed. | |
this.hasCells = new ArrayList<HasCell<C, String>>(hasCells); | |
initDependsOnSelection(); | |
initHandlesSelection(); | |
} | |
private void initDependsOnSelection() { | |
for (final HasCell<C, String> hasCell : hasCells) { | |
final Cell<String> cell = hasCell.getCell(); | |
if (cell.dependsOnSelection()) { | |
dependsOnSelection = true; | |
} | |
} | |
} | |
private void initHandlesSelection() { | |
for (final HasCell<C, String> hasCell : hasCells) { | |
final Cell<String> cell = hasCell.getCell(); | |
if (cell.handlesSelection()) { | |
handlesSelection = true; | |
} | |
} | |
} | |
@Override | |
public boolean dependsOnSelection() { | |
return dependsOnSelection; | |
} | |
@Override | |
public boolean handlesSelection() { | |
return handlesSelection; | |
} | |
@Override | |
public boolean isEditing(Context context, Element parent, C value) { | |
Element curChild = getContainerElement(parent).getFirstChildElement(); | |
for (final HasCell<C, String> hasCell : hasCells) { | |
if (isEditingImpl(context, curChild, value, hasCell)) { | |
return true; | |
} | |
curChild = curChild.getNextSiblingElement(); | |
} | |
return false; | |
} | |
@Override | |
public void onBrowserEvent(Context context, Element parent, C value, | |
NativeEvent event, ValueUpdater<C> valueUpdater) { | |
int index = 0; | |
final EventTarget eventTarget = event.getEventTarget(); | |
if (Element.is(eventTarget)) { | |
final Element target = eventTarget.cast(); | |
final Element container = getContainerElement(parent); | |
Element wrapper = container.getFirstChildElement(); | |
while (wrapper != null) { | |
if (wrapper.isOrHasChild(target)) { | |
onBrowserEventImpl(context, wrapper, value, event, valueUpdater, | |
hasCells.get(index)); | |
} | |
index++; | |
wrapper = wrapper.getNextSiblingElement(); | |
} | |
} | |
} | |
@Override | |
public void render(Context context, C value, SafeHtmlBuilder sb) { | |
for (final HasCell<C, String> hasCell : hasCells) { | |
render(context, value, sb, hasCell); | |
} | |
} | |
@Override | |
public boolean resetFocus(Context context, Element parent, C value) { | |
Element curChild = getContainerElement(parent).getFirstChildElement(); | |
for (final HasCell<C, String> hasCell : hasCells) { | |
// The first child that takes focus wins. Only one child should ever be in | |
// edit mode, so this is safe. | |
if (resetFocusImpl(context, curChild, value, hasCell)) { | |
return true; | |
} | |
curChild = curChild.getNextSiblingElement(); | |
} | |
return false; | |
} | |
@Override | |
public void setValue(Context context, Element parent, C object) { | |
Element curChild = getContainerElement(parent).getFirstChildElement(); | |
for (final HasCell<C, String> hasCell : hasCells) { | |
setValueImpl(context, curChild, object, hasCell); | |
curChild = curChild.getNextSiblingElement(); | |
} | |
} | |
/** | |
* Get the element that acts as the container for all children. If children | |
* are added directly to the parent, the parent is the container. If children | |
* are added in a table row, the row is the parent. | |
* | |
* @param parent the parent element of the cell | |
* @return the container element | |
*/ | |
protected Element getContainerElement(Element parent) { | |
return parent; | |
} | |
/** | |
* Render the composite cell as HTML into a {@link SafeHtmlBuilder}, suitable | |
* for passing to {@link Element#setInnerHTML} on a container element. | |
* | |
* <p> | |
* Note: If your cell contains natively focusable elements, such as buttons or | |
* input elements, be sure to set the tabIndex to -1 so that they do not steal | |
* focus away from the containing widget. | |
* </p> | |
* | |
* @param context the {@link com.google.gwt.cell.client.Cell.Context Context} of the cell | |
* @param value the cell value to be rendered | |
* @param sb the {@link SafeHtmlBuilder} to be written to | |
* @param hasCell a {@link HasCell} instance containing the cells to be | |
* rendered within this cell | |
*/ | |
protected <X> void render(Context context, C value, | |
SafeHtmlBuilder sb, HasCell<C, X> hasCell) { | |
final Cell<X> cell = hasCell.getCell(); | |
sb.appendHtmlConstant("<span>"); | |
cell.render(context, hasCell.getValue(value), sb); | |
sb.appendHtmlConstant("</span>"); | |
} | |
private <X> boolean isEditingImpl(Context context, Element cellParent, C object, | |
HasCell<C, X> hasCell) { | |
return hasCell.getCell().isEditing(context, cellParent, hasCell.getValue(object)); | |
} | |
private <X> void onBrowserEventImpl(Context context, Element parent, | |
final C object, NativeEvent event, final ValueUpdater<C> valueUpdater, | |
final HasCell<C, X> hasCell) { | |
ValueUpdater<X> tempUpdater = null; | |
final FieldUpdater<C, X> fieldUpdater = hasCell.getFieldUpdater(); | |
if (fieldUpdater != null) { | |
tempUpdater = new ValueUpdater<X>() { | |
@Override | |
public void update(X value) { | |
fieldUpdater.update(-1, object, value); | |
if (valueUpdater != null) { | |
valueUpdater.update(object); | |
} | |
} | |
}; | |
} | |
final Cell<X> cell = hasCell.getCell(); | |
cell.onBrowserEvent(context, parent, hasCell.getValue(object), event, | |
tempUpdater); | |
} | |
private <X> boolean resetFocusImpl(Context context, Element cellParent, | |
C value, HasCell<C, X> hasCell) { | |
final X cellValue = hasCell.getValue(value); | |
return hasCell.getCell().resetFocus(context, cellParent, cellValue); | |
} | |
private <X> void setValueImpl(Context context, Element cellParent, C object, | |
HasCell<C, X> hasCell) { | |
hasCell.getCell().setValue(context, cellParent, hasCell.getValue(object)); | |
} | |
public List<HasCell<C, String>> getInnerCells() { | |
return Collections.unmodifiableList(hasCells); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment