Here is the complete code of my grid cell renderer.
VGxtGrid is a wrapper for the grid that allowes to use the GXT Grid as the client component for the Vaadin server component.
TableData is a data container used by the fasade to provide fast access to cell components, IDs, data, ...
ITableCell is an interface components (our wrapper for comunication with vaadin server components) have to implement if they are used as cell components.
Code:
import com.extjs.gxt.ui.client.Style.SelectionMode;import com.extjs.gxt.ui.client.data.BaseModel;
import com.extjs.gxt.ui.client.data.BaseModelData;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionProvider;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.form.Field;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
import com.extjs.gxt.ui.client.widget.grid.GridSelectionModel;
import com.google.gwt.user.client.Element;
/* package private */ class ComponentCellRenderer implements GridCellRenderer<BaseModelData> {
/* ------------------------------------------------------------- *
* Constants
* ------------------------------------------------------------- */
static final String CELL_HEIGHT = Constants.TABLE_CELL_HEIGHT + "px";
private static final Listener<ComponentEvent> RENDER_LISTENER = new Listener<ComponentEvent>() {
/** {@inheritDoc} */
@Override
public void handleEvent(ComponentEvent be) {
Element element = be.getComponent().getElement();
/* enable text selection in cell component */
element.setAttribute("unselectable", "off");
/* center components in cell, added for checkboxes */
element.setAttribute("align", "center");
}
};
private static final Listener<FieldEvent> KEY_LISTENER = new Listener<FieldEvent>() {
/** {@inheritDoc} */
@Override
public void handleEvent(FieldEvent be) {
if (be.getKeyCode() == 32) {
be.cancelBubble();
}
}
};
/* ------------------------------------------------------------- *
* Members
* ------------------------------------------------------------- */
private final VGxtGrid vgxtGrid;
/* ------------------------------------------------------------- *
* Constructors
* ------------------------------------------------------------- */
ComponentCellRenderer(VGxtGrid vgxtGrid) {
assert vgxtGrid != null : "VGxtGrid must not be null";
this.vgxtGrid = vgxtGrid;
}
/* ------------------------------------------------------------- *
* Implements GridCellRenderer
* ------------------------------------------------------------- */
/** {@inheritDoc} */
@Override
public Object render(final BaseModelData model, String property, ColumnData config, final int row, final int col, final ListStore<BaseModelData> store, final Grid<BaseModelData> grid) {
Component component = null;
ITableCell<?> cell = vgxtGrid.getTableData().getCell(row, col);
if (cell != null) {
component = cell.getComponent();
component.setSize((grid.getColumnModel().getColumnWidth(col) - Constants.TABLE_CELL_OFFSET) + "px", ComponentCellRenderer.CELL_HEIGHT);
component.setToolTip(cell.getToolTipConfig());
component.addStyleName("render-cell-component");
if (component.isEnabled() == false || component instanceof Field<?> && ((Field<?>) component).isReadOnly()) {
config.css = "x-selectable render-grid-cell-inner render-grid-cell-inner-disabled";
} else {
config.css = "x-selectable render-grid-cell-inner";
}
addListeners(row, col, grid, component);
}
return component;
}
private void addListeners(final int row, final int col, final Grid<BaseModelData> grid, final Component component) {
/* add change listeners to update tooltips immediately after selection or value change */
if (component instanceof SelectionProvider) {
component.addListener(Events.SelectionChange, new SelectionChangedListener<BaseModel>() {
/** {@inheritDoc} */
@Override
public void selectionChanged(SelectionChangedEvent<BaseModel> se) {
adjustTooltip(row, col, component);
}
});
} else {
component.addListener(Events.OnChange, new Listener<BaseEvent>() {
/** {@inheritDoc} */
@Override
public void handleEvent(BaseEvent be) {
adjustTooltip(row, col, component);
}
});
}
/* Avoid table scrolling when space bar is pressed */
component.addListener(Events.KeyDown, KEY_LISTENER);
/* allow text selection in field, align components centered */
component.addListener(Events.Render, RENDER_LISTENER);
/* delegate selection change to grid */
component.addListener(Events.OnClick, new Listener<ComponentEvent>() {
/** {@inheritDoc} */
@Override
public void handleEvent(ComponentEvent be) {
setSelection(grid, row, be.isControlKey());
}
});
}
private void adjustTooltip(final int row, final int col, final Component component) {
component.setToolTip(vgxtGrid.getTableData().getCell(row, col).getToolTipConfig());
}
private void setSelection(Grid<BaseModelData> grid, int row, boolean isControlKey) {
GridSelectionModel<BaseModelData> sm = grid.getSelectionModel();
BaseModelData data = grid.getStore().getAt(row);
if (sm.isSelected(data) == false) {
boolean keep = sm.getSelectionMode() == SelectionMode.MULTI && isControlKey;
sm.select(data, keep);
}
}
}