Solution for Numeric Text Field in GWT - gwt

I need a text field very similar in behavior to Gxt's NumberField. Unfortunately I am not using Gxt in my application and GWT 2.0 does not have a Numeric text field implementation as yet.
So that currently leaves me with an option to simulate a NumberField by filtering out non-numeric keystrokes using a keyboardHandler.
Is this the the best way to approach the problem? Does anyone here have a better solution/approach in mind?
Thanks in advance :)

Here you can find the code that I use in one of my classes. The features are much more limited that those of GXT, but should put you in the proper track.
It's a really basic widget, but does what I need to.
public class ValueTextBox extends TextBox {
private int min = 0;
private int max = 100;
private boolean minConstrained = true;
private boolean maxConstrained = true;
private int minDigits = 1;
private int step = 1;
private KeyUpHandler keyUpHandler = new KeyUpHandler() {
#Override
public void onKeyUp(KeyUpEvent event) {
if (isReadOnly() || !isEnabled()) {
return;
}
int keyCode = event.getNativeEvent().getKeyCode();
boolean processed = false;
switch (keyCode) {
case KeyCodes.KEY_LEFT:
case KeyCodes.KEY_RIGHT:
case KeyCodes.KEY_BACKSPACE:
case KeyCodes.KEY_DELETE:
case KeyCodes.KEY_TAB:
if (getText().isEmpty()) {
setValue(formatValue(min));
}
return;
case KeyCodes.KEY_UP:
if (step != 0) {
increaseValue();
processed = true;
}
break;
case KeyCodes.KEY_DOWN:
if (step != 0) {
decreaseValue();
processed = true;
}
break;
}
if (processed) {
cancelKey();
}
}
};
private KeyPressHandler keyPressHandler = new KeyPressHandler() {
#Override
public void onKeyPress(KeyPressEvent event) {
if (isReadOnly() || !isEnabled()) {
return;
}
int keyCode = event.getNativeEvent().getKeyCode();
switch (keyCode) {
case KeyCodes.KEY_LEFT:
case KeyCodes.KEY_RIGHT:
case KeyCodes.KEY_BACKSPACE:
case KeyCodes.KEY_DELETE:
case KeyCodes.KEY_TAB:
case KeyCodes.KEY_UP:
case KeyCodes.KEY_DOWN:
return;
}
int index = getCursorPos();
String previousText = getText();
String newText;
if (getSelectionLength() > 0) {
newText = previousText.substring(0, getCursorPos())
+ event.getCharCode()
+ previousText.substring(getCursorPos()
+ getSelectionLength(), previousText.length());
} else {
newText = previousText.substring(0, index)
+ event.getCharCode()
+ previousText.substring(index, previousText.length());
}
cancelKey();
setValue(newText, true);
}
};
public ValueTextBox(int value) {
this(value, 0, 100);
}
public ValueTextBox(int value, int min, int max) {
this(value, min, max, true);
}
public ValueTextBox(int value, int min, int max, boolean constrained) {
this(value, min, max, constrained, constrained);
}
public ValueTextBox(int value, int min, int max, boolean minConstrained,
boolean maxConstrained) {
super();
addKeyPressHandler(keyPressHandler);
addKeyUpHandler(keyUpHandler);
this.min = min;
this.max = max;
this.minConstrained = minConstrained;
this.maxConstrained = maxConstrained;
setValue(formatValue(value), false);
setTextAlignment(TextBoxBase.ALIGN_CENTER);
setStyleName(Resources.INSTANCE.css().fwFormEntry());
}
public void setMinDigits(int minDigits) {
if (minDigits > 0) {
this.minDigits = minDigits;
String value = getText();
long newValue = parseValue(value);
setText(formatValue(newValue));
}
}
public void setSteps(int step) {
this.step = step;
}
protected void increaseValue() {
if (step != 0) {
String value = getText();
long newValue = parseValue(value);
newValue += step;
if (maxConstrained && (newValue > max)) {
return;
}
setValue(formatValue(newValue));
}
}
protected void decreaseValue() {
if (step != 0) {
String value = getText();
long newValue = parseValue(value);
newValue -= step;
if (minConstrained && (newValue < min)) {
return;
}
setValue(formatValue(newValue));
}
}
/**
* #param value
* the value to format
* #return the formatted value
*/
protected String formatValue(long value) {
String newValue = String.valueOf(value);
if (minDigits > newValue.length()) {
String leading = StringUtils.repeat("0", (minDigits - newValue
.length()));
newValue = leading + newValue;
}
return newValue;
}
#Override
public void setValue(String value) {
setValue(value, false);
}
#Override
public void setValue(String value, boolean fireEvents) {
try {
long newValue = parseValue(value);
if ((maxConstrained && (newValue > max))
|| (minConstrained && (newValue < min))) {
return;
}
String prevText = getValue();
super.setText(formatValue(newValue));
if (fireEvents) {
ValueChangeEvent.fireIfNotEqual(this, getValue(), prevText);
}
} catch (Exception ex) {
// Do Nothing
System.out.println(ex.getMessage());
}
}
/**
* #param value
* the value to parse
* #return the parsed value
*/
protected long parseValue(String value) {
return Long.valueOf(value);
}
}
Update: The code is available in https://github.com/ctasada/GWT-Eureka

Here is a simple KeyPressHandler to allow the user to input decimal numbers;
public void onKeyPress(KeyPressEvent event){
TextBox sender = (TextBox)event.getSource();
if (sender.isReadOnly() || !sender.isEnabled()) {
return;
}
Character charCode = event.getCharCode();
int unicodeCharCode = event.getUnicodeCharCode();
// allow digits, '.' and non-characters
if (!(Character.isDigit(charCode) || charCode == '.' || unicodeCharCode == 0)){
sender.cancelKey();
}
}

Don't know when these classes were added to GWT, but they work fine for me without any extra code:
com.google.gwt.user.client.ui.DoubleBox
com.google.gwt.user.client.ui.IntegerBox
com.google.gwt.user.client.ui.LongBox
For more advanced validation you may want to overwrite their base class ValueBox with some custom Parser...

Here is my implementation of NumberField. Very similar in functionality to Carlos's version, but with additional support for decimal input and non-numeric key filtering.
public class NumberBox extends TextBox
{
private boolean isDecimal = false;
public NumberBox( )
{
}
public boolean isDecimal( )
{
return isDecimal;
}
public void setDecimal( boolean isDecimal )
{
this.isDecimal = isDecimal;
}
public Integer getIntegerValue( )
{
return ( StringUtil.isEmpty( getSanitizedValue( ) ) ) ? null : Integer.parseInt( getSanitizedValue( ) );
}
#Override
protected void initialize( )
{
super.initialize( );
addStyleName( "number" );
this.addKeyPressHandler( new KeyPressHandler( )
{
public void onKeyPress( KeyPressEvent event )
{
if ( !isEnabled( ) || isReadOnly( ) )
return;
int keyCode = event.getNativeEvent( ).getKeyCode( );
// allow special keys
if ( ( keyCode == KeyCodes.KEY_BACKSPACE )
|| ( keyCode == KeyCodes.KEY_DELETE )
|| ( keyCode == KeyCodes.KEY_ENTER ) || ( keyCode == KeyCodes.KEY_ESCAPE ) || ( keyCode == KeyCodes.KEY_RIGHT )
|| ( keyCode == KeyCodes.KEY_LEFT ) || ( keyCode == KeyCodes.KEY_TAB ) )
return;
// check for decimal '.'
if ( isDecimal( ) && '.' == (char)keyCode && !getValue( ).contains( "." ) )
return;
// filter out non-digits
if ( Character.isDigit( charCode ) )
return;
cancelKey( );
}
} );
}
}
PS: Superclass TextBox is a custom class extending GWT TextBox with some additional application specific features. The method initialize() is basically invoked inside the TextBox constructor, and getSanitizedValue does some basic sanity checks with trimming.

Carlos Tasada answer works, but contains a bug: you should add event.isShiftKeyDown() check in onKeyPress handler before switch/case block. It will pass some symbols like '(' otherwise.

Based on Julian Downes answer you can do this:
text.addKeyPressHandler(new KeyPressHandler() {
#Override
public void onKeyPress(KeyPressEvent event) {
TextBox sender = (TextBox) event.getSource();
if (sender.isReadOnly() || !sender.isEnabled()) {
return;
}
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER){
return;
}
Character charCode = event.getCharCode();
try{
Double.parseDouble(sender.getText().concat(charCode.toString()));
}
catch(Exception e){
sender.cancelKey();
}
}
});

Related

AutoCompleteTextField list does not always scroll to top?

The AutoCompleteTextField seems to work exactly as intended until I start backspacing in the TextField. I am not sure what the difference is, but if I type in something like "123 M" then I get values that start with "123 M". If I backspace and delete the M leaving "123 " in the field, the list changes, but it does not scroll to the top of the list.
I should note that everything works fine on the simulator and that I am experiencing this behavior when running a debug build on my iPhone.
EDIT: So this does not only seem to happen when backspacing. This image shows the results I have when typing in an address key by key. In any of the pictures where the list isn't viewable or is clipped, I am able to drag down on the list to get it to then display properly. I have not tried this on an Android device.
EDIT2:
public class CodenameOneTest {
private Form current;
private Resources theme;
private WaitingClass w;
private String[] properties = {"1 MAIN STREET", "123 E MAIN STREET", "12 EASTER ROAD", "24 MAIN STREET"};
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
}
public void start() {
if(current != null) {
current.show();
return;
}
Form form = new Form("AutoCompleteTextField");
form.setLayout(new BorderLayout());
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
protected boolean filter(String text) {
if(text.length() == 0) {
options.removeAll();
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
};
};
Container container = new Container(BoxLayout.y());
container.setScrollableY(true); // If you comment this out then the field works fine
container.add(ac);
form.addComponent(BorderLayout.CENTER, container);
form.show();
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
if(w != null) {
w.actionPerformed(null);
}
w = new WaitingClass();
String[] properties = getProperties(text);
if(Display.getInstance().isEdt()) {
Display.getInstance().invokeAndBlock(w);
}
else {
w.run();
}
return properties;
}
}
catch(Exception e) {
Log.e(e);
}
return null;
}
private String[] getProperties(String text) {
List<String> returnList = new ArrayList<>();
List<String> propertyList = Arrays.asList(properties);
for(String property : propertyList) {
if(property.startsWith(text)) {
returnList.add(property);
}
}
w.actionPerformed(null);
return returnList.toArray(new String[returnList.size()]);
}
class WaitingClass implements Runnable, ActionListener<ActionEvent> {
private boolean finishedWaiting;
public void run() {
while(!finishedWaiting) {
try {
Thread.sleep(30);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
finishedWaiting = true;
return;
}
}
public void stop() {
current = Display.getInstance().getCurrent();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
}
I used this code on an iPhone 4s:
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("AutoComplete", new BorderLayout());
if(apiKey == null) {
hi.add(new SpanLabel("This demo requires a valid google API key to be set in the constant apiKey, "
+ "you can get this key for the webservice (not the native key) by following the instructions here: "
+ "https://developers.google.com/places/web-service/get-api-key"));
hi.getToolbar().addCommandToRightBar("Get Key", null, e -> Display.getInstance().execute("https://developers.google.com/places/web-service/get-api-key"));
hi.show();
return;
}
Container box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
box.setScrollableY(true);
for(int iter = 0 ; iter < 30 ; iter++) {
box.add(createAutoComplete());
}
hi.add(BorderLayout.CENTER, box);
hi.show();
}
private AutoCompleteTextField createAutoComplete() {
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
#Override
protected boolean filter(String text) {
if(text.length() == 0) {
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
}
};
ac.setMinimumElementsShownInPopup(5);
return ac;
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
ConnectionRequest r = new ConnectionRequest();
r.setPost(false);
r.setUrl("https://maps.googleapis.com/maps/api/place/autocomplete/json");
r.addArgument("key", apiKey);
r.addArgument("input", text);
NetworkManager.getInstance().addToQueueAndWait(r);
Map<String,Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
String[] res = Result.fromContent(result).getAsStringArray("//description");
return res;
}
} catch(Exception err) {
Log.e(err);
}
return null;
}
I was able to create this issue but not the issue you describe.

GWT- In celltable column checkboxcell select all records i want select display record

Frineds,
I am using celltable and their is one column which I put in table header for select all record option and also I am using pager which showing max 15 record in one page. when I clicked on selectall option it will select all records which are present page no 2,3,4,.... in short all records get selected(if total records is 100 it's selected 100 records).so i want only select display page records not all...
ref code is -
final SelectionModel < GenericFirewallRule > selectionModel =
new MultiSelectionModel < GenericFirewallRule > ();
deleteRuleCellTable.setSelectionModel(selectionModel,DefaultSelectionEventManager. < GenericFirewallRule > createCheckboxManager());
// CheckboxCell cbForHeader = new CheckboxCell();
Column < GenericFirewallRule, Boolean > checkColumn = new Column < GenericFirewallRule, Boolean > (
new CheckboxCell()) {#Override
public Boolean getValue(GenericFirewallRule object) {
if(object == null || object.getRuleNumber() == null){
return null;
}else{
if (selectionModel.isSelected(object)) {
if (!ruleListForDelete.contains(object)) {
ruleListForDelete.add(object);
}
} else {
if (ruleListForDelete.contains(object)) {
ruleListForDelete.remove(object);
}
}
System.out.println("ruleListForDelete : " + ruleListForDelete);
return selectionModel.isSelected(object);
}
}
};
Please suggest me solutions....
You can do something like this:
selectAllHeader = new Header<Boolean>(new HeaderCheckbox()) {
#Override
public Boolean getValue() {
for (T item : getVisibleItems()) {
if (!getSelectionModel().isSelected(item)) {
return false;
}
}
return getVisibleItems().size() > 0;
}
};
selectAllHeader.setUpdater(new ValueUpdater<Boolean>() {
#Override
public void update(Boolean value) {
for (T object : getVisibleItems()) {
getSelectionModel().setSelected(object, value);
}
}
});
public class HeaderCheckbox extends CheckboxCell {
private final SafeHtml INPUT_CHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\" checked/>");
private final SafeHtml INPUT_UNCHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\"/>");
public HeaderCheckbox() {
}
#Override
public void render(Context context, Boolean value, SafeHtmlBuilder sb) {
if (value != null && value) {
sb.append(INPUT_CHECKED);
} else {
sb.append(INPUT_UNCHECKED);
}
}
}

GWT CellTable Custom Number Cell

GWT 2.5 -> I have created Custom NumberCell by extending EditTextCell , but it treats the amount value as String. I want to make column sort in that column but it sorts like String value.
Here is my code,
package com.skit.compiere.client.widgets.fields;
import static com.google.gwt.dom.client.BrowserEvents.BLUR;
import static com.google.gwt.dom.client.BrowserEvents.DBLCLICK;
import static com.google.gwt.dom.client.BrowserEvents.KEYDOWN;
import static com.google.gwt.dom.client.BrowserEvents.KEYUP;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.google.gwt.text.shared.SimpleSafeHtmlRenderer;
public class MyNumberEditCell extends EditTextCell
{
Map<Object, MyNumberEditCell.ViewData> viewDataMap = new HashMap<Object, MyNumberEditCell.ViewData>();
private SafeHtmlRenderer<String> renderer;
public boolean editable = true;
public String SelectedValue = null;
ValueUpdater<String> supervalueup ;
Element superparent ;
NativeEvent superevent;
ViewData viewdata;
Context supercontext ;
String supervalue ;
Template template = GWT.create(Template.class);
SafeHtmlBuilder superhtml = new SafeHtmlBuilder();
Context ctx =null;
String val;
int i=-1;
interface Template extends SafeHtmlTemplates {
#Template("<input type=\"text\" value=\"{0}\" tabindex=\"-1\"></input>")
SafeHtml input(String value);
}
public void render(com.google.gwt.cell.client.Cell.Context context,
String value, SafeHtmlBuilder sb) {
super.render(context, value, sb);
}
#Override
public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
if (DBLCLICK.equals(event.getType())) {
super.onBrowserEvent(supercontext, superparent, supervalue, superevent, supervalueup);
}
else if (BLUR.equals(event.getType())) {
// Commit the change. Ensure that we are blurring the input element and
// not the parent element itself.
EventTarget eventTarget = event.getEventTarget();
if (Element.is(eventTarget)) {
Element target = Element.as(eventTarget);
if ("input".equals(target.getTagName().toLowerCase())) {
commit(supercontext, superparent, viewdata, supervalueup);
}
}
}
}
public ViewData getviewData(Object key) {
return (key == null) ? null : viewDataMap.get(key);
}
private void editEvent(Context context, Element parent, String value,
ViewData viewData, NativeEvent event, ValueUpdater<String> valueUpdater) {
String type = event.getType();
System.out.println(type);
boolean keyUp = KEYUP.equals(type);
boolean keyDown = KEYDOWN.equals(type);
// int keyCodes = event.getKeyCode();
// if(event.getKeyCode()==32){
// event.preventDefault();
// return;
// }
if (keyUp || keyDown) {
int keyCode = event.getKeyCode();
if ( keyCode == KeyCodes.KEY_ENTER ||keyCode == KeyCodes.KEY_ESCAPE) {
// Commit the change.
commit(context, parent, viewData, valueUpdater);
}
else if (keyUp && keyCode == KeyCodes.KEY_ESCAPE) {
// Cancel edit mode.
String originalText = viewData.getOriginal();
if (viewData.isEditingAgain()) {
viewData.setText(originalText);
viewData.setEditing(false);
} else {
setviewData(context.getKey(), null);
}
cancel(context, parent, value);
} else {
// Update the text in the view data on each key.
// if(event.getKeyCode()==32){
// viewdata.setText(viewdata.getText()+" ");
// viewdata.setEditing(true);
// }
updateViewData(parent, viewData, true);
}
}
}
#Override
public boolean isEditing(Context context, Element parent, String value) {
SafeHtmlBuilder safehtml = new SafeHtmlBuilder();
return false;
}
private void cancel(Context context, Element parent, String value) {
clearInput(getInputElement(parent));
setValue(context, parent, value);
}
private native void clearInput(Element input) /*-{
if (input.selectionEnd)
input.selectionEnd = input.selectionStart;
else if ($doc.selection)
$doc.selection.clear();
}-*/;
private InputElement getInputElement(Element parent) {
return parent.getFirstChild().<InputElement> cast();
}
private String updateViewData(Element parent, ViewData viewData,
boolean isEditing) {
InputElement input = (InputElement) parent.getFirstChild();
String value = input.getValue();
viewData.setText(value);
viewData.setEditing(isEditing);
return value;
}
private void commit(Context context, Element parent, ViewData viewData,
ValueUpdater<String> valueUpdater) {
String value = updateViewData(parent, viewData, false);
clearInput(getInputElement(parent));
setValue(context, parent, value);
if (valueUpdater != null) {
valueUpdater.update(value);
}
}
public void setValue(Context context, Element parent, String value) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
renderFields(context, value, sb);
parent.setInnerSafeHtml(sb.toSafeHtml());
}
private void renderFields(com.google.gwt.cell.client.Cell.Context context,
String value, SafeHtmlBuilder sb) {
this.renderer = SimpleSafeHtmlRenderer.getInstance();
Object key = context.getKey();
ViewData viewData = getviewData(key);
if (viewData != null && !viewData.isEditing() && value != null
&& value.equals(viewData.getText())) {
clearViewData(key);
viewData = null;
}
String toRender = value;
if (viewData != null) {
String text = viewData.getText();
if (viewData.isEditing()) {
/*
* Do not use the renderer in edit mode because the value of a text
* input element is always treated as text. SafeHtml isn't valid in the
* context of the value attribute.
*/
sb.append(template.input(value));
return;
} else {
// The user pressed enter, but view data still exists.
toRender = text;
}
}
if (toRender != null && toRender.trim().length() > 0) {
sb.append(renderer.render(toRender));
} else {
/*
* Render a blank space to force the rendered element to have a height.
* Otherwise it is not clickable.
*/
sb.appendHtmlConstant("\u00A0");
}
}
public void setviewData(Object key, ViewData viewData) {
if (key == null) {
return;
}
if (viewData == null) {
clearViewData(key);
} else {
viewDataMap.put(key, viewData);
}
}
static class ViewData {
private boolean isEditing;
/**
* If true, this is not the first edit.
*/
private boolean isEditingAgain;
/**
* Keep track of the original value at the start of the edit, which might be
* the edited value from the previous edit and NOT the actual value.
*/
private String original;
private String text;
/**
* Construct a new ViewData in editing mode.
*
* #param text the text to edit
*/
public ViewData(String text) {
this.original = text;
this.text = text;
this.isEditing = true;
this.isEditingAgain = false;
}
#Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
ViewData vd = (ViewData) o;
return equalsOrBothNull(original, vd.original)
&& equalsOrBothNull(text, vd.text) && isEditing == vd.isEditing
&& isEditingAgain == vd.isEditingAgain;
}
public String getOriginal() {
return original;
}
public String getText() {
return text;
}
#Override
public int hashCode() {
return original.hashCode() + text.hashCode()
+ Boolean.valueOf(isEditing).hashCode() * 29
+ Boolean.valueOf(isEditingAgain).hashCode();
}
public boolean isEditing() {
return isEditing;
}
public boolean isEditingAgain() {
return isEditingAgain;
}
public void setEditing(boolean isEditing) {
boolean wasEditing = this.isEditing;
this.isEditing = isEditing;
// This is a subsequent edit, so start from where we left off.
if (!wasEditing && isEditing) {
isEditingAgain = true;
original = text;
}
}
public void setText(String text) {
this.text = text;
}
private boolean equalsOrBothNull(Object o1, Object o2) {
return (o1 == null) ? o2 == null : o1.equals(o2);
}
}
}

GWT sinkEvents in hosted mode

I extends a gwt celltable to create a custom celltable, i register the sinkevents ie onmouseover/onmouseout.
when you hover on the row of the table the row data is populated on the hover wiget(custom hover popup panel).
its works as it supose to do on development mode but once deployed on tomcat when you move the mouse over different rows on the celltable it
does not update the hover data on the popup panel unless you click away from the table(loose focus) and the hover again on the row.
public class MyCellTable<T> extends CellTable<T> {
private Tooltip popup = new Tooltip();
private List<String> tooltipHiddenColumn = new ArrayList<String>();
private boolean showTooltip;
public MyCellTable() {
super();
sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);
}
#Override
public void onBrowserEvent2(Event event) {
super.onBrowserEvent2(event);
if (isShowTooltip()) {
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEOUT: {
popup.hide(true);
break;
}
case Event.ONMOUSEOVER: {
popup.setAutoHideEnabled(true);
showToolTip(event);
break;
}
}
}
}
private void showToolTip(final Event event) {
EventTarget eventTarget = event.getEventTarget();
if (!Element.is(eventTarget)) {
return;
}
final Element target = event.getEventTarget().cast();
// Find the cell where the event occurred.
TableCellElement tableCell = findNearestParentCell(target);
if (tableCell == null) {
return;
}
Element trElem = tableCell.getParentElement();
if (trElem == null) {
return;
}
TableRowElement tr = TableRowElement.as(trElem);
Element sectionElem = tr.getParentElement();
if (sectionElem == null) {
return;
}
TableSectionElement section = TableSectionElement.as(sectionElem);
if (section == getTableHeadElement()) {
return;
}
NodeList<TableCellElement> cellElements = tr.getCells().cast();
NodeList<TableCellElement> headers = getTableHeadElement().getRows().getItem(0).getCells().cast();
popup.getGrid().clear(true);
popup.getGrid().resizeRows(cellElements.getLength());
for (int i = 0; i < cellElements.getLength(); i++) {
if (getTooltipHiddenColumn().indexOf(headers.getItem(i).getInnerHTML()) == -1) {
TableCellElement tst = TableCellElement.as(cellElements.getItem(i));
popup.getGrid().setHTML(i, 0, headers.getItem(i).getInnerHTML());
popup.getGrid().setHTML(i, 1, tst.getInnerHTML());
}
}
// Here the constant values are used to give some gap between mouse pointer and popup panel
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
int left = event.getClientX() + 5;
int top = event.getClientY() + 5;
if ((offsetHeight + top + 20) > Window.getClientHeight()) {
top = top - offsetHeight - 10;
}
popup.setPopupPosition(left, top);
}
});
popup.show();
}
public ArrayList<ReorderColumnsDetails> getColumnsHeaders(int index){
ArrayList<ReorderColumnsDetails> column = new ArrayList<ReorderColumnsDetails>();
NodeList<TableCellElement> headers = getTableHeadElement().getRows().getItem(0).getCells().cast();
for (int i = 0; i < index; i++) {
ReorderColumnsDetails clm = new ReorderColumnsDetails();
clm.setHearder(headers.getItem(i).getInnerHTML().toString());
clm.setItemIndex(i);
column.add(clm);
}
return column;
}
private TableCellElement findNearestParentCell(Element elem) {
while ((elem != null) && (elem != getElement())) {
String tagName = elem.getTagName();
if ("td".equalsIgnoreCase(tagName) || "th".equalsIgnoreCase(tagName)) {
return elem.cast();
}
elem = elem.getParentElement();
}
return null;
}
/**
* Specify Name of the column's which is not to shown in the Tooltip
*/
public List<String> getTooltipHiddenColumn() {
return tooltipHiddenColumn;
}
/**
* Set title to tooltip
*
* #param title
*/
public void setTooltipTitle(String title) {
popup.setHTML(title);
}
public boolean isShowTooltip() {
return showTooltip;
}
public void setShowTooltip(boolean showTooltip) {
this.showTooltip = showTooltip;
}
}

gwt cell table dynamic columns - sorting

You can represent your "rows" as List<String> instances, you have to change your parameterization from String to List in your Grid, Column and data provider; and of course you have to call updateRowData with a List<List<String>>, not a List<String>.
You also need one Column instance per column, taking the value out of the List by index:
class IndexedColumn extends Column<List<String>, String> {
private final int index;
public IndexedColumn(int index) {
super(new EditTextCell());
this.index = index;
}
#Override
public String getValue(List<String> object) {
return object.get(this.index);
}
}
How do i add sorting to this example. I tried a ListHandler but not sure how to compare List<String>. Any help is appreciated.
You need to add a ListHandler to each column you want to sort separately. Kind of like this:
You'll have to add a getter method to IndexedColumn for the index:
class IndexedColumn extends Column<List<String>, String> {
private final int index;
public IndexedColumn(int index) {
super(new EditTextCell());
this.index = index;
}
#Override
public String getValue(List<String> object) {
return object.get(this.index);
}
public int getIndex(){
return index;
}
}
Then you'll need to add a ListHandler to the CellTable:
ListHandler<List<String>> columnSortHandler = new ListHandler<List<String>>(list);
columnSortHandler.setComparator(columnName, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
if (o1 == o2) {
return 0;
}
// Compare the column.
if (o1 != null) {
int index = columnName.getIndex();
return (o2 != null) ? o1.get(index).compareTo(o2.get(index)) : 1;
}
return -1;
}
});
table.addColumnSortHandler(columnSortHandler);
In the example above list is the List<List<String>> object. The columnName is the Column object. You'll have to do this for every column you want to sort.
Don't forget to also call .setSortable(true) on each of the columns that you will sort.
A good basic example of column sorting can be found here. The code above is based on this example but I used your index in IndexedColumn in order to get the proper String for the column to do the comparison.
Here is the data grid code
indexedColumn.setSortable(true);
sortHandler.setComparator((Column<T, ?>) indexedColumn, (Comparator<T>) indexedColumn.getComparator(true));
Here is the actual class
public class IndexedColumn extends Column<List<String>, String>
{
private Comparator<List<String>> forwardComparator;
private Comparator<List<String>> reverseComparator;
private final int index;
public IndexedColumn(int index)
{
super(new TextCell());
this.index = index;
}
#Override
public String getValue(List<String> object)
{
return object.get(index);
}
public Comparator<List<String>> getComparator(final boolean reverse)
{
if (!reverse && forwardComparator != null)
{
return forwardComparator;
}
if (reverse && reverseComparator != null)
{
return reverseComparator;
}
Comparator<List<String>> comparator = new Comparator<List<String>>()
{
public int compare(List<String> o1, List<String> o2)
{
if (o1 == null && o2 == null)
{
return 0;
}
else if (o1 == null)
{
return reverse ? 1 : -1;
}
else if (o2 == null)
{
return reverse ? -1 : 1;
}
// Compare the column value.
String c1 = getValue(o1);
String c2 = getValue(o2);
if (c1 == null && c2 == null)
{
return 0;
}
else if (c1 == null)
{
return reverse ? 1 : -1;
}
else if (c2 == null)
{
return reverse ? -1 : 1;
}
int comparison = ((String) c1).compareTo(c2);
return reverse ? -comparison : comparison;
}
};
if (reverse)
{
reverseComparator = comparator;
}
else
{
forwardComparator = comparator;
}
return comparator;
}
}