Nebula NatTable didn't display correct cell editor when use GridLayer. - eclipse-rcp

I edited a Nebula example (_301_CustomDataProviderExample) to test the cell editing feature on pressing tab key (enable next cell editing on pressing tab key). The problem occurred when I used GridLayer: the cell editor was display incorrect. I think it's because of row and column headers but I don't know how to debug or fix. Can you help me or give me some hints? This is the code I have edited or added:
#Override
public Control createExampleControl(Composite parent) {
String[][] testData = new String[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
testData[i][j] = "" + i + "/" + j;
}
}
IDataProvider bodyDataProvider = new TwoDimensionalArrayDataProvider(testData);
final DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
SelectionLayer selectionLayer = new SelectionLayer(bodyDataLayer);
ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);
viewportLayer.addConfiguration(new DefaultEditConfiguration());
viewportLayer.addConfiguration(new DefaultEditBindings());
IDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(bodyDataProvider);
DataLayer rowHeaderDataLayer = new DataLayer(rowHeaderDataProvider, 40, DataLayer.DEFAULT_ROW_HEIGHT);
rowHeaderDataLayer.setColumnsResizableByDefault(true);
ILayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer, viewportLayer, selectionLayer);
IDataProvider columnHeaderDataProvider = new LetterColumnHeaderDataProvider(20);
ILayer columnHeaderLayer = new ColumnHeaderLayer(
new DefaultColumnHeaderDataLayer(columnHeaderDataProvider), viewportLayer, selectionLayer);
IDataProvider conerDataProvider = new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider);
ILayer cornerLayer = new CornerLayer(new DataLayer(conerDataProvider), rowHeaderLayer, columnHeaderLayer);
GridLayer gridLayer = new GridLayer(viewportLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer, false);
final NatTable natTable = new NatTable(parent, false);
natTable.setLayer(/* viewportLayer */ gridLayer);
natTable.addConfiguration(new DefaultNatTableStyleConfiguration() {
#Override
public void configureRegistry(IConfigRegistry configRegistry) {
super.configureRegistry(configRegistry);
configRegistry.registerConfigAttribute(
EditConfigAttributes.CELL_EDITABLE_RULE,
IEditableRule.ALWAYS_EDITABLE);
}
});
natTable.configure();
return natTable;
}
Added:
class LetterColumnHeaderDataProvider implements IDataProvider {
private int columns = 0;
public LetterColumnHeaderDataProvider(int columns) {
this.columns = columns;
}
#Override
public Object getDataValue(int columnIndex, int rowIndex) {
return (char) ('A' + columnIndex);
// TODO: support column header AA-AZ, ZA-ZZ, ZZZ...
}
#Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
throw new UnsupportedOperationException();
}
#Override
public int getColumnCount() {
return this.columns;
}
#Override
public int getRowCount() {
return 1;
}
}

The issue is related to registering the DefaultEditConfiguration on the ViewportLayer. Doing this will result in placing the editor that is identified on key press relative to the body layer stack and not the GridLayer. The default configuration applied with the GridLayer contains the necessary edit configurations already. But you disabled it via the last parameter in the GridLayer constructor.
In short, remove the following two lines from your example, they are only needed in case of compositions without a GridLayer.
viewportLayer.addConfiguration(new DefaultEditConfiguration());
viewportLayer.addConfiguration(new DefaultEditBindings());
and change the creation of the GridLayer to this
GridLayer gridLayer = new GridLayer(viewportLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer);
And as a hint, be careful when copying code from different examples when not understanding their purpose. The NatTable examples typically contain explanations in code to explain them in more detail.

Related

Nattable custom label accumulator

A NatTable requires to set cells of column 3 with BACKGROUND_COLOR = GUIHelper.COLOR_GREEN when the property of the Material is of type "Composite".
Material list is the source of data (the DataProvider)
NatTable is configured with StackingTableConfiguration.class
NatTable uses a custom label to set the cell style by means of StackingTableLabelAccumulator.class
As suggested in https://www.eclipse.org/forums/index.php/t/781508/
I have set the cellLabelAccumulator body data layer.
I used AggregateConfigLabelAccumulator since I have the custom label accumulator (AggregateConfigLabelAccumulator) and a columnLabelAccumulator.
When the Material is of type Composite, the label is added to the config labels, but the green color is nor render.
public class StackingTable {
private NatTable natTable;
public static IDataProvider bodyDataProvider;
public static String COLUMN_ONE_LABEL = "ColumnOneLabel";
public static String COLUMN_TWO_LABEL = "ColumnTwoLabel";
public static String COLUMN_THREE_LABEL = "ColumnThreeLabel";
public static String TEST = "Composite_Label";
public StackingTable(Composite parent,
EventList<AncolabStackingLayer> ancolabStackingData,
SelectionLayer stackingTableSelectionLayer ) {
bodyDataProvider = new ListDataProvider<>(ancolabStackingData, colAccessor);
final DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
final ColumnOverrideLabelAccumulator columnLabelAccumulator =
new ColumnOverrideLabelAccumulator(bodyDataLayer);
columnLabelAccumulator.registerColumnOverrides(0, COLUMN_ONE_LABEL);
columnLabelAccumulator.registerColumnOverrides(1, COLUMN_TWO_LABEL);
columnLabelAccumulator.registerColumnOverrides(2, COLUMN_THREE_LABEL);
//Create the gridLayer
natTable = new NatTable(parent, gridLayer, false);
AggregateConfigLabelAccumulator aggregateConfigLabelAccumulator =
new AggregateConfigLabelAccumulator();
aggregateConfigLabelAccumulator.add(columnLabelAccumulator);
aggregateConfigLabelAccumulator.add(
new StackingTableLabelAccumulator(bodyDataProvider));
bodyDataLayer.setConfigLabelAccumulator(aggregateConfigLabelAccumulator);
bodyDataLayer.addConfiguration(
new DefaultNatTableStyleConfiguration());
bodyDataLayer.addConfiguration(
new StackingTableConfiguration(bodyDataProvider));
bodyDataLayer.addConfiguration(new DefaultEditConfiguration());
bodyDataLayer.addConfiguration(new DefaultEditBindings());
natTable.configure();
}
The configuration registry:
public class StackingTableConfiguration extends AbstractRegistryConfiguration {
private IDataProvider bodyDataProvider;
public StackingTableConfiguration(IDataProvider dp) {
this.bodyDataProvider = dp;
#Override
public void configureRegistry(IConfigRegistry configRegistry) {
//...some configutarion attributes for other columns
Style cellStyle2 = new Style();
cellStyle2.setAttributeValue(
CellStyleAttributes.BACKGROUND_COLOR,
GUIHelper.COLOR_GREEN);
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_STYLE, cellStyle2,
DisplayMode.NORMAL, StackingTable.TEST);
}
}
The custom label accumulator:
//Add a label to cells in column 2 when the material of the row is of type = "Composite"
public class StackingTableLabelAccumulator extends AbstractOverrider {
IDataProvider dataProvider;
public StackingTableLabelAccumulator(IDataProvider dataProvider){
this.dataProvider = dataProvider;
}
#Override
public void accumulateConfigLabels(LabelStack configLabels,
int columnPosition, int rowPosition) {
Material mat =
(Material) ((IRowDataProvider) dataProvider).getRowObject(rowPosition);
if(mat.getType().equals("Composite")&& columnPosition == 2) {
configLabels.addLabel(StackingTable.TEST);
//When a material of type composite,
//the code reachs this point, i.e. the label is added to the labelStack
System.out.println(configLabels.getLabels().get(1).toString() +
"\t" + columnPosition + "\t" + rowPosition);
}
}
}

How to set the color of the first column of a Listview item?

I have a Listview (shown in an AlertDialog) that is composed by two columns, made with a HashMap (got the idea somewhere here).
Each column is a TextView. It works well.
Now I want to change the textcolor of the first column of a given row, but I have no idea on how to pick and set this... I googled for hours! Any clues??
This is my code (lists is a SortedSet):
public void showlistdesc () {
ListView listview = new ListView(this);
listview.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
listview.setSoundEffectsEnabled(true);
listview.setSelector(R.drawable.selector);
Integer i=0, pos = 0;
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map;
for (String l : lists) {
if (l.equals(currlist)) pos = i;
i++;
map = new HashMap<String, String>();
map.put("list", l);
map.put("desc", getlistdesc(l, false));
mylist.add(map);
}
listview.setAdapter(new SimpleAdapter(this, mylist, R.layout.lists_row,
new String[] {"list", "desc"}, new int[] {R.id.list1, R.id.desc1}));
AlertDialog.Builder builder = new AlertDialog.Builder(AveActivity.this)
.setView(listview)
.setIcon(R.drawable.ic_launcher)
.setTitle(lists.size() + " bird lists in databases");
final AlertDialog dial = builder.create();
//Scrolls the listview to this position at top
listview.setSelection(pos);
dial.show();
}
Thanks!
EDIT
Tried to extend SimpleAdapter with the following code, and all I can see are solid black rows:
public class MySimpleAdapter extends SimpleAdapter {
private Context context;
public MySimpleAdapter(Context context,List<? extends Map<String, ?>> data,
int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.lists_row, null);
}
TextView list1 = ((TextView) v.findViewById(R.id.list1));
TextView desc1 = ((TextView) v.findViewById(R.id.desc1));
if (v.isPressed()) {
v.setBackgroundColor(context.getResources().getColor(R.color.pressed));
list1.setTypeface(null, 1);
list1.setTextColor(context.getResources().getColor(R.color.selected));
} else {
v.setBackgroundColor(context.getResources().getColor(R.color.black));
if (v.isSelected()) {
list1.setTypeface(null, 1);
list1.setTextColor(context.getResources().getColor(R.color.checked));
desc1.setTextColor(context.getResources().getColor(R.color.white));
} else {
list1.setTypeface(null, 0);
list1.setTextColor(context.getResources().getColor(R.color.normal));
desc1.setTextColor(context.getResources().getColor(R.color.lesswhite));
}
}
return v;
}
}
Now you have special requirement, it is no longer simple, you can't use SimpleAdapter to achieve the effect you are asking. You will have to extend BaseAdapter and in the getView() method you can do the following:
if (position == 0) {
convertView.setBackground(color1);
} else {
convertView.setBackground(color2);
}
Or if what you want is a Header, you can use ListView.addHeaderView() without much hassle.
I found a solution, essentially contained in several posts here.
What I did was to use listview.setItemChecked(pos, true);, something that I tried before and failed, because it showed nothing. The problem was that LinearLayout does not implement Checkable. So I implemented it (code found essentially somewhere here also) with this:
public class CheckableLinearLayout extends LinearLayout implements Checkable {
private boolean isChecked;
public CheckableLinearLayout(Context context) {
super(context);
}
public CheckableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
TextView list1 = ((TextView) findViewById(R.id.list1));
TextView desc1 = ((TextView) findViewById(R.id.desc1));
if (isPressed()) {
list1.setTextColor(getResources().getColor(R.color.selected));
setBackgroundColor(getResources().getColor(R.color.pressed));
} else {
setBackgroundColor(getResources().getColor(R.color.black));
if (isChecked) {
list1.setTextColor(getResources().getColor(R.color.checked));
desc1.setTextColor(getResources().getColor(R.color.white));
} else {
list1.setTextColor(getResources().getColor(R.color.normal));
desc1.setTextColor(getResources().getColor(R.color.lesswhite));
}
}
}
public boolean isChecked() {
return isChecked;
}
public void toggle() {
setChecked(!isChecked);
}
}
And that's it. No need to use selector, nor to touch the adapter. To make this work, in the row layout, use <com.[yourpackage].CheckableLinearLayout instead of the usual LinearLayout.

SWT: remove the invisible component space in composite

I put three composite(1,2,3) inside one composite0, so they all set their layout based on the composite0.setLayout(new FormLayout()). The problem I have now is, I make the composite3 invisible: composite3.setVisible(false); (I dont want to delete the data, still need that component, but just doesn't want it shows on the UI), and there's a big gap after componite2 now. How to remove the big gap(which use to put the composite2)? thank you in advanced!
Snippet 313 of the official SWT examples should help you with that. You basically set a different FormData on composite3 depending on whether you want to show or hide it.
I have a databinding observable for that, but it assumes the controls to be within a GridLayout. I use it to show and hide composites and widgets within a wizard page, depending on the selection state of a checkbox.
To use it, set it up with something like this:
DataBindingContext dbc = new DataBindingContext();
Button button = new Button(composite, SWT.CHECK);
IObservableValue target = SWTObservables.observeSelection(button);
dbc.bindValue(target, new HideControlObservable(someControl));
Here is the observable:
/**
* Observable to control the presence (visibility and size) of any control
* within a grid layout.
* <p>
* Changing the value of this observable will do two things:
* <ol>
* <li>Set the visibility of the control</li>
* <li>Set the size of the control to zero when the control is invisible.</li>
* </ol>
* So, when using this observable, the control will not only be invisible,
* but it will be gone, completely. Normally, when setting the visibility of
* a control to <code>false</code>, the control will not be displayed but
* will still take all the space on the screen.
* </p>
* <p>
* <strong>Note:</strong> this observable works for controls within a
* <strong>GridLayout only</strong>.
* </p>
*/
public class HideControlObservable extends WritableValue implements IValueChangeListener {
private final DataBindingContext dbc = new DataBindingContext();
private final ISWTObservableValue sizeObservable;
private final Point size = new Point(0, 0);
private final Control control;
public HideControlObservable(Control control) {
super(control.getVisible(), Boolean.class);
this.control = control;
UpdateValueStrategy never = new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER);
dbc.bindValue(SWTObservables.observeVisible(control), this, never, null);
sizeObservable = SWTObservables.observeSize(control);
sizeObservable.addValueChangeListener(this);
if (!control.isVisible()) {
GridData gd = (GridData) control.getLayoutData();
if (gd == null) {
gd = new GridData();
}
gd.exclude = true;
control.setLayoutData(gd);
control.setSize(new Point(0, 0));
}
}
#Override
public void doSetValue(Object value) {
super.doSetValue(value);
Boolean bool = (Boolean) value;
if (bool) {
GridData gd = (GridData) control.getLayoutData();
if (gd == null) {
gd = new GridData();
}
gd.exclude = false;
control.setLayoutData(gd);
control.setSize(size);
control.getParent().layout();
} else {
GridData gd = (GridData) control.getLayoutData();
if (gd == null) {
gd = new GridData();
}
gd.exclude = true;
control.setLayoutData(gd);
control.setSize(new Point(0, 0));
control.getParent().layout();
}
}
#Override
public synchronized void dispose() {
sizeObservable.dispose();
super.dispose();
}
#Override
public void handleValueChange(ValueChangeEvent event) {
Point newSize = (Point) event.getObservableValue().getValue();
if (newSize.x > size.x) {
size.x = newSize.x;
}
if (newSize.y > size.y) {
size.y = newSize.y;
}
}
}
FormData data = new FormData();
data.left = new FormAttachment(0, 100, EditorPanel.SPACING);
data.top = new FormAttachment(section1, EditorPanel.SPACING);
data.height = 0;
data.width = 0;
addSectionFormData(a, b, c);
a.setLayoutData(data);
b.setLayoutData(data);
this solve the problem! :)

How to make GWT Datagrid have its first column fixed and scroll horizontally and vertically

Currently GWT DataGrid header does this trick with a fixed header row during a vertical scroll. Is there a way to acheive the same on an entire (first) column?
I have implemented ScrolledGrid that freezes first column in DataGrid. You need to use it instead of DataGrid in order to make first column be frozen.
import com.google.gwt.dom.client.*;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
/**
*
* #author Yuri Plaksyuk
*/
public class ScrolledGrid extends DataGrid {
private final Text cssText;
private boolean addedClass = false;
private int currentScrollLeft = 0;
public ScrolledGrid() {
cssText = Document.get().createTextNode("");
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(cssText);
HeaderPanel headerPanel = (HeaderPanel) getWidget();
headerPanel.getElement().insertFirst(styleElement);
final ScrollPanel scrollPanel = (ScrollPanel) headerPanel.getContentWidget();
scrollPanel.addScrollHandler(new ScrollHandler() {
#Override
public void onScroll(ScrollEvent event) {
int scrollLeft = scrollPanel.getHorizontalScrollPosition();
if (scrollLeft != currentScrollLeft) {
StringBuilder css = new StringBuilder();
if (scrollLeft > 0) {
css.append(".ScrolledGrid-frozen {");
css.append("background-color: inherit;");
css.append("}");
css.append(".ScrolledGrid-frozen div {");
css.append("position: absolute;");
css.append("left: ").append(scrollLeft).append("px;");
css.append("width: ").append(getColumnWidth(getColumn(0))).append(";");
css.append("padding-left: 1.3em;");
css.append("padding-right: 0.5em;");
css.append("margin-top: -0.7em;");
css.append("white-space: nowrap;");
css.append("background-color: inherit;");
css.append("}");
}
else
css.append(".ScrolledGrid-frozen { }");
css.append("th.ScrolledGrid-frozen { background-color: white; }");
cssText.setData(css.toString());
if (!addedClass) {
NodeList<TableRowElement> rows;
TableRowElement row;
TableCellElement cell;
rows = getTableHeadElement().getRows();
for (int i = 0; i < rows.getLength(); ++i) {
row = rows.getItem(i);
cell = row.getCells().getItem(0);
cell.setInnerHTML("<div>" + cell.getInnerHTML() + "</div>");
cell.addClassName("ScrolledGrid-frozen");
}
rows = getTableBodyElement().getRows();
for (int i = 0; i < rows.getLength(); ++i) {
row = rows.getItem(i);
cell = row.getCells().getItem(0);
cell.addClassName("ScrolledGrid-frozen");
}
addedClass = true;
}
currentScrollLeft = scrollLeft;
}
}
});
}
}
Unfortunately, some CSS values are hard-coded.
I adapted Yuri's solution to achieve the following goals:
does not flicker
copes with arbitrary row-heights
works with SelectionModel
more uniform solution
It does not mess with the columns itself, but instead shows arbitrary "frozen" information on row-level.
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.*;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.cellview.client.DefaultCellTableBuilder;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
/**
* #author Daniel Lintner
*
* A DataGrid extension with the ability to display some row-level-information
* when scrolling left (horizontal), hence important columns out of sight of the user.
*/
public class FrozenDataGrid extends DataGrid
{
//textnode getting updated dynamically when scolling horizontally
private Text cssText;
//the latest scroll-position
private int currentScrollLeft = 0;
//an object extracting String-info from your rowdata
private FrozenValueProvider valueProvider;
//inject basic styling into the document - once
//this is how the frozen row-info looks like
static
{
Text baseCss = Document.get().createTextNode("");
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(baseCss);
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-base {");
css.append("position: absolute;");
css.append("background-color: gray;");
css.append("padding: .3em;");
css.append("padding-left: .5em;");
css.append("padding-right: .5em;");
css.append("border-radius: 3px 3px;");
css.append("transition: opacity 500ms;");
css.append("color: white;");
css.append("margin-top: 2px;");
css.append("white-space: nowrap;");
css.append("}");
baseCss.setData(css.toString());
Document.get().getBody().insertFirst(styleElement);
}
public FrozenDataGrid()
{
super();
init();
}
public FrozenDataGrid(int pageSize, DataGrid.Resources resources)
{
super(pageSize, resources);
init();
}
public void init()
{
//create a css textnode
cssText = Document.get().createTextNode("");
//create dynamic css Style
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(cssText);
//append the initial style condition
//todo the name of this style might be built dynamically per instance - if multiple grid-instances exist/not the use-case by now
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
cssText.setData(css.toString());
//set a custom CellTableBuilder in order to inject the info-div to the row
setTableBuilder(new DefaultCellTableBuilder(this)
{
#Override
public void buildRowImpl(final Object rowValue, final int absRowIndex)
{
//do what DefaultCellTableBuilder does
super.buildRowImpl(rowValue, absRowIndex);
//only do something if there is a valueProvider
if(valueProvider != null) {
//we do this deferred because this row has to created first in order to access it
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand()
{
#Override
public void execute()
{
createInfoDiv(getTableBodyElement().getRows().getItem(absRowIndex % getPageSize()), rowValue);
}
});
}
}
});
//fetch the ScrollPanel from the grid
HeaderPanel headerPanel = (HeaderPanel) getWidget();
headerPanel.getElement().insertFirst(styleElement);
final ScrollPanel scrollPanel = (ScrollPanel) headerPanel.getContentWidget();
//setup a timer handling the left-offset-css thing
//we use a timer to be able to cancel this operation -> e.g. continuous scroll
final Timer timer = new Timer(){
#Override
public void run() {
StringBuilder css = new StringBuilder();
//we need to left-offset the info-divs
if (scrollPanel.getHorizontalScrollPosition() > 100)
{
css.append(".ScrolledGrid-frozen {");
css.append("left: ").append(3 + scrollPanel.getHorizontalScrollPosition()).append("px;");
css.append("opacity: 1;");
css.append("}");
}
//we are close to the leftmost scroll position: info hidden
else
{
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
}
cssText.setData(css.toString());
}
};
//track scrolling
scrollPanel.addScrollHandler(new ScrollHandler()
{
#Override
public void onScroll(ScrollEvent event)
{
//cancel previous actions to scroll events
if(timer.isRunning())
timer.cancel();
//actual horizontal scrollposition
int scrollLeft = scrollPanel.getHorizontalScrollPosition();
//a horizontal scroll takes places
if (scrollLeft != currentScrollLeft)
{
//first we hide the row-info
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
cssText.setData(css.toString());
//render left offset after a delay
timer.schedule(500);
//remember the current horizontal position
currentScrollLeft = scrollLeft;
}
}
});
}
private void createInfoDiv(TableRowElement row, Object value)
{
//create a div element and add value and style to it
DivElement div = Document.get().createDivElement();
div.setInnerText(valueProvider.getFrozenValue(value));
div.addClassName("ScrolledGrid-base");
div.addClassName("ScrolledGrid-frozen");
//we add it to the first child of the row, because added as child of the row directly
// confuses the CellTable with coordinating header positions
row.getFirstChildElement().insertFirst(div);
}
public void setFrozenValueProvider(FrozenValueProvider valueProvider) {
this.valueProvider = valueProvider;
}
public interface FrozenValueProvider<T>{
String getFrozenValue(T data);
}
}
Hope this helps developers on this rarely and unsatisfactorily solved problem.
And... there is still room for improvement left.
Cheers Dan

GWT CellTable Custom Selection Model

I need a 'custom selection model' for GWT CellTable. One of the columns in CellTable is a Checkbox column.
Basic rquirements (both work in solution below):
- Row click (not on checkbox), selects that row and un-selects all other rows.
- Checkbox selection should select/un-select that row only.
Following is the code I am using, but its very very slow. Any guidance would be appreciated.
final SelectionModel<T> selectionModel = new MultiSelectionModel<T>();
dataTable.setSelectionModel(selectionModel,
DefaultSelectionEventManager.createCustomManager(
new DefaultSelectionEventManager.CheckboxEventTranslator<T>() {
#Override
public SelectAction translateSelectionEvent(CellPreviewEvent<T> event) {
SelectAction action = super.translateSelectionEvent(event);
if (action.equals(SelectAction.IGNORE)) {
selectionModel.clear();
return SelectAction.TOGGLE;
}
return action;
}
}
)
);
Following is the code snipped for CheckColumn callback.
Column<T, Boolean> checkColumn = new Column<T, Boolean>(
new CheckboxCell(true, false))
{
#Override
public Boolean getValue(T t)
{
// Get the value from the selection model.
return selectionModel.isSelected(t);
}
};
I have put in a KeyProvider for the CellTable and its not slow anymore. :)
ProvidesKey<T> keyProvider = new ProvidesKey<T>() {
public Object getKey(T t) {
return tip == null? null : tip.getId();
}
};
dataTable = new CellTable<T>(PAGE_SIZE, keyProvider);
You could just whitelist your checkbox
int checkboxColumn = 0;
DefaultSelectionEventManager.createCustomManager(new DefaultSelectionEventManager
.WhitelistEventTranslator(checkboxColumn));